Cache key & Vary
Ce contenu n’est pas encore disponible dans votre langue.
Probes what actually varies the cache key, rather than trusting the declared Vary header alone.
How it works
Section titled “How it works”For each of Accept-Encoding, Accept-Language, User-Agent, and a custom header, the check sends a request that varies only that input and compares the response against a baseline (a different cdn-detected cache-status value, or a different response body counts as “keyed”).
Why User-Agent needs special handling
cache-detective’s own probe transport (harnessx/probe) deliberately overwrites the User-Agent header on every request for consistent identification. Varying User-Agent on purpose therefore bypasses that transport for just this one probe (checkbase.DoRaw instead of checkbase.Do) — every other probe in cache-detective goes through the standard transport.
Findings
Section titled “Findings”| Finding | Severity | Meaning |
|---|---|---|
Undeclared cache-key input: <dimension> | medium | Varying this input changed the response, but it’s not declared in Vary — a cache-poisoning surface if the value is attacker-controlled |
Declared Vary dimension has no observed effect: <dimension> | info | Declared in Vary, but varying it produced no observable difference — likely inflates cache fragmentation for no benefit |
Request budget
Section titled “Request budget”This check issues extra requests to the live target but is not gated behind --aggressive — it’s read-only from the target’s point of view (it never plants content a poisoned cache would later replay; that’s Cache poisoning & deception’s job). It still respects --max-aggressive-requests as a hard cap on probe count per resource.
Credentials in the cache key
Section titled “Credentials in the cache key”Varying Accept-Language or User-Agent shows whether the cache keys on them. Credentials can’t be probed that way: a cache that ignores Authorization or Cookie gives the same response for a different valid token, and for no token at all. So when the scan carries credentials (--bearer, --cookie, or an auth profile), the check repeats the request with Authorization and Cookie stripped. Other configured headers stay on, so a custom API-key header isn’t stripped and goes unreported rather than misreported.
If that credential-less request comes back identical to the authenticated one, either the content is public or a cache replayed it. A second credential-less request, against a cache-buster-isolated URL no cache entry can answer, tells them apart:
| Observation | Finding | Severity |
|---|---|---|
| The isolated request is refused or differs | Authenticated response served to unauthenticated request — the origin withholds the content and a cache replayed it anyway | critical |
The isolated request is also a cache HIT on the same body | Same finding, but the cache ignores the query string so the origin couldn’t be observed in isolation — confirm the content is meant to be public | high |
The isolated request matches and isn’t a HIT | None — the origin serves this content to anyone | — |
This catches the missing Vary: Cookie case (a personalized page cached under a shared key) and a cache keyed on the path alone that ignores Authorization. It costs two requests from the --max-aggressive-requests budget.