What is HTTP Request Smuggling?

HTTP request smuggling is a technique that exploits disagreements between HTTP processors about where one request ends and the next begins. When a front-end server (a reverse proxy, load balancer, or CDN) and a back-end server parse the boundaries of HTTP requests differently, an attacker can "smuggle" a hidden request inside what the front-end believes is a single legitimate request. The back-end sees two requests where the front-end saw one, and the smuggled request bypasses all front-end security controls — access controls, WAF rules, authentication checks — as if it were never inspected at all.

First documented in 2005 by Lindy Zelling and Chaim Linhart at Watchfire, HTTP request smuggling remained a curiosity for over a decade. It was James Kettle's 2019 research at PortSwigger, presented at DEF CON and Black Hat under the title "HTTP Desync Attacks: Smashing into the Cell Next Door," that demonstrated how devastating and widespread these vulnerabilities really are. Kettle found smuggling flaws in production systems belonging to major technology companies, defense contractors, and financial institutions — proving this was not a theoretical concern but an active, exploitable class of vulnerability.

The Root Cause: Content-Length vs Transfer-Encoding

HTTP/1.1 provides two mechanisms for specifying the length of a request body. The first is the Content-Length header, which states the body size in bytes as a simple integer. The second is the Transfer-Encoding: chunked header, which sends the body in a series of chunks, each prefixed with its size in hexadecimal, and terminated by a zero-length chunk.

RFC 7230 (Section 3.3.3) is explicit: if both headers are present, Transfer-Encoding takes precedence and Content-Length must be ignored. In practice, not every HTTP implementation follows this rule. Some servers prioritize Content-Length. Some process whichever header they encounter first. Some fail to parse Transfer-Encoding when it is obfuscated with unusual whitespace, capitalization, or duplicate values. This disagreement between the front-end and back-end is the wedge that attackers exploit.

Front-End Proxy Uses Content-Length Back-End Server Uses Transfer-Encoding forwards "one" request POST / HTTP/1.1 Host: target.com Content-Length: 6 Transfer-Encoding: chunked 0 <blank line> G ← front-end reads 6 bytes total ← back-end reads until 0\r\n\r\n ← "G" left in buffer = start of smuggled request

CL.TE: Front-End Uses Content-Length, Back-End Uses Transfer-Encoding

In a CL.TE attack, the front-end server determines the request boundary using Content-Length, while the back-end uses Transfer-Encoding: chunked. The attacker sends a request with both headers, carefully crafting the body so that the front-end forwards the entire payload as a single request, but the back-end — parsing chunk boundaries — considers the body to end earlier. The remaining bytes are left sitting in the back-end's input buffer, where they become the beginning of the next request that the back-end processes.

Consider this request:

POST / HTTP/1.1
Host: vulnerable-site.com
Content-Length: 35
Transfer-Encoding: chunked

0

GET /admin HTTP/1.1
X-Ignore: x

The front-end reads Content-Length: 35 and forwards all 35 bytes of the body (including the chunked terminator, the blank line, and the start of the smuggled request) as a single request. The back-end parses the body as chunked transfer encoding, reads the 0\r\n\r\n chunk terminator, and considers the first request complete. Everything after that — GET /admin HTTP/1.1\r\nX-Ignore: x — is treated as the beginning of a brand new request. This new request was never inspected by the front-end proxy. If the front-end enforces access control on /admin, it has been bypassed entirely.

TE.CL: Front-End Uses Transfer-Encoding, Back-End Uses Content-Length

The TE.CL variant flips the disagreement. The front-end parses the request body using chunked transfer encoding, while the back-end uses Content-Length. The attacker embeds the smuggled request inside a chunk that the front-end dutifully forwards, but the back-end, counting bytes from Content-Length, stops reading the body early and treats the remainder as a new request.

POST / HTTP/1.1
Host: vulnerable-site.com
Content-Length: 4
Transfer-Encoding: chunked

71
POST /admin HTTP/1.1
Host: vulnerable-site.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 15

x=1
0

The front-end follows chunked encoding: it reads the chunk of size 0x71 (113 bytes), then reads the terminating 0 chunk, and forwards everything as one request. The back-end reads Content-Length: 4 bytes from the body (just 71\r\n), considers the request done, and then finds POST /admin HTTP/1.1... waiting in the buffer as a fresh request. The smuggled request to /admin executes without any front-end scrutiny.

TE.TE: Obfuscating Transfer-Encoding

When both the front-end and back-end support Transfer-Encoding, a direct CL.TE or TE.CL attack fails because both servers agree on the request boundaries. The TE.TE variant works around this by sending an obfuscated Transfer-Encoding header that one server processes and the other ignores. If one server fails to recognize the mangled header and falls back to Content-Length, the situation reduces to either CL.TE or TE.CL.

There are dozens of known obfuscation techniques:

Transfer-Encoding: xchunked
Transfer-Encoding : chunked          (space before colon)
Transfer-Encoding: chunked
Transfer-Encoding: x                 (duplicate header, second value invalid)
Transfer-Encoding:
 chunked                             (line folding / obs-fold)
Transfer-Encoding: chunked
X: X[\n]Transfer-Encoding: chunked   (header injection via bare \n)
Transfer-Encoding: chu\x00nked       (null byte injection)

Each HTTP implementation has its own parser quirks. Apache, nginx, HAProxy, IIS, Tomcat, Node.js, and Gunicorn all handle these edge cases differently. The attacker's goal is to find a specific obfuscation that one server in the chain processes as valid chunked encoding while another rejects and falls back to Content-Length. James Kettle's research tooling systematically fuzzes these variations against live targets to discover exploitable desync conditions.

Three Variants of HTTP Request Smuggling CL.TE Front-End Content-Length Back-End Transfer-Encoding Front-end sends too many bytes. Back-end stops at chunk end. Remainder = smuggled. Most common variant in the wild TE.CL Front-End Transfer-Encoding Back-End Content-Length Back-end reads fewer bytes than front-end sent. Remainder = smuggled request. Harder to exploit (timing-sensitive) TE.TE Front-End TE (valid parse) Back-End TE (fails, uses CL) Obfuscated TE header tricks one server. Reduces to CL.TE or TE.CL in practice. Exploits parser implementation quirks

The Anatomy of a Desync

To understand why request smuggling is so dangerous, you need to understand how HTTP connection reuse works. Modern web infrastructure keeps TCP connections alive between the front-end and back-end to avoid the overhead of establishing new connections for every request. The front-end multiplexes requests from many different clients onto a pool of persistent connections to back-end servers.

This is where the desync becomes catastrophic. When the front-end and back-end disagree on a request boundary, the leftover bytes from the attacker's request sit in the connection buffer. The next legitimate request that happens to be routed over that same connection gets prepended with the attacker's smuggled data. The victim's request is corrupted or hijacked, and the victim had no involvement in the attack whatsoever — they simply had the misfortune of their request being assigned to the poisoned connection.

Connection Reuse Enables Cross-User Attacks Attacker Victim Front-End Reverse Proxy Back-End App Server Shared TCP Connection Pool 1. malicious req 3. normal request Back-end TCP buffer (connection reused): Attacker's request (processed) Smuggled prefix Victim's request (appended) Back-end sees: smuggled prefix + victim's request = attacker-controlled request

Real-World Exploitation Scenarios

Request smuggling is not just an access control bypass. It unlocks a family of devastating attack techniques that affect every user of the vulnerable application.

Web Cache Poisoning

If a CDN or caching reverse proxy sits in front of the application, request smuggling can poison the cache for arbitrary URLs. The attacker smuggles a request that causes the back-end to return malicious content (say, an XSS payload or a redirect to a phishing site) for a URL like /login. The cache stores this malicious response and serves it to every subsequent user who requests that URL. A single smuggled request can compromise thousands of users.

Kettle demonstrated this against a major SaaS provider in 2019: by smuggling a request that set a malicious Host header, he poisoned the CDN cache for the provider's login page. Every user visiting the login page would receive a response containing attacker-controlled JavaScript — a full account takeover chain from a single HTTP request.

Credential Theft via Request Hijacking

The attacker smuggles a partial request ending with a header like Content-Length: 500 and an incomplete body. When the next user's request arrives on the same connection, their request — including cookies, authorization tokens, and session IDs — is appended to the attacker's smuggled request as the "body." The back-end processes this combined request, and if the smuggled request targets an endpoint the attacker can later read (such as posting to a forum, submitting feedback, or updating a profile), the victim's credentials are exfiltrated and stored in the attacker-controlled location.

POST /post/comment HTTP/1.1
Host: vulnerable-site.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 800

comment=

This smuggled prefix sits in the buffer. The next user's request — including their Cookie: session=abc123; csrf=xyz789 header — is concatenated as the "comment" body. The attacker visits the comments page and reads the captured credentials.

Request Routing Abuse

In microservices architectures where the front-end routes requests to different back-end services based on URL path or Host header, smuggling can route requests to internal services that should never be directly accessible. The front-end sees a request for /public-api and routes it to the public service, but the smuggled request targets /internal-admin-api and reaches the internal service through the shared connection pool. This bypasses network segmentation enforced at the proxy layer.

On-Site Redirect Exploitation

Many web servers issue redirects for paths without trailing slashes (e.g., /docs redirects to /docs/). The redirect typically echoes the Host header into the Location response header. By smuggling a request with a controlled Host header to a path that triggers an automatic redirect, the attacker can make the back-end issue a redirect to an attacker-controlled domain. If this redirect response is served to a victim (via connection reuse) or cached, users are redirected to a phishing site.

HTTP/2 Downgrade Smuggling

The introduction of HTTP/2 was supposed to eliminate request smuggling entirely. HTTP/2 uses a binary framing layer with explicit length fields for each frame, so there is no ambiguity about where one message ends and the next begins. You cannot send conflicting Content-Length and Transfer-Encoding headers in a well-formed HTTP/2 request — the protocol forbids it.

But most real-world deployments do not run HTTP/2 end-to-end. The front-end (typically a CDN or load balancer) accepts HTTP/2 from clients, then downgrades the request to HTTP/1.1 when forwarding to the back-end. This translation step reintroduces the exact parsing ambiguities that HTTP/2 was designed to prevent.

HTTP/2 Downgrade Smuggling Client (Attacker) CDN / Load Balancer H2 → H1.1 translation Back-End HTTP/1.1 HTTP/2 HTTP/1.1 HTTP/2 binary frames allow injecting headers illegal in HTTP/1.1 e.g., \r\n in header values → header injection in the translated H1.1 request The translation layer reconstructs HTTP/1.1 text from binary frames, potentially introducing smuggling vectors

In 2021, Kettle published "HTTP/2: The Sequel is Always Worse," demonstrating several new smuggling techniques specific to HTTP/2 downgrade scenarios:

HTTP/2 downgrade smuggling is particularly insidious because many organizations assumed that deploying HTTP/2 on their front-end had eliminated smuggling risks. The binary framing protects the front-end-to-client hop, but the back-end still receives an HTTP/1.1 text stream that is just as vulnerable to parsing ambiguities as ever.

Real CVEs and Incidents

HTTP request smuggling has been assigned numerous CVEs across nearly every major HTTP implementation and proxy:

Beyond CVEs, Kettle's original research disclosed smuggling vulnerabilities in production systems at major companies including a US Department of Defense contractor (where he demonstrated access to internal systems), a large SaaS platform (full account takeover via cache poisoning), and numerous e-commerce and financial services sites.

Detection and Exploitation Techniques

Detecting request smuggling in black-box testing requires careful techniques because sending a malformed request can affect other users on the same connection. Kettle developed a timing-based differential detection approach:

  1. CL.TE detection — Send a request with Content-Length indicating a short body but a chunked body that does not terminate. If the back-end uses Transfer-Encoding, it waits for the chunk terminator and eventually times out. A timeout indicates the back-end is parsing chunked encoding (and the front-end used Content-Length), confirming CL.TE.
  2. TE.CL detection — Send a request with a valid chunked body (terminating with 0\r\n\r\n) but a Content-Length larger than the actual body. If the back-end uses Content-Length, it waits for more data and times out. A timeout confirms TE.CL.
  3. Confirming exploitability — Send a smuggled prefix that will cause the next request on the connection to receive a distinctive response (e.g., a 404 for a known-good URL). Send a follow-up "normal" request and check whether it returns the anomalous response.

PortSwigger's HTTP Request Smuggler extension for Burp Suite automates this detection workflow and has been instrumental in making smuggling vulnerabilities discoverable by security testers worldwide.

Defenses Against HTTP Request Smuggling

Defending against request smuggling requires action at multiple layers. There is no single configuration toggle that eliminates the risk; defense-in-depth is essential.

Normalize or Reject Ambiguous Requests

The front-end proxy must enforce strict HTTP parsing. If a request contains both Content-Length and Transfer-Encoding, the front-end should either reject the request with a 400 error or normalize it by removing Content-Length before forwarding (per RFC 7230). Major proxy implementations have added strict modes for this:

Use HTTP/2 End-to-End

If both the front-end and back-end speak HTTP/2, the binary framing eliminates Content-Length/Transfer-Encoding ambiguity entirely. The protocol's frame structure makes it impossible for the endpoints to disagree on message boundaries. The key requirement is no downgrade: if the front-end translates HTTP/2 to HTTP/1.1 before reaching the back-end, the protection is lost. gRPC environments often achieve this naturally, as gRPC mandates HTTP/2.

Disable Connection Reuse Between Front-End and Back-End

If each front-end request uses a fresh TCP connection to the back-end, a smuggled request cannot affect other users — there is no shared buffer for the smuggled bytes to contaminate. This eliminates the cross-user attack vector at the cost of increased latency and connection overhead. It is a viable option for high-security endpoints (e.g., authentication pages) where the performance cost is acceptable.

Ensure Consistent Parsing Across the Chain

The most fundamental defense is to ensure that every HTTP processor in the request path interprets requests identically. This means using the same HTTP library, or at minimum configuring all components to follow the same parsing behavior for edge cases (chunked extensions, obs-fold headers, multiple Content-Length values, etc.). In practice, this is difficult when different components are developed by different vendors, which is why strict rejection of ambiguous requests is the more practical approach.

Monitor and Alert

Deploy monitoring that compares the front-end's view of a request with the back-end's view. If the front-end logged a request for /public but the back-end processed a request for /admin, that discrepancy is a strong signal of smuggling. Similarly, unexpected 400 errors or timeouts on back-end connections can indicate desync attempts. WAF rules that flag requests containing both Content-Length and Transfer-Encoding provide an early warning layer.

Smuggling in Modern Infrastructure

Request smuggling intersects with several layers of modern web infrastructure. CDNs like Cloudflare and Akamai sit in front of origin servers, creating exactly the front-end/back-end split that smuggling exploits. Load balancers from cloud providers (AWS ALB, GCP Load Balancer, Azure Application Gateway) perform HTTP parsing and forwarding, introducing another potential desync point. Even TLS termination layers can be relevant: if TLS is terminated at the front-end and the back-end connection is plaintext HTTP/1.1, the unencrypted hop is where smuggling occurs.

The layered nature of modern web architecture — client, CDN edge, WAF, load balancer, reverse proxy, application server — means there are multiple boundaries where parsing disagreements can arise. Each additional layer is another opportunity for a desync. Organizations running multi-tier proxy chains (e.g., Cloudflare in front of nginx in front of an application server) must ensure consistent parsing at every boundary, not just the outermost one.

The Connection to Network Security

While HTTP request smuggling is an application-layer attack, it connects to the network-layer topics central to internet infrastructure. The BGP routing decisions that determine which physical path your packets take, the CDN edge nodes that terminate your TLS connections, and the load balancers that distribute requests across back-end servers — these are the same components that create the front-end/back-end splits that smuggling exploits. Understanding how traffic flows through these layers is essential to understanding where smuggling vulnerabilities can hide.

You can explore the network infrastructure of major CDN and proxy providers to see how their networks are structured:

Further Reading

See BGP routing data in real time

Open Looking Glass
More Articles
How TLS/HTTPS Works: Securing the Internet's Traffic
Certificate Transparency: How CT Logs Secure the Web's PKI
How Firewalls Work: Packet Filtering, Stateful Inspection, and Beyond
What is Cross-Site Scripting (XSS)?
What is Cross-Site Request Forgery (CSRF)?
What is Server-Side Request Forgery (SSRF)?