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

Cache Poisoning

Security CWE-346 OWASP A4:2021 CVSS 8.1 PHP 5.0+ Advanced
debt(d7/e7/b5/t7)
d7 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'only careful code review or runtime testing' (d7). The detection_hints indicate automated=no, and while tools like Burp Suite, Semgrep, and OWASP ZAP are listed, cache poisoning requires active probing and manual analysis to confirm — a Semgrep rule can flag reflected unkeyed headers but cannot confirm the cache behaviour. Silent in most CI pipelines, discovered only through dedicated security testing.

e7 Effort Remediation debt — work required to fix once spotted

Closest to 'cross-cutting refactor across the codebase' (e7). The quick_fix sounds simple (never cache responses based on unvalidated headers; set Cache-Control: no-store on sensitive pages), but the common_mistakes reveal that fixes span caching infrastructure config, application-level header handling, URL generation logic, and separation of static vs dynamic responses. Correctly remedying cache poisoning requires auditing every cached endpoint, updating CDN/reverse proxy keying rules, and refactoring URL-generation code — a cross-cutting change.

b5 Burden Structural debt — long-term weight of choosing wrong

Closest to 'persistent productivity tax' (b5). The applies_to covers web and api contexts broadly. Once cache poisoning risks are present, every feature that involves caching must be reviewed for unkeyed header reflection and response segmentation. It imposes an ongoing tax on caching design decisions across multiple work streams, but does not fully define the system's shape.

t7 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'serious trap (contradicts how a similar concept works elsewhere)' (t7). The misconception field explicitly states that developers believe cache poisoning only affects public CDN caches, when in reality server-side application caches and reverse proxies are equally vulnerable. Combined with common mistakes like trusting X-Forwarded-Host and Host headers in cached responses, competent developers who haven't encountered this specific attack surface will systematically guess wrong about what constitutes a safe caching boundary.

About DEBT scoring →

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 56
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings T 0 pings W 1 ping T 0 pings F 0 pings S 0 pings S 2 pings M 0 pings T 1 ping W 1 ping T 1 ping F 0 pings S 3 pings S 1 ping M 1 ping T 0 pings W 0 pings T 0 pings F 0 pings 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 3 pings M 0 pings T 0 pings W
No pings yet today
No pings yesterday
Ahrefs 10 Amazonbot 8 Perplexity 7 Scrapy 7 SEMrush 4 Unknown AI 2 Claude 2 PetalBot 2 ChatGPT 1 Meta AI 1 Google 1
crawler 43 crawler_json 2
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