PortSwigger

Lab Description
This lab contains an XSS vulnerability that is not directly exploitable due to browser URL-encoding.
Objective: Take advantage of the cache’s normalization process to exploit this vulnerability. Find the XSS vulnerability and inject a payload that will execute
alert(1)in the victim’s browser. Then, deliver the malicious URL to the victim.
Step 1: Understanding the Vulnerability
URL normalization:
- The cache normalizes URLs (e.g., decodes percent-encoded characters) before storing them in the cache key
- The browser URL-encodes special characters, preventing direct XSS
- By poisoning the cache with a normalized (decoded) payload, the browser’s encoded request hits the cached malicious response
The attack chain:
- Attacker sends request with unencoded XSS payload in path
- Cache normalizes (decodes) the URL and stores response
- Victim clicks link with URL-encoded payload
- Browser sends encoded request → cache matches normalized key → serves poisoned response → XSS executes
Step 2: Reconnaissance
Step 2.1: Find a Reflected Path
Browse to any non-existent path:
GET /random HTTP/1.1
Host: YOUR-LAB-ID.web-security-academy.net
Observe: The path /random is reflected in the error message.
The path parameter is reflected
Step 3: Crafting the XSS Payload
Step 3.1: Test Reflected XSS
GET /random</p><script>alert(1)</script><p>foo HTTP/1.1
Host: YOUR-LAB-ID.web-security-academy.net

In Repeater: The payload works.
In Browser: The payload is URL-encoded and doesn’t execute.
Step 4: Poisoning the Cache
Step 4.1: Send Unencoded Payload
Send the request with the unencoded payload:
GET /random</p><script>alert(1)</script><p>foo HTTP/1.1
Host: YOUR-LAB-ID.web-security-academy.net
tep 4.2: Replay Until Cached
Keep sending until X-Cache: hit.
Step 5: Testing the Exploit
Step 5.1: Load in Browser
Immediately after poisoning, load the URL in your browser:
https://YOUR-LAB-ID.web-security-academy.net/random</p><script>alert(1)</script><p>foo
The browser URL-encodes it to:
https://.../random%3C/p%3E%3Cscript%3Ealert(1)%3C/script%3E%3Cp%3Efoo

But the cache normalizes it back and serves the poisoned response → alert(1) executes!
Step 6: Delivering to the Victim
Step 6.1: Re-poison the Cache
Send the unencoded request again to ensure the cache is poisoned.

Step 6.2: Deliver the Link
Click “Deliver link to victim” in the lab.

Submit the malicious URL.
Step 7: Lab Solved
The victim clicks the link, the browser sends the encoded request, the cache serves the poisoned response, and alert(1) executes.
