HTTP Request Smuggling
The front-end and back-end disagree about where one request ends, so you hide a second request inside the first.
What you will learn
- -Explain how CL and TE disagreements create a desync
- -Distinguish CL.TE from TE.CL smuggles
- -Use a timing probe to detect desync safely
Two reading the same bytes and disagreeing on where the request ends is the entire attack. A front-end proxy forwards traffic to a back-end server over a reused connection. If they parse the request boundary differently, part of what you sent gets treated by the back-end as the start of the next request. That leftover piece is your smuggled request, and it attaches itself to whoever's connection comes through next, which is often another user.
The disagreement lives in two that both to say how long the body is. Content-Length gives a byte count. Transfer-Encoding: chunked says the body arrives in size-prefixed chunks ending with a zero chunk. A request should never send both. When it does, the RFC says prefer Transfer-Encoding, but plenty of servers ignore that, and any mismatch between front and back is exploitable.
CL.TE and TE.CL
Name the desync by which server trusts which header. In CL.TE, the front-end uses Content-Length and the back-end uses Transfer-Encoding. In TE.CL, it is reversed. That ordering decides how you craft the smuggle, so identify it before building a .
Here is a CL.TE body. The front-end reads Content-Length: 6 and forwards all six bytes plus the smuggled part it thinks is filler. The back-end reads chunked, sees the 0 terminator, ends the request there, and treats G as the beginning of the next request on that connection.
$Content-Length: 6$Transfer-Encoding: chunked$0$GTE.CL flips it. The front-end honors the chunked and passes the whole thing, while the back-end stops after Content-Length bytes and leaves your trailing request queued. Getting a proxy to honor a header it should ignore usually means obfuscating the Transfer-Encoding line so only one of the two servers recognizes it.
$Transfer-Encoding:[tab]chunkedDetect it without breaking things
Do not confirm a smuggle by poisoning real users. Use the timing technique instead: send a payload that, if the back-end desyncs, forces it to wait for bytes that never arrive. A normal server responds fast. A vulnerable one hangs for the timeout.
$Transfer-Encoding: chunked$1$A$XA big, repeatable delay that only appears with the malformed body is your signal. It is safe because you are stalling your own connection, not injecting into anyone else's. Burp's smuggler extension automates exactly this probe across CL.TE and TE.CL.
A successful smuggle steals other people's requests, poisons shared caches, and bypasses front-end access . That means real user , so run it only in a lab or under written , and prefer the timing probe over payloads that capture live traffic. PortSwigger's Web Security Academy has a full request smuggling track with safe, resettable targets.
Once confirmed, the payoffs are serious: prepend a request that captures the next user's headers including their session , bypass a front-end that blocks /admin by smuggling the path past it, or poison the response queue so users each other's pages. /2 downgrade smuggling extends all of this to modern where a front-end speaks h2 and rewrites to h1 on the way back.
In a CL.TE desync, which server trusts which header?