Safeguard
Application Security•

How do you avoid web cache poisoning attacks?

Cache poisoning happens when a shared cache stores a response shaped by input outside the cache key. Shrink unkeyed inputs and set Vary correctly.

Safeguard Security Team
5 min read

Web cache poisoning happens when a shared cache stores a response that was shaped by request data the cache does not use to tell requests apart, then serves it to other users. Avoid it by not reflecting unkeyed input, setting Vary correctly, and caching only content that truly does not vary.

How does a cache decide what is the same request?

A cache builds a key from parts of the request, normally the method and the URL, and sometimes selected headers. Two requests with the same key get the same stored response.

RFC 9111 describes this. When a stored response has a Vary header, the cache must not reuse it unless the request headers named by Vary match those of the original request. A Vary value of an asterisk never matches. The standard also warns that some resources mistakenly omit Vary on their default response, which affects which stored copy is chosen later.

The attack lives in the gap. If the server builds its response using something the key ignores, such as a forwarded host header or a query parameter treated as a no-op by the cache, one attacker request can fill the cache with a response that every later visitor receives.

What does the damage look like?

OWASP describes the impact simply: a malicious response in a shared cache keeps going to all users of that cache until the entry is purged. A response cached only in one browser affects that one user.

The consequences depend on what the poisoned response contains. A reflected script becomes stored for everyone. A redirect to another host becomes a site wide redirect. A broken or empty page becomes an outage that outlasts the attacker's single request.

A constructed example

A site sits behind a content delivery layer. The home page is cacheable for five minutes. The application reads a forwarded host header to build absolute links for images and scripts. The cache key includes only the path.

If a request arrives with a header naming a different host, the application builds links to that host and the cache stores the page under the path alone. For the next five minutes, ordinary visitors load scripts from an address the attacker chose. Nothing in the visitor's request looked unusual.

The fix has three parts: stop trusting the header, stop reflecting it, and make sure that if the response ever does vary on it, the cache knows.

How do you prevent it?

Reduce unkeyed inputs. List every request header, cookie and parameter your application reads when building a response. For each one that affects output, either add it to the cache key or stop using it.

Do not reflect what you do not need. Build absolute URLs from configuration, not from request headers.

Set Vary honestly. If the response differs by language, encoding or any named header, declare it. Over-declaring costs cache hits. Under-declaring costs correctness.

Cache less. Static, public assets are safe to cache. Pages with personalisation, authenticated content or reflected input should send cache directives that stop shared caches storing them.

Normalise at the edge. Strip or ignore unexpected headers before they reach the application, and make the cache and the origin agree on how to parse the URL.

Protect the purge path. If you can flush entries quickly, you can recover quickly. Know who can do it.

How do you test your own site?

Test only systems you own or have written permission to test, and never against a shared production cache with real traffic. Use a staging environment with the same cache layer. Add a harmless unique marker to an unusual header, request a cacheable page, then fetch it again without the header from a second client. If the marker appears, the header is unkeyed and reflected. Remove it from the response path.

Also review your cache configuration for rules that ignore query strings or cookies, since those rules decide what the key leaves out.

How to check or apply this

  1. Inventory which pages are cached, for how long, and by which layer.
  2. List the inputs each cached page reads.
  3. Remove reflection of headers you do not need.
  4. Add or correct Vary headers.
  5. Send no-store directives on personalised or authenticated responses.
  6. Test on staging with a unique marker.
  7. Document and rehearse how to purge the cache.

Quick check

Is web cache poisoning the same as cache deception?

No. Poisoning stores attacker shaped content for others to receive. Deception tricks a cache into storing a victim's private content under a public looking address.

Does a browser cache matter?

Yes, but its reach is one user. Shared caches such as proxies and content delivery layers carry the widest impact.

Sources

Last reviewed: 18 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.