Kai Ole Hartwig — Blog
14 min read
High
By

HTTP/2 Bomb: one wire byte, ~4,000 bytes of server memory — the Codex-discovered remote DoS against nginx, Apache, IIS, Envoy and Pingora

2 June 2026. Calif has published the HTTP/2 Bomb: a remote denial-of-service that sits in the default configuration of nginx, Apache httpd, Microsoft IIS, Envoy and Cloudflare Pingora, chaining two techniques each about a decade old into something new. An HPACK indexed-reference bomb turns a single wire byte into up to ~4,000 bytes of server memory, and an HTTP/2 window stall pins each of those allocations in memory almost for free, for as long as the attacker likes; a home PC on a 100 Mbps link is enough to bind ~32 GB against Apache or Envoy in roughly 20 seconds. The chaining was found by the AI coding agent Codex, and a complete, dockerised PoC for all five servers is public. nginx is fixed in 1.29.8 and Apache in trunk; for IIS, Envoy and Pingora there was no patch at the time of publication.

TL;DR — the 90-second summary

What was published?

HTTP/2 Bomb (Calif, 2 June 2026), a remote DoS against the default HTTP/2 configuration of several major web servers. Mechanism: an HPACK Indexed Reference Bomb (amplification: 1 wire byte → ~70 to ~4,000 bytes of server allocation per reference) chained with an HTTP/2 Window Stall (zero-byte flow-control window + 1-byte WINDOW_UPDATE drip that pins the allocations in memory).

How severe?

High. Remote memory exhaustion, default config affected, public PoC. Against Apache httpd and Envoy a single client holds ~32 GB in roughly 20 seconds; a home PC on 100 Mbps suffices. DoS, not code execution.

Which servers are affected?

nginx (1.29.7, ~70:1), Apache httpd (2.4.67, ~4,000:1), Microsoft IIS (Windows Server 2025, ~68:1), Envoy (1.37.2, ~5,700:1), Cloudflare Pingora (0.8.0, ~62:1 per the PoC repo). Go-based servers (Caddy, Traefik) are, per my source-code analysis, structurally largely protected (see FAQ).

Am I affected?

Affected if you run one of these servers with HTTP/2 (h2) enabled and publicly reachable and have not yet patched/mitigated. Behind a robust CDN the situation is much reduced. Pure HTTP/1.1 endpoints and Go-based proxies are not the primary target.

Immediate mitigation?

nginx: upgrade to 1.29.8+ (max_headers, default 1000) or http2 off;. Apache: Protocols http/1.1 as a workaround (the mod_http2 fix is in trunk; a finished 2.4.x release is still pending). IIS/Envoy/Pingora: disable HTTP/2 or front the server with something enforcing a hard header-count cap. Generally: cap per-worker memory (cgroups, ulimit -v).

Criticality?

See the hero badge high. The public PoC and trivial entry bar raise the pressure; no confirmed active mass exploitation as of 2 June.

 

What happened

On 2 June 2026, Calif (Thai Duong) published, under the title „Codex Discovered a Hidden HTTP/2 Bomb“, a remote denial-of-service against most major web servers: nginx, Apache httpd, Microsoft IIS, Envoy and Cloudflare Pingora. The vulnerable behaviour sits in each server's default HTTP/2 configuration, not in some exotic option.

The attack chains two techniques that have each been known individually for about a decade. The first is an HPACK indexed-reference bomb: HPACK (RFC 7541) compresses HTTP/2 headers via a dynamic table into which a sender inserts a header once and then references it by index (usually a single byte). The attacker inserts one header and then fires thousands of 1-byte indexed references at it. Each costs the attacker one byte on the wire but the server a full header allocation: per the source, ~70 bytes on nginx, IIS and Pingora, up to ~4,000 bytes on Apache httpd and Envoy.

The second technique is the HTTP/2 window stall. HTTP/2 (RFC 9113) has flow control in which the receiver advertises a window; crucially, the client controls the window for the server's response. The attacker advertises a zero-byte window so the server can never finish sending its response, then drips 1-byte WINDOW_UPDATE frames that each reset the send timeout. Every allocated cell thus stays pinned in memory for as long as the server timeout allows.

The effect is drastic: against Apache httpd and Envoy a single client binds about 32 GB in roughly 20 seconds, and a home PC on 100 Mbps renders a vulnerable server unreachable „within seconds“. A Shodan search by the authors found over 880,000 websites running HTTP/2 on one of these servers, though many sit behind a CDN and are therefore harder to take down. The provenance is notable: the chaining was found not by a human but by the AI coding agent Codex, which read the codebases and recognised that the two building blocks compose.

Technical assessment

What is actually new about the HTTP/2 Bomb is not the amplification itself — HPACK bombs have existed since 2016. What is new is where the amplification comes from. The classic bomb stuffs a large value into the table and references it, which is why servers learned to cap the total decoded header size. This variant goes the other way: the header is nearly empty, and the amplification comes from the per-entry bookkeeping the server allocates around each entry. The „maximum decoded header size“ limit never fires because there is almost nothing to decode. The flaw thus sits squarely in the blind spot of the established defence.

The second conceptual point is the separation of ratio and time. The authors put it well: „ratio is only half the equation.“ A 70:1 amplification would be harmless if the memory were freed at request end. It becomes a weapon only through the window stall, which holds the connection open almost for free and pins every allocated cell. That is exactly why nginx (only ~70:1) still needs only seconds to minutes to bind gigabytes — the time axis carries what the ratio alone cannot.

The third point explains why the amplification is so much higher on Apache and Envoy: cookie-crumb splitting. Servers that cap the header-field count rather than the size are bypassed via the Cookie header: RFC 9113 §8.2.3 explicitly allows splitting it into one field per crumb, and these servers were not counting the crumbs against their limit. Envoy appends each crumb into a buffer (a fat cookie, referenced many thousands of times, yields up to ~5,700:1 on one stream); Apache rebuilds the entire merged string on every crumb and keeps the older copies alive until cleanup, which produces ~4,000:1 even with an empty cookie. The authors' deeper lesson: when five independent implementations ship the same class of bug, the defect is in the specification — RFC 7541 §7.3 considers the memory risk handled by SETTINGS_HEADER_TABLE_SIZE and overlooks both the bookkeeping and the time axis.

Who is affected

AffectedNot / barely affectedCondition
nginx < 1.29.8, Apache httpd 2.4.x (mod_http2), Microsoft IIS, Envoy, Cloudflare Pingora — each with HTTP/2 (h2) enabledPure HTTP/1.1 endpoints; servers with a hard header-count cap incl. cookie crumbs and a bounded stalled-stream lifetimeHTTP/2 enabled and server in the affected list/version
Instances of the affected servers reachable directly from the internetInstances behind a robust CDN (per the source, „much harder to bring down“)Reachability / CDN fronting
Envoy in Kubernetes ingress/service mesh, Apache/nginx as a reverse proxy in front of applicationsGo-based servers (Caddy, Traefik) — structurally largely protected (see FAQ), with a residual stall risk on default timeoutsHTTP/2 stack implementation

The fastest triage: do you run one of the five servers with HTTP/2 enabled, reachable directly from the internet? Then the path is relevant. A robust CDN in front or pure HTTP/1.1 operation reduces the situation considerably.

Impact and immediate measures

The impact is remote memory exhaustion: a single client can bind enough server memory to push the machine into swap or get workers OOM-killed. The authors point to a particularly nasty variant: instead of triggering the process OOM (a killed worker respawns cleanly), an attacker holds the memory pressure just below the kill threshold and lets every other request on the machine starve in swap. For multi-tenant hosts and shared ingress layers this is an availability — and therefore NIS-2 — concern (Art. 21, maintaining operations).

Operational Decision Block

In this order. First, upgrade nginx to 1.29.8+ (which brings the max_headers directive, default 1000) or, if that is not immediately possible, disable HTTP/2 with http2 off;. Second, secure Apache: since the mod_http2 fix was only in trunk at publication and no finished 2.4.x release is available, Protocols http/1.1 is the realistic immediate workaround; lowering LimitRequestFieldSize only helps partially, and lowering LimitRequestFields does nothing here (the cookie crumbs were not counted against it). Third, IIS/Envoy/Pingora: disable HTTP/2 or put a front layer with a hard per-request header-count cap in place. Fourth, as a safety net, cap per-worker memory (cgroups, ulimit -v, container limits) so a bombed worker is OOM-killed and restarted early, before it drags the machine into swap.

This article reflects my technical and strategic assessment. It is not legal advice and not a data-protection impact assessment.

Detection / verification

Lead. Two levels: „am I vulnerable“ (version and config question) and „am I being attacked right now“ (runtime signal). The tell-tale runtime pattern is a combination of sharply rising memory (RSS) on a worker process and HTTP/2 streams that stay open without the response draining.

Check snippets (copy/paste):

 

# 1) Determine versions
nginx -v            # < 1.29.8 = vulnerable if http2 is enabled
httpd -v            # Apache 2.4.x with mod_http2
envoy --version

# 2) Is HTTP/2 (h2) publicly enabled? Check ALPN against your own endpoint
openssl s_client -alpn h2 -connect example.org:443 </dev/null 2>/dev/null \
  | grep -i 'ALPN'

# 3) nginx: is max_headers set? (available from 1.29.8)
nginx -T 2>/dev/null | grep -i 'max_headers\|http2'

# 4) Runtime: watch worker RSS (spikes under load)
ps -o pid,rss,cmd -C nginx --sort=-rss | head
ps -o pid,rss,cmd -C httpd --sort=-rss | head

# 5) Per-worker memory cap as a safety net (systemd unit)
#    MemoryMax=1G  in the [Service] section, then: systemctl daemon-reload && restart

 

What is suspicious: a single client (one source IP / a few connections) opening many HTTP/2 streams that never complete, with rapidly growing worker RSS at the same time. Because the bomb works with minimal upload, a high memory-per-incoming-byte ratio is the key signal — classic volume-based DoS detection struggles here.

Operator recommendation

German Mittelstand

For TYPO3/application hosting behind nginx the fastest step is the clean one: upgrade to nginx 1.29.8+, and max_headers stays at its default of 1000. Anyone running Apache with mod_http2 sets Protocols http/1.1 as a workaround until the 2.4.x release — the loss of HTTP/2 is tolerable for most standard sites and reversible in days, not weeks. If you have a CDN in front, check that it enforces a hard per-request header-count cap.

Containers / Kubernetes

Envoy as an ingress or sidecar is the trickiest case (highest amplification, no patch at publication). Here: a front layer with a hard header-count cap, deliberate choice of where HTTP/2 terminates, and in any case per-pod memory limits so a bombed pod is restarted rather than dragging the node into swap. Plan the version bump as soon as Envoy ships a fix.

Hosting & operations

The structural lesson for any HTTP/2 termination point: you need both limits („maximum decoded header size“ AND „maximum header count“, including cookie crumbs) plus a bounded lifetime for stalled streams, independent of WINDOW_UPDATE activity. Where that is not possible today, the per-worker memory cap is the pragmatic safety net: an early-killed, cleanly respawned worker is a better failure mode than a machine held at 95% memory.

Frequently asked questions about the HTTP/2 Bomb

Is there a working exploit?+

Yes. Calif published a complete, dockerised PoC kit for all five servers (exploit scripts, lab targets, RSS monitors, demos) including the explicit notice „Please don't point these at infrastructure you don't own.“ That sharply shortens the path from disclosure to attack — so mitigation belongs up front.

Why doesn't LimitRequestFields help on Apache?+

Because the cookie crumbs the attack runs through were not counted against LimitRequestFields — that is precisely the bypass. The actual fix (mod_http2 v2.0.41, currently in trunk only) makes merged cookies count as an „add“ against the limit. Until a 2.4.x release is out, Protocols http/1.1 is the effective workaround; lowering LimitRequestFieldSize is only a partial mitigation.

How do I check whether my nginx is vulnerable?+

Compare the version against 1.29.8 (nginx -v) and check whether HTTP/2 is enabled. Below 1.29.8 without max_headers, the path is open as soon as h2 is running. Fastest fix: upgrade to 1.29.8+ (default max_headers 1000); stopgap: http2 off;.

Is sitting behind a CDN enough?+

It reduces the risk considerably — the authors themselves write that CDN-fronted instances are „much harder to bring down“. The precondition is that the CDN enforces a hard per-request header-count cap (including cookie crumbs) and bounds stalled streams. The origin server should still be patched: anyone who can reach the origin directly (known origin IP, internal paths) bypasses the CDN.

Does this also apply to Traefik and other Go servers?+

Yes, in essence. Traefik uses the same Go net/http2 stack and benefits from the same per-field accounting including cookie crumbs. The shared residual caveat is the stalled-stream lifetime: set sensible write/idle timeouts (or WriteByteTimeout) so a held stream does not stay open indefinitely. One curiosity on the side: a circulating summary claimed Caddy/Traefik were „directly affected“ and pointed to Go versions 1.22.2/1.21.9 — that confuses this bomb with the older HTTP/2 Rapid Reset (CVE-2023-44487) and is not substantiated for this flaw.

Is Caddy affected by the HTTP/2 Bomb?+

Per our source-code analysis of Go's net/http2 (which Caddy uses), Caddy is structurally largely protected against the damaging amplification. Go charges len(Name)+len(Value)+32 bytes per header field against a budget (default MaxHeaderBytes = 1 MB) and tears the connection down on overflow — the +32-byte flat charge per field effectively turns the size limit into a field-count limit, and it applies to every single cookie crumb before anything is merged. That is exactly the defence nginx/Apache/Envoy lacked. The window-stall half is only weakly bounded on Go/Caddy defaults (WriteByteTimeout is off by default), but without the amplifier a held stream pins only ~1 MB rather than gigabytes. Transparency note: this assessment is based on direct source-code analysis of server.go, frame.go and hpack.go, not on a PoC run we performed ourselves: Caddy appears neither in the calif.io blog nor in the PoC repo. We therefore say „structurally largely protected“, not „tested safe“; the source-code evidence, however, clearly points to „protected“.

Conclusion

The HTTP/2 Bomb is a lesson in two things. First, technically: a vulnerability need not be new to be dangerous; it is enough to combine two old, individually tamed building blocks until they coincide in the blind spot of the established defence. The amplification from per-entry bookkeeping plus the free holding via the window stall produce a remote DoS that sits in the default config and can be triggered from a home PC. Second, operationally: triage is cheap (version, ALPN, RSS observation), the immediate measures are known (nginx upgrade, Protocols http/1.1, memory cap), and anyone running Go-based (Caddy, Traefik) is structurally better off but should check the stalled-stream timeouts. Risk, soberly: high for directly reachable, unpatched nginx/Apache/IIS/Envoy/Pingora with HTTP/2 enabled; much smaller behind a robust CDN, on pure HTTP/1.1, or in the Go stack. The most uncomfortable accompanying message is the speed: an AI found the chaining, and public fix diffs can today be turned into exploits quickly — the maintenance window between patch and mass exploitation is shrinking.

Sources

About the author

[Translate to English:] Foto von Kai Ole Hartwig.

Kai Ole Hartwig

Freelance DevSecOps consultant · OnlyOle Consulting

Programming since 2002 – self-taught, set up my own business with KO-Web in 2012. Over 100 projects, with a focus on security, performance, automation and quality. Today freelance: DevSecOps consulting, training and software development.