A proxy and backend server disagree about where one request ends. By sending conflicting Content-Length and Transfer-Encoding headers an attacker poisons the backend's read buffer — prepending an arbitrary prefix to the next user's request.
Modern stacks route HTTP through at least two hops: a frontend (CDN, load-balancer, reverse proxy) and a backend application server. Both must agree on exactly how many bytes each request contains. HTTP/1.1 allows two framing methods: Content-Length (a fixed byte count) and Transfer-Encoding: chunked (a streaming format). When the frontend and backend each pick a different framing rule for the same request, an attacker can craft a body that looks complete to one hop but leaves bytes in the other's buffer — bytes that get prepended to the next user's legitimate request.
| Bug Found | CL.TE — frontend uses Content-Length, backend uses Transfer-Encoding; smuggled prefix poisons next request |
| Bug Found | TE.TE — obfuscated second Transfer-Encoding header causes one server to fall back to Content-Length, recreating the desync |
| True Positive | Hardened endpoint rejects any request containing conflicting or duplicate framing headers with 400 Bad Request |
The frontend proxy reads Content-Length: 49 and forwards exactly 49 bytes.
The backend ignores Content-Length when Transfer-Encoding is present, processes the body as chunked,
and finds a chunk terminator before byte 49 — leaving the remainder as a dangling prefix for the next request.
Both servers honour Transfer-Encoding, but the attacker sends two TE headers.
The second uses an unrecognised token (xchunked).
Whichever server drops the invalid header falls back to Content-Length — recreating
a classic CL/TE desync without the two headers ever appearing obviously contradictory.
The safe endpoint inspects every incoming request before forwarding. Any request containing
both Content-Length
and Transfer-Encoding,
or multiple TE headers, is returned with 400 Bad Request
and the connection is closed — nothing is forwarded to the backend.
Test both CL.TE and TE.TE payloads against it.
GET /admin… prepended to the next user's request (bug found).Transfer-Encoding: xchunked causes the backend to discard both TE headers and fall back to Content-Length: 4. The 88 remaining bytes poison the next request with a forged transfer payload (bug found).