HTTP/2 Smuggling Through Cloudflare Workers and Edge Quirks
HTTP/2 removed the visible ambiguity around Content-Length and chunked bodies, but it did not remove request smuggling. It moved the argument. The edge receives framed H2, a Worker may rebuild the request, and an origin often receives HTTP/1.1. If those hops disagree about where one request ends, your clean H2 stream can become a poisoned H1 connection.
That translation boundary is the target.
Map each hop before sending payloads
Start with response fingerprints. Does the public endpoint advertise h2 through ALPN? Do headers such as cf-ray, server: cloudflare, or a Worker-added marker appear? Does the origin behave differently when you force HTTP/1.1? Record redirects too; a Worker may own /api/* while static paths go straight through the CDN.
Cloudflare itself is not proof of a bug. You need a route where attacker-controlled framing or headers survive the edge and are interpreted differently downstream.
The useful H2 families are:
- H2.CL: the H2 frame length and a forwarded
Content-Lengthdisagree. - H2.TE: an illegal or obfuscated
Transfer-Encodingreaches an H1 backend. - Header injection: a gateway fails to reject newline characters or malformed pseudo-headers during conversion.
- Worker reconstruction: code creates a new
Requestwhile copying a dangerous header set or body inconsistently.
Burp Repeater can send HTTP/2 and preserve a manually supplied Content-Length. Send tiny probes first. A timeout, a mismatched response, or a backend error after a deliberately short body is a clue, not yet a finding.
Workers make routing interesting
A Worker can normalize the URL, alter headers, fetch another hostname, or choose an origin from user input. I've seen security assumptions break when the Worker validates one path and fetch() forwards a decoded version. Try encoded slashes, duplicate path separators, mixed-case headers, and an absolute URL where the route accepts one.
Watch for a request that is rejected on the direct route but accepted through a Worker-owned route. The strongest proof shows that the same backend receives two interpretations. A harmless canary such as GET /robots.txt queued behind the probe is safer than targeting an authenticated page.
Prove desynchronization without hurting neighbors
Shared edge connections make smuggling tests risky. Never fire a large automated queue at production. Use your own endpoint or account, a unique canary, and the smallest sequence that demonstrates response mix-up. If a probe causes the next request to receive the canary response, stop. You have enough.
Timing alone is weak because edge networks retry and pool connections unpredictably. Capture the exact H2 request, the translated behavior you inferred, and repeated paired responses. Explain why ordinary latency cannot produce that order.
Severity depends on the follow-up: bypassing a Worker route check, stealing another request's response, or reaching an internal endpoint. Report the parser disagreement first and the bounded consequence second. Recommend rejecting ambiguous length headers at the first hop, keeping H2 to the origin where possible, and rebuilding Worker requests from an allowlist rather than copying every inbound header.
PortSwigger's advanced request smuggling material covers H2 downgrade attacks and gives a solid vocabulary for describing the desync without pretending every timeout is exploitable.