Web Cache Deception
detect, understand, remediate
Web cache deception tricks an intermediate cache (CDN, reverse proxy, or load balancer) into storing a private, authenticated response under a URL that looks static, so any subsequent visitor can retrieve another user's data by requesting the same path.
No credit card required. Free plan available forever.
What is web cache deception?
Web cache deception (CWE-524) is an attack where an adversary persuades an intermediate cache (such as a CDN, reverse proxy, or load balancer) to store a private, authenticated response under a URL the cache has been configured to treat as static. The attacker then sends the crafted URL to a victim, the victim's browser retrieves the page while authenticated, and the cache stores the personalised response. From that moment on, anyone requesting the same URL receives the victim's cached page, including session details, personal data, or anti-CSRF tokens.
The technique was first publicly described by Omer Gil in 2017, and large platforms have remediated variants of it ever since. It is distinct from web cache poisoning: cache poisoning injects attacker-controlled content into a cached response, while cache deception steals legitimate users' cached responses by abusing path handling rules. Both attacks live at the boundary between the application and the caching layer, and both are flagged as security misconfiguration findings in most pentest reports.
Modern stacks rely on CDNs and edge caches that key on the URL path and a small set of headers, often with default rules that automatically cache anything ending in static extensions like .css, .js, .png, or .jpg. When the origin application also tolerates extra path segments after a route (returning the same dynamic page for both /account and /account/foo.css), the conditions for web cache deception are in place.
How it works
Find a path-tolerant route
The attacker identifies an authenticated, personalised endpoint that still returns the same dynamic content when an arbitrary suffix is appended, for example /account vs /account/anything.css. Cookie-based auth must persist across the suffix.
Craft a static-looking URL
The attacker builds a URL on that route ending in an extension the cache treats as static (.css, .js, .png, .jpg, .pdf, .ico). The cache layer is more likely to cache the response and ignore Cache-Control headers from the origin.
Lure the victim to load it
The attacker sends the crafted URL to an authenticated victim through phishing, a forum post, or an embedded image tag. The victim's browser sends session cookies, the origin returns a personalised response, and the cache stores it under the static-looking key.
Retrieve the cached response
The attacker then requests the same URL without authentication. The cache serves the victim's personalised content, exposing session identifiers, profile data, anti-CSRF tokens, or anything else the original page rendered.
Common causes
Lenient routing on the origin
Frameworks that match a controller against the leading segments of a URL and ignore the rest, for example treating /account, /account/, /account/foo.css, and /account/anything as the same route. The origin happily renders the personalised page.
Extension-based caching at the edge
CDN or reverse proxy rules that automatically cache responses based purely on URL extension, without checking Cache-Control headers, the Vary header, or whether the response carries authentication cookies.
Mismatch between path normalisation layers
The cache and the origin disagree about path semantics: trailing slashes, encoded characters, repeated separators, or extension handling. Each layer thinks the URL means something different, and the cache stores what the origin generated.
Origin that ignores cache directives
Authenticated endpoints that fail to set Cache-Control: private, no-store on personalised responses. The CDN treats the response as cacheable by default unless the origin explicitly opts out.
Real-world impact
Account page exposure
Personal profile fields, email addresses, billing summaries, and partial card numbers cached under URLs like /account/style.css and served to any subsequent visitor.
Session and CSRF token leakage
Pages that embed anti-CSRF tokens, API keys, or session identifiers in HTML get cached, letting an attacker hijack the authenticated session by replaying the recovered token.
Internal admin views
Authenticated admin or staff pages cached under static-looking suffixes, giving an unauthenticated attacker visibility into internal customer data, ticket queues, or feature flag dashboards.
How to detect it
Automated detection
- SecPortal's external scanning module inspects cache-related response headers (Cache-Control, X-Cache, Age, CF-Cache-Status) on every discovered endpoint and flags personalised pages that lack private or no-store directives
- Probes append static-looking suffixes (
/foo.css,/foo.png) to authenticated paths and compare the resulting status, content length, and body fingerprint with the original route to detect path-tolerant routing - Repeat requests across regions and IP ranges look for X-Cache: HIT, Age, or vendor-specific cache hit indicators on responses that should never be shared between users
Manual testing
- While authenticated, request a personalised page with an appended static suffix (for example /account/test.css) and confirm the response body still contains the personalised content rather than a 404 or a real CSS file
- Repeat the same request from an unauthenticated browser, ideally from a different region. If the response contains the original user's data, the cache has stored a private response under a public key
- Inspect Cache-Control, Vary, Set-Cookie, and CDN-specific headers to understand who cached the response and on what cache key, so the report can recommend a precise fix
- Try alternate suffixes (
.js,.png,.pdf,.ico) and path tricks (encoded slashes, dot segments) since CDNs apply different rules per extension and per path normalisation policy
How to fix it
Tighten origin routing so unknown suffixes return 404
Configure the application router so that paths like /account/foo.css do not match the /account controller. Reject extra segments instead of returning the personalised page. This removes the precondition the attack relies on.
Set explicit Cache-Control on every authenticated response
Personalised responses must carry Cache-Control: private, no-store and either Vary: Cookie or, better, an authentication-aware cache key. Never rely on the CDN to infer that an authenticated page should not be cached.
Disable extension-based caching for dynamic paths
Replace blanket "cache anything ending in .css/.js/.png" rules with explicit allow-lists scoped to known static asset directories such as /static, /assets, or /_next/static. Dynamic routes should never inherit static caching.
Normalise paths before they reach the cache key
Use a single path normalisation policy across the CDN, the reverse proxy, and the origin so that /account, /account/, and /account//foo all map to the same canonical URL. Where this is not possible, strip ambiguous suffixes at the edge.
Strip session cookies on responses that may be cached
For genuinely shared assets, ensure the origin removes Set-Cookie and any per-user state before the response leaves the application. A static asset that carries a Set-Cookie is a cache deception flag in itself.
Rotate any tokens that may have been cached
When this finding is confirmed in production, rotate session identifiers, anti-CSRF tokens, and API keys that could have been embedded in cached responses. Treat the issue as a confidentiality incident, not just a misconfiguration.
Related SecPortal guidance
Security headers checker
Audit Cache-Control, Vary, and other directives on any URL with the free header grader.
External assessment workflow
See how cache findings flow from scan to client report inside SecPortal.
Pentest report delivery
Turn cache deception evidence into a defensible writeup with severity, screenshots, and retest tracking.
Compliance impact
Related vulnerabilities
Detect web cache deception in your stack
SecPortal's external scanner inspects cache headers, path normalisation, and CDN behaviour to surface cache deception risk on every engagement. Start free.
No credit card required. Free plan available forever.