Web Cache Deception (WCD)
Different from cache poisoning, WCD tricks a cache into storing a private, dynamic response (containing sensitive data like API keys, CSRF tokens, or session info) under a URL that looks static — so an attacker can later request that same cached URL and retrieve the victim’s private data.
Basic attack flow:
- Craft a URL that the application treats as a dynamic, authenticated endpoint (e.g.,
/my-account), but that the cache treats as static. - Trick a victim (logged in) into visiting that crafted URL.
- Request the same URL yourself — if cached, you get the victim’s response.
Key discrepancy classes (the heart of the course)
1. Static extension cache rules
Caches often cache anything ending in .js, .css, .jpg, etc. If you can append a fake extension to a dynamic path and the backend still routes it to the dynamic handler (ignoring/stripping the suffix), e.g. /my-account/foo.js, the cache stores it as static while the app serves real account data.
2. Path mapping discrepancies
Cache and origin server parse the URL path differently. E.g., /my-account/wcd.js might be treated by the origin as /my-account (extra segment ignored) but cached under the full path with .js.
3. Delimiter discrepancies
Characters like ;, #, ?, %23, etc. are interpreted differently by cache vs. origin. E.g., /my-account%23.js — the cache may truncate or ignore the fragment while the origin resolves the full dynamic path.
4. Delimiter decoding discrepancies
Similar idea but involves differences in when URL-decoding happens — one layer decodes before routing, the other after, letting you smuggle a static-looking suffix past the cache while the backend still hits the dynamic route.
Get Lucky Singh Rawat’s stories in your inbox
Join Medium for free to get updates from this writer.
5. Static directory cache rules
Some caches blanket-cache everything under a directory like /static/ or /assets/ regardless of extension. If the origin has a routing quirk that maps /static/..%2fmy-account (path traversal-like tricks) back to a dynamic page, you get the same effect.
6. Normalization discrepancies
Cache and origin normalize paths differently — handling of .., double slashes, encoded slashes (%2f), trailing dots, case sensitivity, etc. These let you construct a URL that normalizes to the dynamic endpoint at the origin but is cached under a different, static-looking key.
7. File name cache rules
Caches keying purely on filename patterns (e.g., anything named wcd.js regardless of path) — combined with origin routing that ignores path prefixes, lets dynamic content get cached under a predictable filename.
Exploitation mechanics (tie-together)
- You need: (a) a way to make a URL look static to the cache, (b) confirmation the origin still serves the dynamic/authenticated response for that exact URL, and © a way to get a victim to visit it (stored XSS, phishing link, CSRF-like delivery,
<img>/redirect tricks, etc.) since the victim must authenticate the request that gets cached. - Always confirm caching behavior using response headers (
X-Cache: hit/miss,Age,Cache-Control) and by requesting twice — once to “poison,” once to “retrieve.” - Check cache key composition: does it include query string, headers (e.g.,
Host,Accept-Encoding), or just the path?
Preventing web cache deception vulnerabilities
You can take a range of steps to prevent web cache deception vulnerabilities:
- Always use Cache-Control headers to mark dynamic resources, set with the directives no-store and private.
- Configure your CDN settings so that your caching rules don’t override the Cache-Control header.
- Activate any protection that your CDN has against web cache deception attacks. Many CDNs enable you to set a cache rule that verifies that the response Content-Type matches the request’s URL file extension. For example, Cloudflare’s Cache Deception Armor.
- Verify that there aren’t any discrepancies between how the origin server and the cache interpret URL paths.






