This is a tiny air hose jammed into a fire-suppression tank until the whole room runs out of pressure
CVE-2026-49975 tracks Apache HTTP Server's mod_http2 handling of split cookie headers under HTTP/2. A remote client can seed HPACK's dynamic table with a tiny cookie entry, replay thousands of indexed references, and force Apache to repeatedly rebuild merged cookie strings while keeping the stream alive with a zero flow-control window. The bug affects Apache deployments with mod_http2 enabled and HTTP/2 exposed; the public repro was validated against Apache 2.4.67, and Apache's fix landed as mod_http2 2.0.41 on 2026-05-27.
There is no vendor CVSS baseline here, so this is = ASSESSED AT HIGH. The important reality check: this is *not* an RCE or data-theft bug, but it *is* unauthenticated, internet-reachable on any public Apache HTTP/2 edge, works against default behavior, and already has public PoC material. That combination pushes it above routine DoS backlog noise, while the availability-only impact keeps it out of CRITICAL.
5 steps from start to impact.
Reach an HTTP/2-enabled Apache edge
h2 or accepts h2c. mod_http2 must be loaded and the site must actually allow HTTP/2 via Protocols; no credentials, prior foothold, or user interaction are required.- Apache HTTP Server with
mod_http2loaded - HTTP/2 enabled on the target vhost or listener
- Attacker can open TCP/TLS sessions to the service
- Many internal Apache servers never expose HTTP/2 directly to the internet
- A CDN, ADC, or reverse proxy that terminates HTTP/2 upstream can shrink reachable population
- Some enterprises disable
mod_http2on legacy or admin-only vhosts
h2 negotiation, but they do not prove the vulnerable cookie-accounting path or module version.Seed the HPACK table with the PoC
hpack_httpd_cookie_bomb.py, the attacker inserts a small cookie header into the HPACK dynamic table once, then references it by index. This makes the on-wire payload extremely cheap while forcing Apache to materialize many logical headers server-side.- HTTP/2 header compression is active
- Server accepts header blocks and cookie crumbs as normal
- HTTP/2-aware edge devices that enforce a hard header-count cap can stop this early
- Implementations that do not split or merge cookies the Apache way are not this CVE
Bypass field-count protections through cookie merging
cookie crumbs are merged without counting them properly against LimitRequestFields. The attacker can therefore submit thousands of cookie references and drive repeated string rebuilds, creating roughly 4000:1 allocation amplification in the public repro.- Vulnerable
mod_http2build prior to2.0.41 - Cookie header accounting not fixed
- Patched
mod_http22.0.41+closes the accounting bypass - Very small per-request limits can reduce per-stream blast radius, though not eliminate the class
47d3100 is the key fix reference.Pin the allocations with a stalled response
SETTINGS_INITIAL_WINDOW_SIZE=0, preventing the server from draining its response and freeing stream state. By trickling WINDOW_UPDATE frames, the client keeps resetting idle logic and holds the inflated memory in place far longer than a normal request lifecycle would allow.- Client controls HTTP/2 flow-control window
- Server keeps the stalled stream alive
- Aggressive connection timeout and stream lifetime enforcement can reduce hold time
- Front-end proxies that fully terminate HTTP/2 may absorb the behavior before Apache sees it
Exhaust worker memory and degrade availability
2.4.67.- Sufficient memory headroom to be consumed
- No earlier connection-kill, cgroup, or upstream edge enforcement
- Tight cgroup or container memory caps can kill a worker before the whole node collapses
- Horizontal scaling and front-door rate controls can blunt but not remove the impact
The supporting signals.
| In-the-wild status | No CISA KEV listing and no authoritative public evidence of mass exploitation found as of 2026-06-02; however, the public writeup explicitly released working exploit material. |
|---|---|
| PoC availability | Yes. Calif published a companion repo with Apache-specific repro content including hpack_httpd_cookie_bomb.py and a tested harness against Apache 2.4.67: PoC repo. |
| Reporter / researcher | Calif credits Quang Luong for discovering the exploit, with Jun Rong and Duc Phan confirming it on other servers. |
| Disclosure timeline | Calif says Apache was notified on 2026-05-27 and Stefan Eissing fixed it the same day; the public blog and PoC dropped on 2026-06-02. |
| Affected scope | Apache HTTP Server instances with mod_http2 enabled and HTTP/2 exposed. The public repro states it was built against docker.io/library/httpd:latest, observed as Apache 2.4.67. |
| Fixed version | Apache fix landed as mod_http2 2.0.41. Calif noted that on 2026-06-02 it was available from standalone mod_http2 releases and trunk, but *not yet in a 2.4.x httpd release* at that time. |
| Related vendor status | The same cross-vendor attack pattern also affected nginx, which added max_headers in 1.29.8 the day after disclosure to them. Calif reported IIS, Envoy, and Pingora as notified with fix status unknown at publication. |
| Exposure / scanning data | Calif reports a Shodan query found 880,000+ sites supporting HTTP/2 and running one of the affected server families, though many are shielded by CDNs. That is not Apache-only exposure, but it confirms a large reachable population for the attack class. |
| EPSS | No FIRST EPSS score for this CVE was located during review. *Inference:* the CVE appears too new / not yet fully represented in public EPSS data. |
| Assessed CVSS vector | *Inference:* CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H — unauthenticated remote network attack with pure availability impact. |
noisgate verdict.
The decisive factor is unauthenticated remote reachability on internet-facing Apache HTTP/2 edges combined with a public, low-complexity PoC. What keeps this out of CRITICAL is that the blast radius is service availability, not code execution or tenant escape.
Why this verdict
- Starting point: 7.5 availability-heavy network CVSS. This is an unauthenticated remote DoS with no user interaction and a clean path from the internet to the bug on any exposed Apache HTTP/2 listener.
- Upward pressure: public exploit chain and default behavior. Calif published a working Apache repro on 2026-06-02, and the writeup says the vulnerable behavior exists in default HTTP/2 configurations rather than niche custom modules.
- Upward pressure: single-client efficiency is ugly. The published Apache repro shows roughly 32 GB in ~18 seconds and around 4000:1 amplification, which is enough to topple undersized edges fast.
- Downward pressure: attacker must hit an Apache endpoint that actually terminates HTTP/2. If your CDN, WAF, or reverse proxy terminates
h2before Apache, the reachable population drops materially. - Downward pressure: impact is availability-only. There is no evidence here of code execution, auth bypass, or cross-tenant data compromise; the business pain is outage, not takeover.
- Net result: = ASSESSED AT HIGH. Internet-reachable, exploit-ready, default-path DoS belongs above backlog hygiene, but the lack of confidentiality/integrity impact keeps it below CRITICAL.
Why not higher?
This is not a pre-auth RCE, not a privilege-escalation chain, and not a data-exposure issue. Even though the memory amplification is severe, the end state is service degradation or outage, so the blast radius is materially narrower than bugs that hand over the host or application tier.
Why not lower?
Scoring this lower would ignore the combination that matters operationally: public PoC, no auth, network reachability, and default HTTP/2 behavior. A bug that can let one cheap client pin tens of gigabytes on a public edge is not routine nuisance DoS.
What to do — in priority order.
- Disable HTTP/2 on exposed Apache vhosts — If you cannot prove
mod_http22.0.41+or a vendor backport, removeh2/h2cfromProtocolsas the primary containment step. For a HIGH verdict, deploy this compensating control within 30 days; if the site is internet-facing and high-business-impact, do it far sooner. - Enforce HTTP/2 header-count limits upstream — Put a CDN, ADC, WAF, or reverse proxy in front of Apache that can terminate HTTP/2 and enforce a hard header-count cap, including cookie crumbs. This is the best architectural mitigation when Apache itself cannot be updated immediately; deploy within 30 days.
- Cap per-worker memory — Use cgroups, container limits, or equivalent process memory caps so a bombed worker dies before the whole node is dragged into swap. This does not fix exploitability, but it reduces node-wide blast radius; deploy within 30 days.
- Tighten connection and stream lifetime limits — Reduce idle timeouts, keepalive duration, and stream lifetime where your application tolerates it so zero-window stalls do not persist indefinitely. This is a risk reducer, not a cure; implement within 30 days.
- Alert on anomalous HTTP/2 behavior — Instrument for zero-window sessions, long-lived low-throughput
h2connections, abnormal header counts, RSS spikes, and worker churn. This gives you a fighting chance to identify active abuse before it becomes a broad outage; deploy within 30 days.
LimitRequestFieldsalone does not solve this on vulnerable Apache builds; the fix specifically changed cookie accounting so crumbs can no longer bypass that limit.- Only limiting *decoded header size* is not enough; Calif's writeup shows the amplification comes from per-entry bookkeeping and repeated merge allocation, not just oversized logical headers.
- TLS by itself does nothing. If Apache is the HTTP/2 termination point, encrypted transport still delivers the exploit straight to the vulnerable parser.
Crowdsourced verification payload.
Run this on the Apache host itself as a local auditor or via your config-management runner. Invoke it as bash check_cve_2026_49975.sh /usr/sbin/apachectl or just bash check_cve_2026_49975.sh; it needs read access to Apache config and module files, and sudo helps on locked-down installs.
#!/usr/bin/env bash
# check_cve_2026_49975.sh
# Detect likely exposure to CVE-2026-49975 on Apache HTTP Server.
# Exit codes: 0 PATCHED, 1 VULNERABLE, 2 UNKNOWN
set -u
APACHECTL="${1:-}"
if [[ -z "$APACHECTL" ]]; then
for c in apachectl apache2ctl httpd; do
if command -v "$c" >/dev/null 2>&1; then
APACHECTL="$(command -v "$c")"
break
fi
done
fi
if [[ -z "$APACHECTL" ]]; then
echo "UNKNOWN: could not find apachectl/apache2ctl/httpd"
exit 2
fi
TMPM="$(mktemp)"
TMPC="$(mktemp)"
trap 'rm -f "$TMPM" "$TMPC"' EXIT
if ! "$APACHECTL" -M >"$TMPM" 2>/dev/null; then
echo "UNKNOWN: unable to enumerate loaded modules with $APACHECTL -M"
exit 2
fi
if ! grep -qiE 'http2_module|mod_http2' "$TMPM"; then
echo "PATCHED: mod_http2 not loaded"
exit 0
fi
if ! "$APACHECTL" -t -D DUMP_RUN_CFG >"$TMPC" 2>/dev/null; then
# continue; many builds still allow -t config tests but not dump details
:
fi
HTTP2_ENABLED=0
if grep -RsiE '^\s*Protocols\b.*\b(h2|h2c)\b' /etc/httpd /etc/apache2 /usr/local/etc/apache2 2>/dev/null | grep -q .; then
HTTP2_ENABLED=1
elif grep -siE '\bProtocols\b.*\b(h2|h2c)\b' "$TMPC" >/dev/null 2>&1; then
HTTP2_ENABLED=1
fi
if [[ "$HTTP2_ENABLED" -eq 0 ]]; then
echo "PATCHED: mod_http2 is present but HTTP/2 does not appear enabled in active config"
exit 0
fi
MODPATH=""
for p in \
/usr/lib64/httpd/modules/mod_http2.so \
/usr/lib/httpd/modules/mod_http2.so \
/usr/lib/apache2/modules/mod_http2.so \
/usr/local/apache2/modules/mod_http2.so; do
if [[ -f "$p" ]]; then
MODPATH="$p"
break
fi
done
if [[ -z "$MODPATH" ]]; then
MODPATH="$(find /usr/lib* /usr/local -type f -name mod_http2.so 2>/dev/null | head -n1)"
fi
if [[ -z "$MODPATH" || ! -r "$MODPATH" ]]; then
echo "UNKNOWN: HTTP/2 enabled and mod_http2 loaded, but mod_http2.so path/version could not be determined"
exit 2
fi
VER="$(strings "$MODPATH" 2>/dev/null | grep -Eo '2\.[0-9]+\.[0-9]+' | sort -Vu | tail -n1)"
if [[ -z "$VER" ]]; then
PKGVER="$(rpm -qf "$MODPATH" 2>/dev/null || dpkg -S "$MODPATH" 2>/dev/null || true)"
echo "UNKNOWN: could not extract mod_http2 version from $MODPATH ($PKGVER)"
exit 2
fi
ver_lt() {
# returns 0 if $1 < $2
[[ "$(printf '%s\n%s\n' "$1" "$2" | sort -V | head -n1)" != "$2" ]]
}
if ver_lt "$VER" "2.0.41"; then
echo "VULNERABLE: mod_http2 version $VER with HTTP/2 enabled (fixed in 2.0.41)"
exit 1
fi
echo "PATCHED: mod_http2 version $VER and HTTP/2 enabled"
exit 0
If you remember one thing.
mod_http2 2.0.41 fix or equivalent backport. If a site is public and business-critical, do not wait for the outer edge of those deadlines.Sources
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.