HTTP request smuggling: when two servers disagree on where a request ends
HTTP request smuggling is an attack on the chain of servers in front of an application. A front-end, such as a proxy, load balancer or CDN, and the back-end server read the same stream of bytes, but disagree about where one request ends. The attacker sends something the front-end sees as one request and the back-end sees as one and a half, and the leftover half is glued onto the next request in line, often someone else's.
Quick facts
- Also called
- HTTP desync attack
- Weakness
- CWE-444: inconsistent interpretation of HTTP requests
- OWASP category
- A06:2025 Insecure Design, which lists CWE-444 (A06 page); see OWASP Top 10
- Needs
- At least two HTTP processors in a row that parse message length differently
- Does a WAF stop it?
- Partly. A front-end that refuses ambiguous requests removes the attack; one that forwards them is part of it
The HTTP/1.1 rules on message length and smuggling are in RFC 9112, sections 6 and 11.2.
Where a request ends
Over one HTTP/1.1 connection, requests follow each other with nothing in between. The receiver works out where a request body ends from one of two headers: Content-Length, which gives the size in bytes, or Transfer-Encoding: chunked, which sends the body in pieces and ends with an empty piece.
If a request carries both, RFC 9112 says Transfer-Encoding wins, and that such a message might be an attempt at request smuggling and ought to be handled as an error. Not every server follows that rule the same way, and the gap between two servers that differ is the whole attack.
How request smuggling works
Front-ends reuse a few connections to the back-end for requests from many users. The attacker sends a request whose length is ambiguous:
- CL.TE. The front-end uses Content-Length and forwards the whole body. The back-end uses Transfer-Encoding, stops at the empty chunk, and treats the rest as the start of the next request.
- TE.CL. The front-end uses Transfer-Encoding; the back-end uses Content-Length, reads fewer bytes, and leaves the rest waiting.
- TE.TE. Both support Transfer-Encoding, but one of them can be made to ignore an oddly written header, which turns the case into one of the two above.
The smuggled leftover sits at the start of the back-end connection. When the next request arrives, possibly from another user, the back-end reads the attacker's prefix first and the real request as its continuation.
What attackers do with it
- Bypass front-end controls. A smuggled request never passes the front-end's checks, because the front-end thought it was body data.
- Capture other users' requests. A smuggled prefix that stores data can swallow the next user's request, cookies included.
- Poison caches. A response meant for the smuggled request is stored under a normal address and served to everyone.
- Deliver other attacks. Reflected XSS or open redirects, delivered to users who never clicked anything.
The relation to CRLF injection is close: both exploit how HTTP marks boundaries. CRLF injection writes new header lines into a message; smuggling exploits disagreement about where a message ends.
HTTP/2 and request smuggling
HTTP/2 frames carry their own length, so end-to-end HTTP/2 does not have this ambiguity. The risk returns when a front-end speaks HTTP/2 to the browser and rewrites requests as HTTP/1.1 for the back-end. If it copies a Content-Length or Transfer-Encoding header from the client without checking it, the back-end sees the same ambiguous message as before.
That is why the fix is about the whole chain, not one hop: every server that turns one format into another has to validate what it writes.
How to prevent HTTP request smuggling
- Refuse ambiguous requests at the front. Both Content-Length and Transfer-Encoding, repeated or malformed length headers, odd spacing: reject, do not normalise and forward.
- Use HTTP/2 end to end where possible. Or validate every header when downgrading to HTTP/1.1.
- Keep front-end and back-end parsers up to date. Most real cases are parser bugs fixed in later versions.
- Close the back-end connection after an error. A connection that saw a bad request should not carry the next user's.
- Avoid reusing back-end connections across users where you can. It removes the queue that smuggling relies on, at some cost in performance.
What a WAF can do about request smuggling
A request filter is itself a front-end, so it is either the defence or part of the problem. One that refuses messages with conflicting length headers removes the most common variants before they reach the back-end. One that parses differently from the server behind it creates a new gap.
Smuggling is also a reason to keep the origin reachable only through the front-end: a back-end that also accepts connections directly has two front doors with different rules.
Questions
What is HTTP request smuggling?
An attack in which a front-end server and a back-end server disagree about where an HTTP request ends, so part of the attacker's request is treated as the start of the next request on the same connection.
What is the difference between CL.TE and TE.CL?
In CL.TE the front-end measures the body with Content-Length and the back-end with Transfer-Encoding; in TE.CL it is the other way round. Either way, the leftover bytes become a smuggled request.
Does HTTP/2 prevent request smuggling?
End-to-end HTTP/2 does, because frames carry their own length. A front-end that downgrades HTTP/2 to HTTP/1.1 for the back-end can reintroduce it if it does not validate length headers.
How do you prevent request smuggling?
Refuse requests with conflicting or malformed length headers at the front-end, use HTTP/2 end to end or validate when downgrading, keep parsers updated, and close back-end connections after errors.