Skip to content

HTTP Request Smuggling

When a request passes through a front-end (proxy, CDN, load balancer) before reaching the back-end, both must agree on where one request ends and the next begins. If they disagree on how to interpret the body length, the attacker “smuggles” part of their request into the start of the next user’s request. That’s request smuggling: poisoning the shared request queue.

flowchart LR
    A[Attacker] -->|"ambiguous request (CL.TE / TE.CL)"| F[Front-end]
    F -->|"sees it as one"| B[Back-end]
    B -. "back-end splits it in two (desync)" .-> V["Prefix injected into the<br/>next victim's request"]

The bug isn’t in one machine, it’s in the disagreement between two. The front forwards over a keep-alive connection to the back, and if one counts the body by Content-Length and the other by Transfer-Encoding: chunked, a carefully malformed request is split differently on each side. The leftover part of the request is prepended to the victim’s request on that same connection.

By which header each end prioritizes:

  • CL.TE: the front uses Content-Length, the back uses Transfer-Encoding.
  • TE.CL: the front uses Transfer-Encoding, the back uses Content-Length.
  • TE.TE: both support Transfer-Encoding but one can be obfuscated into ignoring it (Transfer-Encoding: xchunked, spaces, duplicate header).
POST / HTTP/1.1
Host: target
Content-Length: 6
Transfer-Encoding: chunked
0
G

If the back prioritizes chunked, it sees the request ending at 0\r\n\r\n and the G stays at the start of the buffer → prepended to the next request (GPOST ...).

  • Timing detection: a malformed CL.TE/TE.CL request makes the back wait for bytes that never arrive → measurable delay. Burp’s technique.
  • Try Transfer-Encoding obfuscations: space before :, tab, \n as separator, double TE, oddly-cased value.
  • HTTP/2 → HTTP/1.1 downgrade: the front speaks H2 and translates to H1 to the back; inconsistent Content-Length/chunked or headers H2 allows and H1 doesn’t (H2.CL, H2.TE, CRLF in values).

Once the desync is confirmed:

  • Steal other users’ requests: smuggle a prefix that captures the next request (with its cookie) and reflects it to an endpoint you control.
  • Bypass front-end controls: the front filters /admin, but you smuggle a request to /admin the front doesn’t inspect.
  • Response queue poisoning: misalign requests and responses → a user gets another’s response.
  • Chained cache poisoning: smuggling + cache poisons responses for everyone.
  • Turn XSS/open redirect into something that hits victims with no interaction.
# conceptual CL.TE: prefix left queued for the victim
POST / HTTP/1.1
Host: target
Content-Length: 4
Transfer-Encoding: chunked
0
GET /admin HTTP/1.1
X-Ignore: X
  • Burp Suite — HTTP Request Smuggler extension (James Kettle): timing detection, desync probe, H2 downgrade.
  • Turbo Intruder — to send requests with fine framing control.
  • h2csmuggler — for desync via HTTP/2 cleartext upgrade.

Hijacking of other users’ sessions, bypass of front-end auth/authZ, mass cache poisoning, exfiltration of in-transit credentials.

  • Requests with both Content-Length and Transfer-Encoding.
  • Obfuscated Transfer-Encoding (spaces, non-standard values, duplicated).
  • Responses that don’t match the client’s request; users seeing others’ data.

Log raw framing headers; alert on simultaneous CL+TE and on malformed TE.

  • Use HTTP/2 end-to-end with no downgrade to HTTP/1.1 on the internal hop (eliminates the whole class when H2 is kept).
  • Normalize/reject at the front any request with CL+TE or ambiguous TE; a single interpretation across the whole chain.
  • Front and back with the same server/version and parsing config; disable back-end connection reuse if not safe.
  • Reject duplicate headers and values not conforming to RFC 7230.
  • Keep WAF/reverse-proxy updated (many smuggling fixes are config/version).

Invalidate cache, rotate affected sessions, patch/align front and back parsing, disable keep-alive to the back if needed.

  • James Kettle — “HTTP Desync Attacks” (2019) and “HTTP/2” (2021) — foundational research; hit major CDNs and thousands of sites.
  • CVE-2019-18277 (HAProxy), CVE-2021-33193 (Apache mod_http2) — smuggling in popular servers/proxies.
  • Netflix, PayPal and others — critical desync disclosed in James Kettle’s HTTP Request Smuggling research (PortSwigger).
  • Multiple advisories from Varnish, Squid, nginx, and load balancers over framing discrepancies.
  • Does the front forward to the back over keep-alive? (prerequisite)
  • Does timing detection (CL.TE / TE.CL) show desync?
  • Does obfuscating Transfer-Encoding change interpretation? (TE.TE)
  • Is there an HTTP/2→HTTP/1.1 downgrade with inconsistent CL/TE? (H2.CL/H2.TE)
  • Can a request be prepended to another user’s?
  • Are front-end controls (/admin) bypassed via smuggling?
  • Is CL+TE framing rejected or normalized at the front?