Request Smuggling

Sections Request Smuggling

Front-end and back-end servers disagree on where one request ends and the next begins. Hijack other users’ requests, bypass auth, poison caches.

T=https://target.com

i. Where it lives

Anywhere there’s a chain of HTTP proxies / load balancers / CDNs in front of the app:

  • CloudFront / Akamai / Cloudflare / Fastly in front of origin
  • nginx / HAProxy / AWS ALB → application server
  • Reverse proxy with web cache (Varnish)
  • WAF appliances doing buffering before forward
  • API gateway → microservice

The vuln is in the disagreement between two HTTP parsers. Different software products handle edge cases differently in:

  • Content-Length (CL) vs Transfer-Encoding: chunked (TE) when both present
  • Obfuscated Transfer-Encoding headers (extra whitespace, line folding, quoted values)
  • HTTP/2 downgrade to HTTP/1.1 between front-end and back-end
  • Newlines and header parsing edge cases

ii. The smuggling variants

TypeFront-end usesBack-end usesNotes
CL.TEContent-LengthTransfer-EncodingFront sends full body, back sees chunked stop early
TE.CLTransfer-EncodingContent-LengthFront uses chunks, back uses CL
TE.TEBoth (one obfuscated)Both (other one ignored)Header obfuscation drives the desync
H2.CLHTTP/2Content-Length on downgradeHTTP/2 lengths vs HTTP/1.1 CL after downgrade
H2.TEHTTP/2Transfer-EncodingSame idea with TE
0.CLHTTP/2 with 0-byte bodyCL claims contentNewer technique, James Kettle’s 2024 research
CL.0Content-LengthNo body expectedBack-end ignores CL, treats remainder as new request

Modern HTTP/2 smuggling is the active research area in 2024-2026. Older HTTP/1.1 CL.TE / TE.CL is mostly patched on managed CDNs but still found in self-hosted reverse proxy setups.

iii. Tools

smuggler.py (defniffer / Defiant)

The most reliable HTTP/1.1 smuggling scanner:

git clone https://github.com/defparam/smuggler
python3 smuggler.py -u "$T"
## Adjust technique:
python3 smuggler.py -u "$T" --no-color -t 5 -m TLS
## From a list:
python3 smuggler.py -u "$T" -l urls.txt

Output flags [CRITICAL] for confirmed smuggling. Read the saved request file in payloads/ to verify manually.

HTTP Request Smuggler (Burp extension)

The Burp Pro / Community extension by Albinowax. Best for interactive testing:

  • Install via Burp BApp Store
  • Right-click a request → Smuggle Probe
  • For HTTP/2: Smuggle Probe → “Try HTTP/2 smuggling”

The extension does the parsing-quirk fuzzing automatically.

h2csmuggler

For HTTP/2 cleartext upgrade smuggling specifically:

python3 h2csmuggler.py -x http://proxy.example.com:80 http://internal.example.com/

nuclei templates

nuclei -u "$T" -tags smuggling

Useful for quick first-pass against many hosts.

iv. Detection (manual probes)

The classic CL.TE / TE.CL detection probes - send these manually via netcat (Burp Repeater bypasses some of the timing tricks needed):

CL.TE probe - back-end uses TE, so after the chunked terminator 0\r\n\r\n, anything extra hangs waiting for the next request:

POST / HTTP/1.1
Host: target.com
Content-Length: 6
Transfer-Encoding: chunked

0

X

If the connection times out waiting for X → CL.TE confirmed.

TE.CL probe - front-end uses TE, back-end uses CL. Back-end reads CL bytes:

POST / HTTP/1.1
Host: target.com
Content-Length: 6
Transfer-Encoding: chunked

0


X

If response is immediate → TE.CL confirmed.

Use Burp Repeater with HTTP/1

Most clients normalize HTTP. Burp Repeater has an “Update Content-Length” toggle - disable it. Connection: close usually needed too.

v. TE header obfuscation tricks

When both front and back parse Transfer-Encoding but one accepts an obfuscated version, you get TE.TE. Common obfuscations:

Transfer-Encoding: xchunked
Transfer-Encoding : chunked       ## space before colon
Transfer-Encoding: chunked
Transfer-Encoding:[tab]chunked
[space]Transfer-Encoding: chunked  ## leading space
X: X[\n]Transfer-Encoding: chunked ## line folding
Transfer-Encoding
 : chunked                          ## obs-fold
Transfer-encoding: chunked          ## case variations
TRANSFER-ENCODING: chunked
Transfer-Encoding: chunked, identity
Transfer-Encoding: chunked
Content-Length: 4                   ## conflict

Smuggler.py and the Burp extension fuzz these automatically.

vi. HTTP/2 smuggling

HTTP/2 doesn’t have textual headers - request bodies are framed. When a HTTP/2 front-end terminates and re-emits HTTP/1.1 to the back-end, the conversion process can introduce desyncs.

HTTP/2 → HTTP/1.1 downgrade scenarios:

  • HTTP/2 request with transfer-encoding: chunked (forbidden in HTTP/2) - front strips, back-end sees re-emitted HTTP/1.1 with the smuggled chunked encoding
  • HTTP/2 request with explicit content-length mismatching the actual frame length

The smuggler bypass: send HTTP/2 with content-length: 0 but include a body in the data frame. Front-end uses CL=0, back-end uses the data → CL.0 smuggling.

Use Burp’s HTTP Request Smuggler extension with HTTP/2 selected. Manual HTTP/2 smuggling needs a low-level client like nghttp2 or burp-stager.

vii. What to do with smuggling

Bypass front-end controls

Smuggle a request that the front-end never sees, hitting back-end endpoints normally blocked at the edge:

## Smuggled request goes to /admin which front-end blocks

Capture other users’ requests

Append a request prefix that captures the next victim’s headers:

## After your smuggled prefix, the next request to that backend
## connection has its first bytes appended to your "request body"
## You read those bytes via a reflective endpoint

Classic capture chain via search endpoint:

POST /search HTTP/1.1
...
search_query=...   ← victim's request gets appended here

When the search endpoint stores or reflects the query, you read the victim’s Cookies and Authorization headers.

Cache poisoning amplification

Combine smuggling with WEB11 Web Cache Poisoning to poison a public asset with attacker-controlled content. Every visitor downstream of the cache receives the malicious content.

Smuggled SSRF

Smuggle a request to an internal-only endpoint not exposed externally. Common targets: admin panels, internal APIs.

Web cache deception via smuggling

Make the cache store sensitive content (like /api/me) under an attacker-friendly URL.

viii. Tricks worth knowing

Connection: keep-alive

HTTP smuggling depends on connection reuse. Force Connection: keep-alive on your probe. Most servers default to keep-alive on HTTP/1.1 - but some normalize away.

CDN behavior fingerprint

Hit /__cf_origin/ (Cloudflare) and similar paths. Front-end responds with diagnostic info revealing the CDN. Knowing the CDN narrows expected smuggling variants:

  • Cloudflare → fairly robust, HTTP/2 downgrade attacks more interesting
  • Akamai → historically vulnerable to TE.CL
  • Fastly → varies by config
  • AWS ALB → HTTP/2 downgrade history

Smuggle then poll

After a smuggle attempt, hit the target rapidly with multiple distinct requests. If the back-end is desynced, you’ll see weird responses (404 instead of 200, response from a different endpoint) - confirms desync.

Differential timing

A successful smuggling primer leaves the back-end waiting. Subsequent requests have unusual response times. Watch latency curves while probing.

ix. James Kettle’s research progression

Smuggling research is dense. Order to read:

  1. HTTP Desync Attacks: Request Smuggling Reborn - 2019 original
  2. HTTP/2: The Sequel is Always Worse - 2021 HTTP/2 attacks
  3. Smashing the state machine - state-based attacks
  4. HTTP/1.1 must die - 2024 CL.0 / 0.CL

The 2024 paper introduced “0-byte content length” desyncs which are the hot new variant. PortSwigger labs include practice for each.

x. References

xi. Where it leads

  • Session theft → account takeover, see WEB02 Auth & Session
  • Auth bypass to internal admin paths → privilege escalation
  • Cache poisoning → persistent XSS-like attacks for all visitors, see WEB11 Web Cache Poisoning
  • SSRF amplification → internal endpoints exposed
  • Header rewriting → trust manipulation (smuggled X-Forwarded-For: 127.0.0.1 etc)

Smuggling is high-impact when it works, but rare and hard to confirm. Expect plenty of false positives. Always validate by chaining to a real impact (session capture, cache poisoning).