HTTP request smuggling is one of those vulnerabilities that should not exist. The HTTP specification defines how to determine the boundary between requests. Servers should agree on where one request ends and the next begins. But they do not, and that disagreement is exploitable.
When a frontend server (load balancer, reverse proxy, CDN) and a backend server disagree about request boundaries, an attacker can smuggle a hidden request inside a legitimate one. The frontend sees one request. The backend sees two. The smuggled request bypasses frontend security controls and is processed with the context of whatever legitimate request follows it.
The Core Problem: Content-Length vs Transfer-Encoding
HTTP provides two mechanisms for specifying the body length of a request:
Content-Length specifies the body size in bytes. The server reads exactly that many bytes after the headers.
Transfer-Encoding: chunked sends the body in chunks, each prefixed with its size in hexadecimal. A zero-length chunk signals the end of the body.
The HTTP specification states that if both headers are present, Transfer-Encoding takes precedence. In practice, different servers handle this differently, and that discrepancy is the root cause of request smuggling.
CL.TE Smuggling
The frontend uses Content-Length, the backend uses Transfer-Encoding. The attacker sends:
POST / HTTP/1.1
Host: target.com
Content-Length: 35
Transfer-Encoding: chunked
0
GET /admin HTTP/1.1
X-Ignore: X
The frontend reads 35 bytes (the entire body including the smuggled request) and forwards everything to the backend as a single request. The backend processes the chunked encoding, sees the 0\r\n\r\n terminator, and treats everything after it as the start of a new request: GET /admin HTTP/1.1.
The smuggled GET /admin request sits in the backend's buffer. When the next legitimate user's request arrives, it is appended to the smuggled request as headers or body, and the backend processes the smuggled request with the victim's cookies and session.
TE.CL Smuggling
The frontend uses Transfer-Encoding, the backend uses Content-Length. The attacker sends:
POST / HTTP/1.1
Host: target.com
Content-Length: 4
Transfer-Encoding: chunked
5c
GET /admin HTTP/1.1
Host: target.com
Content-Length: 15
x=1
0
The frontend processes the chunked encoding and forwards the entire body. The backend reads only 4 bytes (per Content-Length), and the remainder is treated as the start of a new request.
TE.TE Smuggling
Both servers support Transfer-Encoding, but they can be made to disagree by obfuscating the header:
Transfer-Encoding: chunked
Transfer-Encoding : chunked
Transfer-Encoding: xchunked
Transfer-Encoding: chunked
Transfer-Encoding: x
Transfer-Encoding:[tab]chunked
One server recognizes the obfuscated header as valid Transfer-Encoding, the other does not and falls back to Content-Length. The result is the same desync.
Impact of Request Smuggling
Request smuggling is a gateway to other attacks:
Bypassing security controls. Frontend WAF rules, IP allowlists, and authentication checks are bypassed because the smuggled request never passes through the frontend as an independent request.
Cache poisoning. Smuggle a request that causes the cache to store a malicious response. The cache key matches the legitimate request that followed, so all users requesting that resource receive the poisoned response.
Session hijacking. The smuggled request captures the next user's request headers (including cookies and authorization tokens) by making them part of a parameter in the smuggled request.
Credential theft. Smuggle a request to a reflected XSS endpoint, causing the next user's browser to execute the attacker's JavaScript.
Request routing manipulation. In microservice architectures, smuggle a request to an internal service that is not directly accessible.
Detection Techniques
Detecting request smuggling requires careful observation:
Timing-based detection. Send a request designed to cause a timeout if smuggling is possible. If the frontend uses CL and the backend uses TE, send a request with a Content-Length that includes a partial chunk. If the backend processes chunked encoding, it will wait for the chunk to complete, causing a timeout.
Differential response detection. Send two requests through the same connection. The first contains a smuggled prefix, the second is a normal request. If smuggling works, the second request is interpreted differently by the backend.
Automated tools:
- Burp Suite has built-in HTTP request smuggling detection (the HTTP Request Smuggler extension)
- smuggler.py is a dedicated open-source tool
- h2csmuggler detects HTTP/2 cleartext smuggling
HTTP/2 Smuggling
HTTP/2 introduces new smuggling vectors:
H2.CL smuggling. The frontend processes HTTP/2 (which uses framing, not Content-Length) and downgrades to HTTP/1.1 for the backend. If the frontend inserts a Content-Length header based on the HTTP/2 frame, and the backend processes Transfer-Encoding from the original request, desync occurs.
H2.TE smuggling. Similar to H2.CL, but the desync is between HTTP/2 framing and Transfer-Encoding processing.
H2C smuggling. HTTP/2 cleartext (h2c) upgrades over HTTP/1.1 connections can bypass reverse proxy restrictions. The proxy does not understand the h2c upgrade and forwards the raw bytes, allowing the attacker to speak HTTP/2 directly to the backend.
H2 request tunneling. HTTP/2's CONNECT method can be used to tunnel arbitrary data to internal services if the frontend supports it but does not properly validate the target.
Prevention Strategies
Normalize request processing. Ensure the frontend and backend agree on how to interpret every request. Use the same HTTP parser or enforce strict parsing rules at the frontend.
Reject ambiguous requests. If both Content-Length and Transfer-Encoding are present, reject the request with a 400 error. Do not try to be lenient.
Use HTTP/2 end-to-end. HTTP/2 uses binary framing that eliminates the Content-Length vs Transfer-Encoding ambiguity. Smuggling only occurs when downgrading to HTTP/1.1 for the backend.
Disable connection reuse. If the frontend opens a new backend connection for each request, smuggled requests cannot affect other users. This has a performance cost but eliminates the attack.
WAF rules. While WAFs cannot prevent all smuggling, they can detect obvious indicators: requests with both Content-Length and Transfer-Encoding, malformed Transfer-Encoding headers, and requests with Content-Length mismatches.
Keep software updated. Proxy servers and web servers regularly patch smuggling vulnerabilities. Nginx, HAProxy, Apache, and CDN providers have all issued fixes for smuggling issues.
Monitor for anomalies. Track request sizes, response codes, and timing patterns. Smuggling attempts often produce unusual patterns: 400 errors from the backend, unexpected timeouts, or responses that do not match the request.
Testing Checklist
For each frontend/backend pair in your architecture:
- Test CL.TE with Content-Length larger than the chunked body
- Test TE.CL with Content-Length smaller than the actual body
- Test TE.TE with obfuscated Transfer-Encoding headers
- Test HTTP/2 downgrade scenarios if applicable
- Verify that ambiguous requests are rejected, not silently handled
- Check that the frontend and backend agree on request boundaries with various edge cases
How Safeguard.sh Helps
Safeguard.sh tracks the web servers, reverse proxies, and HTTP libraries in your infrastructure for known request smuggling CVEs. These components are the direct cause of smuggling vulnerabilities, and patches are released regularly. By maintaining a complete SBOM that includes your infrastructure components, Safeguard.sh ensures that known smuggling vulnerabilities are flagged the moment a patch is available, reducing the window of exposure in your request processing pipeline.