shared × unstructured — bad data written permanently, and it spreads

Web Cache Poisoning

An input the cache key ignores gets baked into a stored response and replayed to everyone.

01the recipe

In the wild

example.py
# SMELL: cache a response keyed on trusted parts, ignoring an input that shapes it.
# (cache invalidation x unconstrained inputs)
key = request.path                        # ignores the X-Forwarded-Host header...
cache[key] = render(page, host=request.headers["X-Forwarded-Host"])
# attacker sets the header once -> poisoned page served to everyone after.

# RIGHT: key on every input that affects the output, or don't trust it at all.
host = allowlist(request.headers.get("X-Forwarded-Host"))   # vetted
cache[(request.path, host)] = render(page, host=host)
An attacker-influenced input the cache key ignores gets stored in a response and replayed to every subsequent user. One request poisons the shared cache; the blast radius is everyone downstream.
// observed
poisoned: one crafted header rewrites the page for all users
keyed:    host vetted and part of the key -- no shared poisoning
02weakness catalog

Mapped weaknesses (CWE)

On its own, this defect is catalogued by MITRE as one or more of these weaknesses. The exploitable vulnerability usually appears only when it chains or combines with another.