Web Cache Deception
Also Known As
cache deception attack
WCD
TL;DR
Tricking a cache into storing sensitive authenticated responses by appending a static-file-like suffix to a private URL.
Explanation
Web Cache Deception (discovered 2017) exploits misconfigured caches that serve any URL ending in .css, .js, or .png from cache without authentication. An attacker tricks a victim into visiting https://bank.com/account.php/fake.css — the server returns the real /account.php response (authenticated content) but the cache stores it publicly under the /fake.css variant. The attacker then fetches the same URL without authentication and receives the cached sensitive page. Mitigations: configure caches to respect Cache-Control: no-store headers, never cache responses based on file extension alone, and ensure authenticated responses carry appropriate Vary and Cache-Control headers.
Common Misconception
✗ Web cache deception and web cache poisoning are the same attack. Poisoning makes the cache serve malicious content to other users. Deception tricks the cache into storing a victim's private response so the attacker can retrieve it.
Why It Matters
Web cache deception tricks a cache into storing a private, personalised response as a public resource — subsequent users receive the victim's cached private data.
Common Mistakes
- Cache keyed on URL path without considering that appended static-looking suffixes (/profile/style.css) are cached.
- Not setting Cache-Control: no-store on private authenticated responses.
- CDN or reverse proxy that caches based on file extension rather than response headers.
- Not testing cache behaviour of authenticated endpoints with appended paths.
Avoid When
- Do not cache responses based solely on file extension — attackers append .css or .js to URLs to trick caches.
- Never serve personalised content without explicit Cache-Control: private or no-store headers.
When To Use
- Set Cache-Control: no-store on all authenticated or personalised responses.
- Validate that CDN/reverse proxy cache rules are based on the full URL path including query strings, not just the file extension.
Code Examples
✗ Vulnerable
// Attack: GET /account/profile/nonexistent.css
// Server returns /account/profile (authenticated user data)
// CDN sees .css extension → caches as static asset
// Attacker fetches /account/profile/nonexistent.css → gets victim's profile
// Fix:
header('Cache-Control: no-store, private'); // On all authenticated responses
// Verify CDN respects Cache-Control headers and does not cache on extension
✓ Fixed
# Cache deception: attacker tricks CDN into caching a private page
# GET /account/settings/fake.css
# → PHP serves /account/settings (private) because it ignores .css
# → CDN caches it as a 'static asset'
# Prevention:
# 1. Set Cache-Control: no-store on all authenticated responses
header('Cache-Control: no-store, private');
# 2. nginx — only pass extensionless/php paths to PHP-FPM
location ~* \.(css|js|png|jpg|webp)\$ {
try_files \$uri =404; # serve only real static files
}
# 3. Vary: Cookie — CDN won't cache when session cookie present
header('Vary: Cookie');
Tags
🤝 Adopt this term
£79/year · your link shown here
Added
15 Mar 2026
Edited
31 Mar 2026
Views
21
🤖 AI Guestbook educational data only
|
|
Last 30 days
Agents 0
No pings yet today
No pings yesterday
Amazonbot 8
Ahrefs 2
Perplexity 2
ChatGPT 2
Google 1
How they use it
crawler 14
crawler_json 1
Related categories
⚡
DEV INTEL
Tools & Severity
🟠 High
⚙ Fix effort: Medium
⚡ Quick Fix
Ensure your CDN only caches responses with Cache-Control: public headers — authenticated or personalised pages must return Cache-Control: no-store; audit what your CDN actually caches
📦 Applies To
any
web
🔗 Prerequisites
🔍 Detection Hints
CDN caching authenticated pages; no Cache-Control headers on personalised content; PHP session content served from CDN cache
Auto-detectable:
✓ Yes
owasp-zap
burpsuite
cloudflare-analytics
⚠ Related Problems
🤖 AI Agent
Confidence: Medium
False Positives: Medium
✗ Manual fix
Fix: Medium
Context: File
Tests: Update
CWE-525
CWE-345