Skip to content
Security Notes

HTTP request smuggling: exploiting front-end and back-end disagreement

By Elias Lankinen10 min read

The two-clock problem

In August 2025, a security researcher spent two weeks sending carefully malformed web requests at large companies and walked away with more than $200,000 in bug bounties. One single flaw he reported to Cloudflare had, by the company's own reckoning, exposed roughly 24 million websites. He was not exploiting a clever piece of malware or a stolen password. He was exploiting a disagreement: two servers, sitting one behind the other, that could not agree on where one web request ended and the next began. That disagreement is the whole of HTTP request smuggling. It is one of the strangest bug classes in web security because the vulnerability does not live inside any single program. Each server involved can be behaving exactly as its own manual says. The danger is in the seam between them.

Source: Carl Lender, via Wikimedia Commons (CC BY 2.0).jpg)
Source: Carl Lender, via Wikimedia Commons (CC BY 2.0)

Almost no serious website is a single machine any more. When you load a page, your request usually hits a front-end first: a content delivery network (CDN), a load balancer, or a reverse proxy. That front-end inspects the request, maybe applies some security rules, and then forwards it to a back-end server that actually runs the application. To be efficient, the front-end typically keeps one connection open to the back-end and pumps many users' requests down it, one after another, like train cars on a single track. For that to work, both machines have to agree on where each request stops. HTTP/1.1, the workhorse protocol that has carried the web since 1997, offers two different ways to signal how long a request's body is, and this is where the trouble starts. The first is the Content-Length header, which simply states the body size in bytes: Content-Length: 15 means "read exactly the next 15 bytes." The second is chunked transfer encoding, switched on with the header Transfer-Encoding: chunked. Instead of declaring a total, the body arrives in pieces, each prefixed with its size written in hexadecimal, and a chunk of size zero marks the end. Two mechanisms for one job is a recipe for ambiguity, and the standard knows it. RFC 9112, the 2022 specification for HTTP/1.1, is blunt: if a request somehow contains both headers, Transfer-Encoding overrides Content-Length, a server may reject the request outright, and it must close the connection afterward, because "such a message might indicate an attempt to perform request smuggling." That instruction is clear on paper. The problem is that the paper describes one server. Real traffic passes through several, written by different vendors, updated on different schedules, each making its own choice about which header to trust.

When two servers read the same bytes differently

Picture the attack in its classic form. An attacker sends a request that includes both a Content-Length and a Transfer-Encoding: chunked header, deliberately in conflict. The front-end and the back-end each pick a different header to obey. The result is that they carve the byte stream into requests at different points, and the leftover bytes from the attacker's message get glued onto the front of whatever request comes next, which may belong to another user entirely. Researchers name the variants by which server trusts which header. PortSwigger's Web Security Academy, the reference text most practitioners learn from, lays out three:

  • CL.TE: the front-end uses Content-Length, the back-end uses Transfer-Encoding. The front-end forwards what it thinks is a complete request, but the back-end stops early at a zero-size chunk and treats the remaining bytes as the beginning of a new request.
  • TE.CL: the reverse. The front-end honors the chunked encoding while the back-end counts bytes with Content-Length, so the back-end stops before the chunk stream is finished and leaves a fragment behind.
  • TE.TE: both servers understand chunked encoding, but the attacker obfuscates the header so that one of them fails to recognize it and falls back to Content-Length. A stray space, a tab, or a bogus value like Transfer-Encoding: xchunked is sometimes enough to fool exactly one server in the chain. A stripped-down CL.TE payload looks roughly like this:
POST / HTTP/1.1
Host: vulnerable.example
Content-Length: 13
Transfer-Encoding: chunked

0

SMUGGLED

The front-end reads Content-Length: 13 and forwards the whole thing as one request. The back-end reads Transfer-Encoding: chunked, sees the 0 chunk, and decides the request ended there. The word SMUGGLED is left in the buffer, waiting to be prepended to the next visitor's request. Replace that word with a real request line and headers, and you can prepend an entire request of your choosing to a stranger's traffic.

Source: H2g2bob, via Wikimedia Commons (CC0)
Source: H2g2bob, via Wikimedia Commons (CC0)

The subtlety worth sitting with is that neither server is broken. The front-end that trusts Content-Length and the back-end that trusts Transfer-Encoding are each making a defensible choice. The vulnerability is emergent. It exists only in the pairing. This is why request smuggling is sometimes called a chain-of-custody bug: no one link is faulty, but the handoff between them leaks.

A twenty-year-old bug that everyone forgot

The technique is not new. It was first documented in 2005 by a team at the security firm Watchfire, in a paper on "HTTP Request Smuggling" credited to Chaim Linhart, Amit Klein, Ronen Heled, and Steve Orrin, as the topic's history records. For most of the following decade it was treated as an academic curiosity. It was fiddly to find, seemed to require unusual server setups, and the web moved on to worrying about other things. Then in 2019, James Kettle, director of research at PortSwigger, dragged it back into the light with a Black Hat USA presentation and paper titled "HTTP Desync Attacks: Smashing into the Cell Next Door." Kettle's contribution was not the concept but the practicality. He developed a reliable, low-risk way to detect the flaw using timing: send an ambiguous request, and if the back-end is left waiting for bytes that never come, the connection hangs for a measurable moment. That time delay betrays the desync without corrupting anyone else's traffic. Armed with that method, he found the bug everywhere, including at PayPal and other major names, and collected more than $60,000 in bounties in the process. "Desync," short for desynchronization, became the umbrella term for the whole family, and Kettle's open-source Burp Suite extension, HTTP Request Smuggler, put automated detection in every tester's hands. Why had such a serious flaw sat neglected for fourteen years? Partly because it hides at the protocol layer rather than in application code, where scanners and bug hunters spend most of their attention. Partly because exploiting it demands an intimate feel for how specific servers parse bytes, knowledge that few people carried. And partly because the modern architecture that makes the attack so damaging, the sprawling chain of CDNs and proxies in front of every big site, only became universal in the 2010s. The bug did not change. The blast radius did.

What you can actually do with it

Prepending a hidden request to someone else's connection sounds abstract until you see what it buys an attacker. The most common goal is bypassing front-end security. Many architectures do their access-control checks at the front-end and trust anything the back-end receives. Smuggle a request for /admin past the guard, and the back-end, which never saw the guard, serves it. A second is capturing other users' requests. By smuggling a request that causes the back-end to store or reflect the next request it receives, an attacker can harvest a victim's session cookies or credentials as they arrive. The victim did nothing wrong; their request simply landed on a poisoned connection. The most far-reaching impact is web cache poisoning. If a smuggled request can convince a shared cache to store a malicious response under a legitimate URL, every subsequent visitor to that URL is served the attacker's content until the cache entry expires. One request can affect thousands of people. This is not hypothetical: CVE-2020-15810, a flaw in the widely deployed Squid proxy disclosed in 2020, allowed exactly this, HTTP request smuggling leading to cache poisoning. The same primitive also enables better-targeted cross-site scripting, open redirects, and credential theft, according to the Web Security Academy. The through-line is amplification. A normal web attack compromises one session at a time. Request smuggling lets a single crafted message reach into the traffic of everyone sharing an infrastructure.

HTTP/2 was supposed to fix this

Here is the most persistent misconception about request smuggling: that HTTP/2 made it go away. The belief is understandable. HTTP/2, standardized in 2015, replaced the ambiguous text framing of HTTP/1.1 with a binary format where every message carries an explicit, unambiguous length. Within a pure HTTP/2 conversation, the "which header wins" question simply cannot arise. On its own terms, HTTP/2 does close the classic hole. The catch is in the seam again. Enormous numbers of sites speak HTTP/2 to the browser at the front-end, then downgrade the request to HTTP/1.1 to talk to the back-end, because much back-end software still speaks only the old protocol. That translation step re-manufactures the very ambiguity HTTP/2 had removed. If the front-end mishandles the conversion, a length declared one way in HTTP/2 can be reinterpreted a different way in the HTTP/1.1 it emits. Kettle explored this in his 2021 research "HTTP/2: The Sequel is Always Worse." In 2022 he pushed further with "Browser-Powered Desync Attacks," published on August 10 of that year. Two ideas from it reset the field. The first was the client-side desync, where the split happens between the victim's own browser and the front-end, meaning an attacker no longer needs a special server setup or a vulnerable proxy chain; a single-server website can be exploited by luring a victim to a malicious page. The second was the CL.0 desync, in which the back-end ignores the body length entirely, an attack that can be mounted with a completely valid, specification-compliant request that no security filter would flag as suspicious. The research demonstrated live token theft against Amazon and flaws affecting Akamai (via capitalone.ca), Cisco and Pulse Secure VPNs, and AWS Application Load Balancer. So the honest summary is not "HTTP/2 fixed smuggling." It is "HTTP/2 fixed smuggling for anyone who uses it end to end, which almost nobody does."

The desync endgame

Kettle's most recent work states the conclusion in its title. "HTTP/1.1 Must Die: The Desync Endgame," published on August 6, 2025 and updated that October, argues that the protocol's ambiguity is unfixable in principle and that the only durable defense is to run HTTP/2 all the way to the back-end, cutting out the downgrade. The evidence he gathered is sobering. Across the research period he earned more than $350,000 in bounties, including that two-week haul of over $200,000 and $221,000 from Akamai alone across 74 separate reports. The Cloudflare flaw he found exposed around 24 million websites. Named victims in the writeup include T-Mobile, GitLab, LastPass, and the trading firm EXNESS, each felled by a different flavor of desync. The paper also formalizes just how many ways a request's length can now be misread. There are four: Content-Length, Transfer-Encoding, an implicit zero length, and HTTP/2's own framing. Every distinct pair of interpretations across two servers is a potential vulnerability. New techniques cataloged include the 0.CL desync and its reverse, attacks that abuse the little-used Expect header, and a "double-desync" that chains one flaw into another. Kettle's recommendation is specific: enable upstream HTTP/2 on your proxies, a feature already available on HAProxy, F5 BIG-IP, and Google Cloud, among others, while noting that some major vendors, at the time of writing, did not yet support it. There is a final twist. PortSwigger has begun turning this hunt over to machines. Its "HTTP Terminator" project used an AI system to autonomously discover novel desync attacks and, in testing, to break into real enterprise websites, including several financial-services firms. A bug class that took a human fourteen years to rediscover is now being industrialized by software that never gets bored of trying malformed requests.

What to watch

The uncomfortable lesson of request smuggling is that correctness is not composable. You can assemble a system out of parts that each pass every test, wire them together in the ordinary way, and produce something exploitable, because the guarantee each part makes is about itself, not about the conversation between them. That failure mode is not unique to HTTP. It shows up anywhere two systems parse the same data with subtly different rules, from filename handling to Unicode normalization to the way firewalls and applications disagree about what counts as one request. HTTP/1.1 will not actually die soon. It is embedded in decades of software, much of it unmaintained, and "just run HTTP/2 to your origin" is easy to say and expensive to do across a real fleet. The likelier future is a long, awkward coexistence in which the downgrade seam stays open and the attacks keep evolving. The question worth watching is not whether the next desync technique arrives, but who finds it first: the researchers publishing at Black Hat, or the automated systems that have quietly started reading the protocol more carefully than the people who deployed it.

Sources

  1. PortSwigger Web Security Academy, "What is HTTP request smuggling? Tutorial & Examples", accessed 2026.
  2. James Kettle, PortSwigger Research, "HTTP/1.1 Must Die: The Desync Endgame", 2025.
  3. James Kettle, Black Hat USA, "HTTP Desync Attacks: Smashing into the Cell Next Door", 2019.
  4. James Kettle, PortSwigger Research, "Browser-Powered Desync Attacks: A New Frontier in HTTP Request Smuggling", 2022.
  5. James Kettle, PortSwigger Research, "HTTP/2: The Sequel is Always Worse", 2021.
  6. IETF, "RFC 9112: HTTP/1.1", 2022.
  7. Wikipedia, "HTTP request smuggling", accessed 2026.
  8. Red Hat Bugzilla, "CVE-2020-15810: squid: HTTP Request Smuggling could result in cache poisoning", 2020.
  9. PortSwigger, "HTTP Request Smuggler (Burp Suite extension)", accessed 2026.