Web Cache Poisoning Lab: Serve Your Payload to Everyone

✨ AI Summary
CacheServ caches each page by its URL and serves that copy to everyone. The app also reflects the X-Forwarded-Host header into the HTML — but that header is not part of the cache key. So one poisoned request can be stored and then handed to every visitor who asks for the same URL.
Lab at a glance: Advanced · 110 XP · about 20 minutes · runs in your browser, no signup or setup. Try it yourself first; the full solution is behind a spoiler below.

What this lab teaches

Web cache poisoning abuses the gap between what a cache uses as its key and what actually influences the response. If a header changes the page but is not part of the cache key (an 'unkeyed input'), an attacker can send one request that both injects content and gets cached — then every later visitor to that URL is served the attacker's version.

The lesson: anything that affects the response must be part of the cache key, or it becomes a way to poison the cache for everyone.

How CacheServ keys its cache

CacheServ builds the cache key from the URL only, but reflects the X-Forwarded-Host header into the page. Send a request with a malicious value in that header and the poisoned response gets stored under the normal URL key — so the next visitor, sending no such header, still receives your content.

The attack approach

  • Confirm X-Forwarded-Host is reflected into the HTML but is not part of the cache key.
  • Send a request to the target URL with a malicious X-Forwarded-Host value.
  • Get that poisoned response cached under the ordinary URL key.
  • Make a clean request (no special header) and confirm the cache serves the poisoned content.

Full walkthrough (spoiler)

If the clean request comes back untouched, your poisoned response did not get cached — open the steps.

Show the step-by-step solution
  1. Send a request to the cached URL with a crafted X-Forwarded-Host header that the page will reflect.
  2. Because the header is unkeyed, the cache stores your poisoned response under the plain URL key.
  3. Send a second, normal request to the same URL without the header — simulating a victim.
  4. The cache serves the stored poisoned content to that request. The lab detects the victim receiving your injected content and marks you solved.

Why it works

The cache assumes the URL fully determines the response, so it reuses one stored copy for every visitor. But the reflected header also shapes the page and is not in the key. One attacker request fixes the stored copy; everyone who shares that key then gets it. The mismatch between 'what affects the response' and 'what is keyed' is the whole bug.

Core principleEvery input that can change a cached response must be part of the cache key — or must not be reflected at all.

Where this happens in the real world

James Kettle's 2018 research 'Practical Web Cache Poisoning' demonstrated this class against major sites and frameworks, popularising unkeyed-header attacks via headers like X-Forwarded-Host. It maps to Security Misconfiguration (A05) in the OWASP Top 10 (2021) and can turn a reflected quirk into a mass, persistent attack.

How to defend against it

  • Key the cache on every input that influences the response, or strip those inputs before caching.
  • Do not reflect request headers like X-Forwarded-Host into responses unless you must, and never unvalidated.
  • Allowlist and normalise headers at the edge so unexpected ones cannot reach the app.
  • Scope cache entries carefully and keep cacheable responses free of request-specific data.
Mr Elite tip: To hunt cache poisoning on targets you are authorised to test, add headers like X-Forwarded-Host and see if they are reflected. If they are and they are not in the cache key, one request can affect many users.

Try it, then go further

Reading about it is the easy part. Open the lab, try your own approach before peeking at the spoiler, and see how many attempts it takes.

❓ Frequently asked questions

What is web cache poisoning?
An attack where an attacker gets a harmful response stored in a shared cache so that other users requesting the same resource are served the attacker's content.
What is an unkeyed input?
A request element (often a header like X-Forwarded-Host) that changes the response but is not part of the cache key, so its effect gets cached and reused for everyone.
Who discovered this class?
James Kettle's 2018 research 'Practical Web Cache Poisoning' demonstrated unkeyed-header attacks across major sites and made the technique widely known.
How do I prevent it?
Include every response-affecting input in the cache key (or strip it), and avoid reflecting request headers into responses unvalidated.
⚡
Join free to earn XP for reading this article Track your progress, build streaks and compete on the leaderboard.
Join Free
Lokesh N. Singh aka Mr Elite
Lokesh N. Singh aka Mr Elite
Founder, Securityelites · AI Red Team Educator
Founder of Securityelites and creator of the SE-ARTCP credential. Working penetration tester focused on AI red team, prompt injection research, and LLM security education.
About Lokesh ->

Leave a Comment

Your email address will not be published. Required fields are marked *