Web Cache Poisoning
Web cache poisoning tricks a caching layer into storing a malicious response and serving it to all subsequent users, turning a single attacker's request into a persistent attack affecting every visitor.
What Is Web Cache Poisoning?
Web cache poisoning exploits the difference between headers that affect the response but are not included in the cache key. If a CDN or reverse proxy caches a response that was influenced by an attacker-controlled header, every subsequent user who requests the same URL receives the poisoned response.
The attack turns a single malicious request into a persistent, self-spreading attack served to all visitors.
How It Works
Caches store responses indexed by a cache key — typically the URL and Host header. Many other headers (X-Forwarded-Host, X-Forwarded-Scheme, X-Original-URL) influence the response but are not part of the cache key — these are "unkeyed inputs".
XSS via Cache Poisoning
If the application reflects X-Forwarded-Host into the response body:
GET / HTTP/1.1
Host: target.com
X-Forwarded-Host: evil.com"><script>alert(1)</script>Response (gets cached):
<script src="https://evil.com"><script>alert(1)</script>/cdn/app.js"></script>Now every user who visits / receives the XSS payload from the cache — without the attacker's header.
Open Redirect via Cache Poisoning
GET /login HTTP/1.1
Host: target.com
X-Forwarded-Host: attacker.comIf the app generates absolute redirect URLs from the host header:
HTTP/1.1 302 Found
Location: https://attacker.com/dashboardThis redirect gets cached — every user hitting /login is redirected to the attacker's site.
Real-World Impact
- Stored XSS at scale — one request infects all visitors for the cache TTL duration
- Credential theft — redirect all users to a phishing login page
- Denial of Service — cache an error page for popular URLs
- Session fixation — inject
Set-Cookieheaders into cached responses
How to Fix
Normalize or remove unkeyed headers at the edge:
# Strip headers that shouldn't influence cached responses
proxy_set_header X-Forwarded-Host "";
proxy_set_header X-Original-URL "";Never reflect request headers directly into response:
# Wrong
host = request.headers.get("X-Forwarded-Host", request.host)
redirect_url = f"https://{host}/dashboard"
# Right — use configured base URL
redirect_url = f"{settings.BASE_URL}/dashboard"Configure your CDN to include unkeyed inputs in the cache key if they must influence responses:
# Cloudflare Cache Rules — vary cache by header
Cache-Tag: vary-x-forwarded-host
Set short cache TTLs for dynamic pages and use Vary headers correctly:
Vary: Accept-Encoding, Cookie
Cache-Control: no-storeWhat VibeWShield Detects
VibeWShield's Cache Poisoning scanner activates when caching headers are detected (Age, CF-Cache-Status, X-Cache, X-Varnish). It:
- Injects a unique UUID-based canary domain into
X-Forwarded-Host,X-Forwarded-Scheme,X-Original-URL,X-Rewrite-URL, andForwardedheaders - Issues a clean second request without the headers
- If the canary appears in the clean response, the cache is confirmed poisoned
Findings are flagged as High with the exact header, canary value, and cache status evidence.
Free security scan
Test your app for Web Cache Poisoning
VibeWShield automatically checks for Web Cache Poisoning and 40+ other vulnerabilities using 63 scanners — in under 3 minutes, no signup required.
Scan your app free