Most web apps sit behind a chain: a CDN or reverse proxy in front, an application server behind. Both have to agree on one basic thing — where each HTTP request ends. Request smuggling happens when they don't.
HTTP gives two ways to state a body's length: the Content-Length header (a byte count) and Transfer-Encoding: chunked (length-prefixed chunks ending in a zero-size chunk). If an attacker sends both, and the front-end trusts one while the back-end trusts the other, they parse the request to different endpoints. The bytes one server thinks are still "body" are what the other server reads as the start of the next request — which belongs to some other user sharing that back-end connection.
The two classic desyncs
- CL.TE — the front-end uses
Content-Length, the back-end usesTransfer-Encoding. The front-end forwards the whole body; the back-end stops at the chunked terminator early and treats the remainder as a new request. - TE.CL — the reverse: the front-end honors chunked, the back-end honors
Content-Length. The attacker sizes the chunk so that leftover bytes are queued for the next request on that connection.
Either way, the attacker's "leftover" bytes get prepended to the next request that flows over the reused connection. That victim request now carries the attacker's smuggled prefix.
What it buys an attacker
- Bypass front-end controls. Security rules, auth, and WAF checks enforced at the proxy are skipped by the portion of the request the back-end sees but the proxy never inspected.
- Capture other users' requests. A smuggled prefix can cause the victim's request — including their session cookie and headers — to be reflected back or stored where the attacker can read it.
- Cache poisoning and request hijacking across users sharing the back-end connection, because the corruption is on the connection, not just the attacker's own request.
The fix: one unambiguous interpretation across the whole chain
Smuggling only exists when two hops disagree. Remove the ambiguity everywhere.
The principles
- Never allow both length headers. A request with
Content-LengthandTransfer-Encodingis malformed — reject it at the edge with a 400. - Normalize framing at the front door. Strip or canonicalize ambiguous and obfuscated
Transfer-Encodingvalues before anything is proxied downstream. - Go HTTP/2 end to end. Unambiguous framing removes the entire class of CL/TE desync.
- Patch the chain. Smuggling is largely a parser-discrepancy bug; keeping proxies and app servers current closes known gaps.
The one line: request smuggling is two servers disagreeing about where a request ends — make the whole chain agree, and reject anything ambiguous at the edge.
Try it in the request smuggling simulation: craft a CL.TE payload, watch a hidden request prepend onto the next one, then apply edge validation and see the desync rejected. It shares DNA with web cache poisoning — both abuse how intermediaries handle your requests.
Frequently Asked Questions
Related posts
Race Conditions in Web Apps: When Two Requests Beat Your Check
Check-then-act logic that looks correct on paper breaks when two requests run at once. Here's how TOCTOU race conditions drain balances and reuse one-time codes, and how atomic operations and locks fix them.
Aug 11, 2026 · 7 min readMass Assignment: How role=admin Ends Up in Your Update
Mass assignment lets an attacker set fields you never meant to expose — like isAdmin or accountBalance — by adding them to a request body. Here's why binding whole objects is dangerous and how to allowlist fields in Node, Rails, and Django.
Aug 10, 2026 · 6 min readInsecure Deserialization: How Loading Data Becomes Running Code
Deserializing untrusted data can execute code before your app reads a single field. Here's how gadget chains work in Python pickle, Java, PHP, and Node, and why JSON with a schema is the fix.
Aug 9, 2026 · 7 min read