HTTP Request Smuggling and Cache Attacks
CL.TE and TE.CL, HTTP/2 downgrades, desync races, cache poisoning and deception, plus parameter pollution read four different ways by four parsers.
Six notes on what happens between the client and the origin, where a request can be split, a connection reused and a response stored for somebody else.
HTTP Request Smuggling
Two servers parsing the same request differently can turn a normal connection into a desynchronized message queue. Request smuggling appears when front-end and back-end disagree about where a request ends. Content-Length and Transfer-Encoding are the classic sources. CL.TE means the front-end uses Content-Length while the back-end uses Transfer-Encoding. TE.CL reverses that relationship. I confirm proxy architecture, use timing probes and only then send a payload that affects the next request inside an isolated lab. Modern HTTP/1.1 intermediaries normalize more traffic. WAFs and CDNs may also rewrite headers, so behavior needs measurement across the real path.
1
2
3
4
5
6
7
8
POST / HTTP/1.1
Host: lab.example
Content-Length: 13
Transfer-Encoding: chunked
0
SMUGGLED
HTTP/2 Request Smuggling
HTTP/2 removes several HTTP/1 ambiguities, but the problem returns when a front-end translates requests to an HTTP/1 back-end. HTTP/2 carries length in framing and removes many old ambiguities. Downgrade proxies still need to reconstruct a valid HTTP/1 request for the backend. H2.CL and H2.TE appear when HTTP/2 headers or framing are converted so the backend interprets extra bytes as another request. I check whether the edge accepts HTTP/2, whether the backend uses HTTP/1 and use tooling that preserves real HTTP/2 framing rather than text emulation. Many interfaces hide pseudo-headers and normalization. Correct testing needs control over :method, :path, :authority and the front-end translation.
Use Burp Repeater with HTTP/2 enabled and inspect the downgraded behavior. A hand-written HTTP/1 text request will not reproduce an H2-only probe.
HTTP Desync
Request smuggling becomes clearer when you view the persistent connection as a shared queue between two parsers. HTTP desync describes a state where front-end and back-end lose agreement about request boundaries. The effect may poison the next request, influence cache entries, mix credentials or reach endpoints with inherited headers. I start with controlled desync probes and confirm connection reuse before attempting any cross-request effect. Load balancing, connection pools and retries make reproduction probabilistic. A finding needs stable evidence rather than a random 400 response.
Baseline first: send repeated harmless requests on one connection and compare timing and backend behavior before introducing a desync probe.
Web Cache Poisoning
Cache poisoning begins when the cache decides two requests are equivalent while the application does not. Cache keys often use host, path and query. Unkeyed headers may change the response without producing a separate cache entry. X-Forwarded-Host, X-Original-URL, cookies and cache-ignored parameters may influence redirects, scripts and content. I identify cache hits, age, vary behavior and reproducibility with a cache buster before attempting any persistent payload. The same input may be unkeyed at one CDN and keyed at another. Vary behavior and normalization differ by layer.
1
2
3
GET /?cb=123 HTTP/1.1
Host: app.example
X-Forwarded-Host: poison.example
Web Cache Deception
A private page can become a public cache object when the CDN and application disagree about what a path represents. Cache deception abuses caching rules based on extensions, directories or normalization while the origin still treats the path as authenticated dynamic content. Paths such as /account/profile.css may look static to the cache and equivalent to /account/profile to the application, depending on routing behavior. I test path confusion with a lab account, inspect caching headers and confirm later access without the authenticated session. Private caching depends on Vary, Cache-Control, key composition and edge rules. One reproducible anonymous hit is stronger than assuming vulnerability from a suffix.
1
2
3
GET /account/profile.css HTTP/1.1
Host: app.example
Cookie: session=lab-user
HTTP Parameter Pollution
role=user&role=admin looks ambiguous because it is. Frameworks, proxies and backends may choose first, last, arrays or concatenation. HTTP does not define one universal semantic for duplicate query parameters. Implementations choose their own behavior. HPP may bypass validation when a WAF reads the first value and the application uses the last or break signatures when canonicalization differs. I compare duplicates in query strings, forms and JSON-like parsers and observe which value reaches a lab endpoint. The bug requires a parser differential with security impact. Accepting duplicate parameters without impact is only behavior.
1
2
GET /api/user?role=user&role=admin HTTP/1.1
Host: app.example.test