Web cache poisoning + cache deception hunting - unkeyed input poisoning, cache-key analysis, path-confusion deception, header/parameter cloaking. Wiki-first, FIND schema output.
npx skills add https://github.com/Encod3d-Sec/TORCH --skill hunt-cache
Assumes hunt-core for the scope gate, two-account rule, confirmation gate, enumeration limits, stop conditions, wiki protocol, FIND output, and Deadends. Do not re-derive any of that here.
qmd_query "web cache poisoning deception unkeyed input cache-key path confusion" via wiki-search MCP
Hub: [[web-moc]] (live web index). Primary page: [[web-cache-poisoning]]. Payload arsenal: wiki/payloads/web-cache.md.
Anchors: [[web-cache-deception]], [[web-cache-attacks]]. Related: [[http-host-header-attacks]], [[http-request-smuggling]].
Needs a cache in front (CDN / Varnish / Cloudflare / Akamai / Fastly, or an app-layer cache). Signals: Age, X-Cache: hit/miss, Cache-Control, CF-Cache-Status headers; static-ish responses; responses that reflect a header or param.
Rank before testing:
X-Forwarded-Host, X-Forwarded-Scheme, X-Host, X-Forwarded-For, plus custom headers a page reflects into links/scripts. Highest hit-rate poisoning vector; discover unkeyed inputs with Param Miner./account/profile.css, /account/profile/nonexistent.js, path-parameter ;, encoded %2f, fat GET) that desync what the cache keys on from what the origin serves. Primary deception vector.Drive load-bearing requests through Burp Repeater for operator visibility; use Param Miner to enumerate unkeyed headers/params. curl is fine for the quick keyed-vs-unkeyed loop.
X-Cache/Age across requests; determine what is keyed (usually method + host + path + some query) vs unkeyed (most headers, some params). Always attach a unique cache-buster while probing so you never touch a shared key.X-Forwarded-Host, X-Forwarded-Scheme, X-Host, X-Forwarded-For, custom headers (Param Miner to discover)./account/profile.css, /account/profile/nonexistent.js, path-parameter ;, encoded %2f.python3 scripts/wiki-stage.py --kind technique --slug <slug> --target-page techniques/web/web-cache-poisoning.md (deception-path findings: --target-page techniques/web/web-cache-deception.md).An unkeyed input reflected into HTML/JS turns poisoning into stored XSS served to every client hitting that key - escalate the payload with hunt-xss. A reflected X-Forwarded-Host in a redirect or absolute link gives open redirect / resource swap to all users. Both raise impact from self-only to mass; prove reach on a benign key, then stop (see stop condition).
When the input looks keyed or filtered: try header-name variants (X-Forwarded-Host vs X-Host vs Forwarded), duplicate/pollute the param so the cache keys one occurrence and the origin reads another, exploit cache-key normalization (case, trailing slash, %2f), and use a fat GET (body params on a GET) to smuggle the value past a keyed query string.
Web cache poisoning is a blind / OOB-capable class: the win is a response served to OTHER clients, which you cannot observe from your own session alone.
NOT confirmation: your own cached response reflected back to you alone; a single response that might be per-user; an Age / X-Cache: hit change with no cross-session retrieval; the payload echoed in your own request.
IS confirmation: a poisoned or deceived response served to a DIFFERENT session and reproduced in a clean session (fresh profile, no cached state, cache-buster off); or an OOB callback to your unique Burp Collaborator / interactsh subdomain from a resource you injected into the cached page - a Collaborator-pointed unkeyed header confirms the poisoning reaches the cache and is loaded by other clients.
When you plant a blind/OOB payload, append a row to targets/<eng>/oob.md: | <token> | <sink url+param> | cache | <date> | waiting | | (columns: token | sink | class | planted | status | source; token = your unique Burp Collaborator / interactsh label). The recon-capture hook auto-correlates incoming callbacks to flip the row to HIT and SessionStart surfaces HITs; a HIT row in targets/<eng>/oob.md is the gate to scaffold the FIND. Do NOT claim a blind cache poisoning without cross-session proof or a HIT row.
Per hunt-core, cache poisoning is a traffic-affecting primitive: poisoning the shared/production cache can serve malicious content to every real user who hits that key. Demonstrate on a benign, self-scoped cache key (a unique cache-buster or your own path) and STOP at proof. Do not mass-poison a shared key, and do not leave a live payload sitting in the production cache.
HIGH (stored XSS / redirect to all users, or PII disclosure via deception); CRITICAL if it yields mass account takeover; MEDIUM if self-only / weak impact.
Append: - [ ] web-cache <host> -- key includes host+all reflective params; deception suffixes not cached (Cache-Control: private)
Take encod3d-sec/hunt-cache from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.