What Is Web Cache Deception? A Practical Testing Guide
Web cache deception occurs when an origin treats a URL as a private dynamic page while a cache treats the same URL as a public static resource. If an authenticated victim visits the crafted URL, the cache may store their personalized response and serve it to another visitor.
This differs from web cache poisoning. Deception stores a victim's sensitive response under an attacker-chosen cache key; poisoning makes the cache store attacker-influenced content.
Understand both parsers
Testing starts with two questions:
- How does the origin map the path to an application route?
- How does the CDN decide whether the response is cacheable?
Differences may involve file extensions, path parameters, delimiters, normalization, encoded characters, or rewrite rules.
Establish a safe baseline
Use your own test account and choose a page containing a unique harmless canary. Request it normally and record Cache-Control, Age, X-Cache, CF-Cache-Status, Vary, and any CDN-specific headers.
Never ask another person to visit the test URL. Your own authenticated and unauthenticated sessions are enough to prove exposure.
Test path interpretation
Append a static-looking suffix to a private route, such as a controlled .css or .js segment. Try semicolon or encoded delimiters only where allowed. The key observation is whether the origin still returns the private page while the cache changes from bypass or dynamic to miss and then hit.
Make one authenticated request, then repeat without cookies from a clean client. A genuine issue requires the anonymous response to contain the canary from the authenticated response.
Verify the cache key
Change query parameters, host, scheme, headers, and path encoding carefully to learn what separates cache entries. Check whether cookies or authorization headers are ignored. Do not assume an Age header alone proves sensitive caching; compare a unique response marker.
Common false positives
- A browser cache, rather than a shared CDN cache.
- A static login shell with no private data.
- A cache hit generated only for the same authenticated cookie.
- A response containing public profile information.
- Framework fallback pages that look personalized but are rendered client-side.
Use two isolated clients and a unique marker to remove ambiguity.
Impact and reporting
Explain the exact victim requirement, affected route, cache lifetime, data exposed, and whether search engines or crawlers could trigger or discover the URL. Include a short sequence of requests with timestamps and sanitized response snippets.
Do not repeatedly cache sensitive pages. Purge your test object when the program offers a cache purge mechanism, and notify the owner if test data remains reachable.
Recommended fixes
- Mark authenticated and personalized responses
private, no-store. - Make CDN cache rules allowlist known public routes instead of file extensions alone.
- Ensure the CDN and origin normalize paths identically.
- Reject ambiguous delimiters and unexpected path suffixes.
- Include authentication state in the cache key only when private caching is intentionally designed.
- Test cache behavior at the edge, not only in origin unit tests.
Cache behavior is a security boundary. A private origin response must never become public because another component parsed the URL differently.
Original Bugflare guide informed by PortSwigger's web cache deception research and testing methodology.