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.
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.
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.
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.
In 2021, Kettle published "HTTP/2: The Sequel is Always Worse," demonstrating several new smuggling techniques specific to HTTP/2 downgrade scenarios:
- H2.CL desync — HTTP/2 has its own content-length mechanism (the
DATAframe length). If the front-end uses the frame length but passes through aContent-Lengthheader to the back-end, and the values disagree, the back-end may be desynchronized. - H2.TE desync — HTTP/2 forbids
Transfer-Encoding, but some front-ends do not strip it during downgrade. The header passes through to the back-end, which processes chunked encoding on a request that was originally framed by HTTP/2. - Header injection via CRLF — HTTP/2 header values are binary and can contain bytes like
\r\nthat are illegal in HTTP/1.1 headers. When the front-end translates an HTTP/2 request to HTTP/1.1, these bytes become line terminators, allowing the attacker to inject entirely new HTTP/1.1 headers or even a second request. - Request splitting — A variation of header injection where the attacker injects a complete HTTP/1.1 response or request boundary into a header value, causing the back-end to see multiple messages where one was intended.
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:
- CVE-2019-16869 (Netty) — Netty's HTTP decoder mishandled whitespace in
Transfer-Encodingheaders, enabling TE.TE smuggling when paired with a stricter front-end. Netty is the HTTP layer beneath many Java-based services. - CVE-2020-8555 (Kubernetes) — SSRF via request smuggling in the kube-apiserver. An attacker could exploit HTTP parsing inconsistencies to reach cluster-internal services.
- CVE-2021-22959 and CVE-2021-22960 (Node.js) — Two smuggling vulnerabilities in Node.js's HTTP parser (
llhttp). The first allowed smuggling via improper handling of bare\rcharacters; the second involved incorrect parsing of chunked extension fields. - CVE-2022-1388 (F5 BIG-IP) — A critical vulnerability (CVSS 9.8) in F5's BIG-IP product line. Attackers exploited request smuggling via the
Connectionheader to bypass authentication on the iControl REST management interface, achieving unauthenticated remote code execution on BIG-IP appliances. This was actively exploited in the wild within days of disclosure. - CVE-2023-25690 (Apache HTTP Server) — When
mod_proxywas configured withRewriteRule, specially crafted requests could exploitContent-Length/Transfer-Encodingdisagreements to smuggle requests past the proxy. - CVE-2023-44487 (HTTP/2 Rapid Reset) — While primarily a denial-of-service vulnerability, the HTTP/2 rapid reset attack exploited frame handling inconsistencies across implementations, highlighting how protocol-level framing bugs remain a live concern.
- CVE-2024-24795 (Apache HTTP Server) — HTTP response splitting via malformed headers in
mod_proxy, allowing smuggling through header injection in the downgrade path.
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:
- CL.TE detection — Send a request with
Content-Lengthindicating a short body but a chunked body that does not terminate. If the back-end usesTransfer-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 usedContent-Length), confirming CL.TE. - TE.CL detection — Send a request with a valid chunked body (terminating with
0\r\n\r\n) but aContent-Lengthlarger than the actual body. If the back-end usesContent-Length, it waits for more data and times out. A timeout confirms TE.CL. - 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:
- HAProxy —
option http-restrict-req-hdr-names rejectand strict parsing enabled by default in modern versions. - nginx — Rejects requests with both
Content-LengthandTransfer-Encodingby default since version 1.21.1. - Apache —
HttpProtocolOptions Strictenforces RFC compliance. - AWS ALB — Strips ambiguous headers before forwarding.
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:
- AS13335 — Cloudflare, which operates one of the largest reverse proxy networks
- AS16509 — Amazon Web Services, including ALB and CloudFront
- AS20940 — Akamai, a pioneer in CDN and edge security
- AS15169 — Google, operating Cloud Load Balancing and Cloud CDN
Further Reading
- James Kettle, HTTP Desync Attacks: Smashing into the Cell Next Door (2019) — the research that reignited interest in request smuggling
- James Kettle, HTTP/2: The Sequel is Always Worse (2021) — HTTP/2 downgrade smuggling
- James Kettle, Browser-Powered Desync Attacks (2022) — client-side desync using browser-initiated requests
- RFC 7230, Section 3.3.3 — the normative text on message body length and Content-Length/Transfer-Encoding precedence
- RFC 7540, Section 8.1.2.6 — HTTP/2 rules on Content-Length
- PortSwigger Web Security Academy — interactive labs for practicing request smuggling techniques