← CodeClarityLab Home
Browse by Category
+ added · updated 7d
← Back to glossary

Cache Poisoning

security CWE-346 OWASP A4:2021 CVSS 8.1 PHP 5.0+ Advanced

Also Known As

web cache poisoning CDN poisoning

TL;DR

An attacker manipulates a cached response so that subsequent users receive malicious content served from the cache.

Explanation

Web cache poisoning abuses the gap between what a caching layer uses as a cache key (typically URL + Host) and what the backend actually processes (including unkeyed headers like X-Forwarded-Host). By injecting a malicious value into an unkeyed header that the application reflects in its response, an attacker can poison the cached copy served to all subsequent visitors. Mitigations include keying caches on all relevant headers, disabling reflection of arbitrary headers, and using Vary headers appropriately.

How It's Exploited

GET /page HTTP/1.1
Host: evil.com
# If Host is reflected in cached response, every subsequent visitor gets evil.com links

Common Misconception

Cache poisoning only affects public CDN caches. Server-side application caches and reverse proxies can also be poisoned if unkeyed headers influence the cached response.

Why It Matters

A poisoned cache entry serves malicious content to every user who hits that cache key — a single request from an attacker can affect thousands of victims.

Common Mistakes

  • Reflecting unkeyed request headers (like X-Forwarded-Host or X-Original-URL) into cached responses.
  • Including user-controlled query parameters in responses that are served from cache to other users.
  • Not separating cached static resources from dynamic personalised responses.
  • Trusting the Host header for generating absolute URLs in cached pages.

Code Examples

✗ Vulnerable
// Caching a response that includes unvalidated Host header
\$cacheKey = 'page:' . \$_SERVER['HTTP_HOST'] . \$_SERVER['REQUEST_URI'];
\$cached   = \$cache->get(\$cacheKey);
if (!\$cached) {
    \$html = render(['canonical' => 'https://' . \$_SERVER['HTTP_HOST'] . '/page']);
    \$cache->set(\$cacheKey, \$html);
}
✓ Fixed
// Use a fixed canonical hostname — never trust the Host header for cache keys
\$canonicalHost = config('app.url'); // 'https://yourapp.com'
\$cacheKey      = 'page:' . md5(\$canonicalHost . \$_SERVER['REQUEST_URI']);

// In nginx — only forward known Host values to PHP:
// if (\$host !~* ^(yourapp\.com|www\.yourapp\.com)\$) { return 444; }

Added 15 Mar 2026
Edited 22 Mar 2026
Views 29
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
1 ping W 0 pings T 0 pings F 1 ping S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 2 pings W 1 ping T 0 pings F 2 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 3 pings S 1 ping S 0 pings M 0 pings T 1 ping W 0 pings T
No pings yet today
Ahrefs 8 Perplexity 7 Amazonbot 6 Unknown AI 2
crawler 23
DEV INTEL Tools & Severity
🟠 High ⚙ Fix effort: Medium
⚡ Quick Fix
Never cache responses based on unvalidated request headers; vary cache keys on only the headers you explicitly support; set Cache-Control: no-store on sensitive pages
📦 Applies To
PHP 5.0+ web api
🔗 Prerequisites
🔍 Detection Hints
Response content influenced by X-Forwarded-Host or arbitrary headers that are also cached; user-specific content in shared cache
Auto-detectable: ✗ No burpsuite semgrep owasp-zap
⚠ Related Problems
🤖 AI Agent
Confidence: Medium False Positives: Medium ✗ Manual fix Fix: High Context: File Tests: Update
CWE-345 CWE-494

✓ schema.org compliant