Web Cache Poisoning / Deception
Caches (CDN, reverse proxy, browser cache) store a response and serve it to many users for speed. The problem appears when the cache key (what identifies “the same response”) omits an input that actually affects the content. Then the attacker poisons a cached response served to everyone (poisoning), or tricks the cache into storing a victim’s private content and serving it to a third party (deception).
Threat model
Section titled “Threat model”Everything revolves around the cache key. The cache decides “this request equals that one” typically by method + host + path + query. If a header or parameter not in the key (“unkeyed input”) changes the response, the attacker sends a request with that input manipulated; the cache stores the poisoned response under the normal key; victims requesting that key receive the poison.
Web Cache Poisoning
Section titled “Web Cache Poisoning”Red Team — discovery
Section titled “Red Team — discovery”- Identify unkeyed inputs: headers like
X-Forwarded-Host,X-Forwarded-Scheme,X-Host,X-Forwarded-For,User-Agent, or query params that are reflected but not in the key. - Watch cache headers:
X-Cache: hit/miss,Age,Cache-Control,Vary. Ahitmeans it was served from cache. - Send the request with the suspicious header and a marker; repeat without it and see if the marker persists (got cached).
By hand
Section titled “By hand”# 1) the unkeyed header is reflected in the responseGET /?cb=123 HTTP/1.1Host: targetX-Forwarded-Host: evil.com-> response: <script src="//evil.com/a.js"> (reflected)
# 2) that response gets cached under the key /?cb=123# 3) the victim requests /?cb=123 -> receives the attacker's scriptCommon vectors:
- Cached XSS: an
X-Forwarded-Hostreflected in a<link>/<script>/<base>→ XSS for everyone. - Cached redirect:
X-Forwarded-Hostending up in aLocation→ mass open redirect. - Cache DoS (CPDoS): poison with an error response (a header that causes 400/404) cached under the home page.
- Cache key normalization: delimiters (
;,#, encoding) the cache and origin treat differently to slip content under a “clean” key.
Web Cache Deception
Section titled “Web Cache Deception”The reverse flow: you make the cache store a dynamic/private page because the URL looks static.
# the authenticated victim visits (because you send them the link):https://target/account/profile/nonexistent.css# the origin ignores the extension and returns the profile (with private data)# the cache sees ".css" -> caches "static content"# the attacker requests the same URL -> receives the victim's profileVariants: .css, .js, /static/, path confusion (/profile%2f..%2fprofile.css), delimiters the origin and cache parse differently.
- Burp Suite — Param Miner extension (discovers unkeyed headers/params).
- Burp Repeater to confirm hit/miss and persistence.
- Manual observation of
X-Cache,Age,Vary.
Impact
Section titled “Impact”XSS/redirect/DoS served to all users (poisoning); theft of authenticated victims’ private data (deception).
Blue Team
Section titled “Blue Team”Detection
Section titled “Detection”- Cached responses reflecting non-standard headers (
X-Forwarded-Host, etc.). - Spikes of
hiton URLs with odd queries or static extensions on dynamic paths. - Dynamic content appearing in the static cache.
Telemetry
Section titled “Telemetry”Log the effective cache key, incoming headers, and resulting X-Cache; alert on reflected unkeyed inputs.
Hardening
Section titled “Hardening”- Include in the cache key every input that affects the response, or don’t reflect unkeyed inputs.
- Use
Varycorrectly for headers that change the response. - Don’t cache session/user-dependent content; set
Cache-Control: private, no-storeon authenticated responses. - Define what is cached by real extension/path, not by URL suffix; normalize paths consistently across cache and origin.
- Disable support for
X-Forwarded-*headers you don’t use; don’t trust them to build URLs.
Response
Section titled “Response”Purge the affected cache, fix the key/normalization, review what private content may have been served.
CVEs and real-world cases
Section titled “CVEs and real-world cases”- James Kettle — “Practical Web Cache Poisoning” (2018) and “Web Cache Entanglement” (2020) — reference research; hit GitHub, Mozilla, large firms.
- Omer Gil — “Web Cache Deception” (2017) — discovered the technique; PayPal among the initial victims.
- CPDoS (2019) — academically documented cache-DoS class affecting popular CDNs.
- Numerous HackerOne reports of poisoning via
X-Forwarded-Host.
Testing checklist
Section titled “Testing checklist”- What goes into the cache key? (method, host, path, query)
- Are there reflected headers/params not in the key? (Param Miner)
- Can a response with the attacker’s
X-Forwarded-Hostbe cached? - Reflection into
<script>/<base>/Location→ cached XSS/redirect? - A cacheable error under a popular URL? (CPDoS)
- Does a dynamic URL with a
.css/.jsextension cache with private data? (deception) - Do authenticated responses carry
Cache-Control: private/no-store?