Six Years of Patches That Missed the Point
HTTP/1.1 has a structural flaw Kettle identified in 2019: no reliable way to tell where one request ends and the next begins. A parser discrepancy between a front end and back end lets an attacker redefine that boundary. He proved the impact by persistently compromising PayPal’s login page twice.
The fix was always clear: H2 for the upstream connection. Six years on, most systems still downgrade H2 client connections back to H1 before the backend, worsening isolation. Regex filters became the substitute, patching detection tooling while leaving the actual vulnerability untouched.
How One Researcher’s Mistake Exposed 24 Million Sites
Vans sent Kettle a puzzling report: a standard H2-downgrade desync was redirecting users from banks and unrelated third parties, not from the target site itself. Kettle diagnosed a Cloudflare-to-Heroku desync. That was wrong.
When Kettle added a cache buster to replicate the attack, the attack stopped. Without the buster, the request never reached Heroku. Cloudflare’s own cache was intercepting it. Omitting the buster triggered a desync inside Cloudflare’s infrastructure, giving anyone testing any Cloudflare site the ability to persistently compromise all 24 million sites on the CDN. The vulnerability only appeared if the researcher made exactly the right mistake.
HTTP Request Smuggler v3: Detecting What Regex Blocks
HTTP Request Smuggler v3 is the tool Kettle released at the talk, built on a 2021 Black Hat Europe concept from Daniel Thatcher. It finds parser discrepancies without using the transfer-encoding header that WAFs block. Instead, it probes using host-header mutations: masking the host with a leading space, duplicating it with a malformed value, or sending a variant the RFC permits but some servers reject.
The output classifies discrepancies as visible-hidden (front end sees the header, back end doesn’t) or hidden-visible (the reverse). Either type converts into a CL0 desync. A hidden-visible mismatch on IIS behind Amazon’s Application Load Balancer was already exploitable for IP spoofing and access control bypass. AWS declined to patch it by default because legacy clients in their customer base rely on sending malformed requests.
Zero-CL Desync: Turning a Dead End Into an Attack
Zero-CL desyncs were considered impossible: the front end ignores a hidden content-length, forwards only headers, and the back end deadlocks waiting for a body. The unlock came from an IIS quirk. Requesting a path that matches a reserved Windows device name (like /con) makes IIS respond early without waiting for the body, breaking the deadlock. Kettle had known about that quirk for over 10 years. This was the first time it had a use.
The double desync exploit chain (20:19) converted that primitive into a full attack. Stage one poisons the attacker’s second request into a CL0 desync, which then hits the victim’s third request. Positioning the payload before front-end-injected headers made the chain reliable enough to deliver malicious JavaScript to live users.
The Expect Header: A Second Attack Class
The Expect header splits a request into two stages so clients can bail before sending a large body. Adding that statefulness into proxy code that never needed it causes servers to miscount bytes, leak memory including secret keys, or expose internal headers that stripping logic was meant to hide. On Netlify, it exposed those headers across the entire CDN.
Paired with a bounty-hunting team, Kettle found that a plain Expect header triggers CL0 desyncs on many targets. GitLab’s vulnerability report attachment host was the sharpest case. Response queue poisoning on that server (28:03) took 27,000 requests but returned a private vulnerability report and a $7,000 bounty. A CL0 desync on Akamai, reported separately by the same team, earned them over $200,000.
Notable Quotes
that more desync attacks are always coming. James Kettle · ▶ 23:43
we persisted and after 27,000 requests, James Kettle · ▶ 28:29
they went on to earn over $200,000 James Kettle · ▶ 32:15
Key Takeaways
- HTTP/1.1’s request-boundary ambiguity cannot be patched with regex; upstream H2 is the only fix.
- The Expect header and early-response gadgets open two new desync attack classes affecting CDN-scale targets.
- HTTP Request Smuggler v3 detects parser discrepancies without transfer-encoding headers that trigger WAF blocks.