Vulnerability

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.

Severity

High

CWE ID

CWE-524

OWASP Top 10

A05:2021 - Security Misconfiguration

CVSS 3.1 Score

7.4

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

1

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.

2

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.

3

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.

4

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

Compliance impact

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.