Quick answer: HTTP Request Smuggling is an attack that exploits the fact that two chained servers (a front-end and a back-end) interpret differently where an HTTP request ends. By manipulating the Content-Length and Transfer-Encoding headers, you "smuggle" part of a request that the back-end attributes to the next one, letting you bypass controls, poison the cache or steal other users' requests.
What is HTTP Request Smuggling?
In the modern web, your request almost never reaches the application server directly. It passes through a chain: a reverse proxy, a CDN or a load balancer (the front-end) forwards requests to one or more application servers (the back-end), reusing the same connection for several requests.
The problem appears when the front-end and the back-end disagree about where a request ends. HTTP allows indicating the end of the body in two ways: with the Content-Length header (how many bytes the body has) or with Transfer-Encoding: chunked (the body is sent in chunks and ends with a zero-size chunk). If one of the servers obeys one header and the other obeys the other, an attacker can craft an ambiguous request where part of their bytes is interpreted as the start of the next request. That's smuggling: sneaking one request inside another.
It's a high-end vulnerability that usually scores as high or critical severity. Its theory, along with other complex techniques, is in Academy › Advanced.
Why does this problem exist?
The root is in two modern-web design decisions that, combined, open the door:
- Reused keep-alive connections. For performance, the front-end doesn't open a new connection to the back-end for each request: it reuses the same one for many, one after another. That means if the back-end gets out of sync about where a request ends, the next request in the queue belongs to another user. That's where the theft potential is.
- Two ways to delimit the body. The HTTP/1.1 standard says
Transfer-Encoding should take priority over Content-Length, and that a request with both headers is ambiguous and should be rejected. But in practice, different servers (Nginx, Apache, IIS, CDNs, load balancers) have implemented this in slightly different ways over the years. That inconsistency is the crack.
When an attacker sends both headers at once, or an obfuscated Transfer-Encoding, they bet the front-end and back-end will treat them differently. If they're right, they desync the connection. That's why the underlying fix is to normalize how these headers are parsed across the whole chain.
The three variants: CL.TE, TE.CL and TE.TE
The notation describes which header each server prioritizes. The first term is the front-end; the second, the back-end.
CL.TE
The front-end uses Content-Length and the back-end uses Transfer-Encoding. The front forwards what it thinks is one request based on its length, but the back parses it by chunks and there's "leftover" content that it treats 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, guided by Content-Length: 13, sends the entire block. The back-end, guided by Transfer-Encoding: chunked, sees the 0 as the end of the body and treats SMUGGLED as the beginning of the next request.
TE.CL
The reverse: the front-end uses Transfer-Encoding and the back-end uses Content-Length. The smuggled block is placed inside a chunk, and the back-end —which only looks at the length— leaves part of it out for the following request.
TE.TE
Both support Transfer-Encoding, but one of the two can be induced to ignore it by obfuscating the header (for example, Transfer-Encoding : chunked with an odd space, altered casing or duplicate values). By getting one to discard it, the scenario degenerates into a CL.TE or TE.CL. The key here is header obfuscation. Typical obfuscation variants that one server might process and another ignore:
Transfer-Encoding: xchunked
Transfer-Encoding : chunked
Transfer-Encoding: chunked
Transfer-Encoding: chunked
Transfer-Encoding: identity
X: X[\n]Transfer-Encoding: chunked
Each line exploits a different parsing detail (a space before the colon, a duplicate value, an odd prefix). The goal is always the same: one of the two servers respects the header and the other discards it.
How to detect smuggling?
Detecting it without breaking the service is an art. Two main approaches:
1. Timing technique. You send a request designed so that, if there's desync, the back-end waits for more bytes that never arrive and causes a delay. An anomalous response time (several seconds versus milliseconds) gives away the vulnerability. It's the safest technique for a first detection because it doesn't poison other users.
2. Differential technique (confirmation). You send two requests in a row: the first smuggles a prefix that alters the response of the second. If the second request returns something different from normal (an error, another route), you confirm the desync. Here you have to be careful: done wrong, you can affect real users' requests.
Ethical golden rule: in a bug bounty program, detect with timing, confirm with the minimum possible impact and never run tests that poison other users' responses beyond what's strictly necessary to demonstrate the flaw. Document and stop.
What's the impact?
Smuggling is dangerous because what you smuggle affects the shared connection, not just you:
- Bypassing front-end security controls. Many controls (WAF, authentication, path filters) live on the front-end. If you smuggle a request that the back-end processes without going through those controls, you bypass them. It's a common way to reach blocked administrative routes.
- Cache poisoning. You can get the cache to store a malicious response associated with a legitimate URL, serving it to other users. It overlaps with cache poisoning, and chaining both multiplies the impact.
- Stealing other users' requests. By smuggling a prefix that "captures" the next request in the queue, you can make another victim's request (with their cookies or tokens) end up reflected in a response you control. Session theft without touching the victim's browser.
- Amplified reflected XSS. Turning an XSS that would require interaction into one served to anyone who passes through that connection.
That ability to affect third parties is what raises the severity: it's not a flaw that only affects you.
How to test it? The Burp extension
The reference tool is HTTP Request Smuggler, the Burp Suite extension created by James Kettle (the researcher who popularized these modern techniques). It installs from the BApp Store and automates much of the work:
- You intercept a request to the target with Burp.
- You launch the extension's smuggling scan (it uses timing detection).
- If it detects desync, it helps you build the specific attack (CL.TE, TE.CL…) with its "smuggle probe" function.
- You confirm the impact in a controlled way and document the minimal request.
Working smuggling by hand requires a very good low-level understanding of HTTP; the extension reduces the error, but you provide the judgment about what's safe to test.
And smuggling in HTTP/2?
Recent research has shown that the problem didn't die with HTTP/2. When a front-end speaks HTTP/2 with the client but downgrades the connection to HTTP/1.1 to talk to the back-end, it can reintroduce header ambiguity when making that translation. These are the "H2.CL" and "H2.TE" variants: the HTTP/2 front-end generates inconsistent Content-Length or Transfer-Encoding headers when converting. It's advanced terrain, but it's worth knowing the surface is still alive even in modern infrastructures.
How is it fixed?
On the defensive side, the real mitigations are clear:
- Use HTTP/2 end to end without downgrading to HTTP/1.1, removing the source of ambiguity.
- Normalize ambiguous requests: have the front-end reject any request that carries both
Content-Length and Transfer-Encoding, instead of trying to interpret it.
- Have the front-end and back-end use the same server/version or, at minimum, the same parsing logic, so they never disagree.
- Disable connection reuse to the back-end when the risk justifies it (it has a performance cost, but it cuts the user-to-user theft path).
As a hunter, understanding the defense improves your report: you can explain not only the flaw, but the concrete fix the team should apply.
Frequently asked questions (FAQ)
Is it dangerous to test request smuggling on a real target?
It can be. Differential tests can affect other users' requests. Detect with the timing technique (safe), confirm with minimal impact and stop as soon as you demonstrate it. Never poison real users' responses beyond what's essential.
Is it useful if the site only has one server?
Smuggling needs a chain of at least two systems that parse HTTP (proxy/CDN/load balancer + back-end). If the request reaches a single server directly with no intermediaries, there aren't two interpretations to pit against each other.
What severity does a request smuggling have?
Usually high or critical, because it lets you affect other users: steal their requests, bypass front-end controls or poison the cache. The exact impact depends on what you can chain.
Do I need the Burp extension or can I do it by hand?
You can do it by hand if you master low-level HTTP, but HTTP Request Smuggler drastically reduces the margin of error in detection and building the attack. To start, the extension is highly recommended.
How to get started with smuggling
It's an advanced technique: it's not the first thing you attack as a newcomer. The reasonable path is to first master the OWASP Top 10 families by hand, understand the request/response cycle well with a proxy, and then move up to desync techniques like this one.
To arrive prepared, train web exploitation with labs that replicate real reports and study the advanced theory in Academy › Advanced. When the HTTP cycle is transparent to you, smuggling stops looking like magic and becomes a desync you know how to read, detect and demonstrate responsibly.