Web cache poisoning — turn one request into stored XSS for every visitor.
The playbook:
1/ Find the cache. Look for Age, X-Cache, Cf-Cache-Status, Via headers. If Age increments across requests, it's caching.
2/ Find unkeyed inputs. Cache key is usually method URL. Headers like X-Forwarded-Host, X-Forwarded-Scheme, X-Host, X-Original-URL, Forwarded — usually NOT in the key but often reflected. Param Miner (Burp extension) brute-forces hundreds for you.
3/ Always cache-bust during testing. ?cb=randomstring on every probe. Do not poison real users while fingerprinting.
4/ Confirm reflection. Send X-Forwarded-Host:
attacker.com — does it appear in <link rel=canonical>, <script src>, og:url, or Location?
5/ Prove the cache stored it. Fire poisoned request → clean request from a different browser. If your payload comes back, you own that cache key. This step is non-negotiable.
6/ Pick the impact. Host header inside <script src=...> = stored XSS for every viewer while the TTL holds. Location reflection = mass open redirect. og:url poisoning = phishing via link previews. Internal headers echoed = SSRF/info leak.
Bonus targets: cache key normalization (case, trailing slash, ?fbclid, ?utm_), fat GET smuggling (oversized query strings), parameter cloaking (?p=safe&p=evil — frontend reads one, cache stores the other).
The trap most hunters fall into: they find reflection, declare victory, submit. Without proof the response was CACHED and served to a second viewer, it's just reflection — not cache poisoning. Triage closes it.
Report on impact. "Header reflects in canonical" = info. "Cached XSS payload served to N other browsers for 60s, here's the video" = critical.
What's the wildest cache key bug you've seen?