portswigger-all-labs

Complete PortSwigger Web Security Academy Lab Writeups Detailed, categorized solutions for every lab — from APPRENTICE to EXPERT — covering all 30 vulnerability types.

View on GitHub

Labs Covered

This write-up focuses on the following PRACTITIONER-level labs from the PortSwigger Web Security Academy related to Web Cache Poisoning:

1 Web cache poisoning with an unkeyed header

This lab demonstrates how attackers can poison cache responses by exploiting headers that are not included in the cache key.

2 Web cache poisoning with an unkeyed cookie

This lab shows how cookies not included in cache keys can be abused for cache poisoning attacks.

3 Web cache poisoning with multiple headers

This lab explores exploiting combinations of headers that are not properly keyed in the cache system.

4 Targeted web cache poisoning using an unknown header

This lab demonstrates using non-standard or undocumented headers to poison cached responses.

5 Web cache poisoning via an unkeyed query string

This lab shows how query strings that are not part of the cache key can be exploited for poisoning.

6 Web cache poisoning via an unkeyed query parameter

This lab demonstrates poisoning attacks targeting individual query parameters that are ignored by the caching layer.

7 Parameter cloaking

This lab shows how attackers can obfuscate parameters to achieve cache poisoning while evading detection.

8 Web cache poisoning via a fat GET request

This lab explores using oversized GET requests to trigger cache poisoning behaviors.

9 URL normalization

This lab demonstrates how URL normalization inconsistencies between cache layers and application servers can lead to successful poisoning attacks.

LAB 1 - Web cache poisoning with an unkeyed header

Lab Description

image

Solution

When we launch the lab, the following page appears:

image

Changing the URL of the Host header results in an error:

image

You could optionally change the port (e.g., to 90) to attempt to load a script. I didn’t explore that path, but feel free to test it:

image

Now, we observe that using the X-Forwarded-Host header lets us change the script source to apples.com, as shown by the highlighted URL:

apples.com/resources/js/tracking.js

image

In the first request, we get a cache miss.

Then on sending the same request again, we get a cache hit, confirming the response has been cached:

image


Cache Buster

Before modifying the request, it’s important to use a cache buster. This helps avoid accidentally poisoning the cache for other users during testing.

Add a cache-busting parameter to the URL, like so:

http://example.com/page.html?cache=123456

Here, cache=123456 ensures the response is unique to your request.

image

In this case, we use /?cb=1234 as our cache buster:

image


PortSwigger provides a mock Exploit Server to simulate a malicious response.

We configure the server to serve the following file:

/resources/js/tracking.js

And in that file, insert the payload:

alert(document.cookie);

image

Then update your request to use:

X-Forwarded-Host: YOUR-EXPLOIT-SERVER-ID.exploit-server.net

Replace YOUR-EXPLOIT-SERVER-ID with the domain assigned to you by PortSwigger.

The first request gives a cache miss:

image

Sending the same request again results in a cache hit, confirming the cache was poisoned:

image

Now we remove the cache buster and repeat the same request to test if poisoning works across the normal route.


Note:

To simulate a victim, open the poisoned URL in a browser. You should see the alert() triggered. ⚠️ Keep in mind: The cache in this lab expires every 30 seconds, so act quickly.

cache: miss

image

cache: hit

image

Alert triggered and lab is solved:

image


Lab Description

image

Solution

When we look at normal request we can see that url and cookie late part are reflected in the response

image

Changing the url give us error

image

Now we change cookie fehost with king and we can see in reponse its been reflected First time we send it gives us miss second time we send gives us hit

image

Now we have to alert on screen to solve the lab we used below script we can also used any other which work for example:fehost=someString"-alert(1)-"someString

First time we send request it gives us cache:miss

image

Second time we send request it gives us cache:hit

image

And we can see below lab is solved

image


LAB 3 - Web cache poisoning with multiple headers

Lab Description

image

Solution

Send normal request and see host is reflected in reponse no it not as we can see below image.

image

We can see tha script which is loading from host is /resource/js/tracking.js

image

Changing host header gives us 403 response

image

The X-Forwarded-Proto (XFP) header is a de-facto standard header for identifying the protocol (HTTP or HTTPS) that a client used to connect to your proxy or load balancer. Your server access logs contain the protocol used between the server and the load balancer, but not the protocol used between the client and the load balancer. To determine the protocol used between the client and the load balancer, the X-Forwarded-Proto request header can be used.

Using x-forwaded-proto http redirect us to which prersent in host header

image

And also we use x-forwarded-host and we can see in below image it is now redirecting to https and thw domain which we give in x-forwarded host exmple.com

image

Configuring our server to serve /resource/js/tracking.js and genrate alert cookie in js and then store exploit

image

cllick on view exploit

image

Changing x-forwaded-host to our exploit server domain and it will now load our server file and generate alert

image

Generater alet and lab is solved

image

Solved

image


LAB 4 - Targeted web cache poisoning using an unknown header

Lab Description

image

Solution

First we will check what is reflected and what is Cache and what is reflected in response we will see below these things Host:oa.….… ** reflected in response and using **/resources/css/js/tracking.js file to load js file Vary:useragnet(mean user agent is included in cache and hit or miss cache

image

We used X-forwarded-HOST but did not change our host url as we can see below.

image

Now used param miner to identify header not working in burp proessinal crack but work on burp community linux

image

Configuration of param which is default in our case

image

As we can look at x-host header is identified

image

Now using x-host to change url which is reflected in response

image

Configurating our exploit server to alert when we change it to x-host and and the file the above url is taking so it will request /resources/…. From a

The exploit server

image

And we can see alert belo image from abve request but in this lab we have to target specific user-agent victum to solved the lab ,So which user have that user-agent alert will be generated to them in cache.

image Commenting we can also used tresources/js/tracking.js file of exploit server We Will give 404 response and we will get agent which we have to target

image

As we can see we get 404 reponse in access log of server.

image

X-host has our exploit server url and user-agent have above agent Of our url

image

Sending above request will solved lab

image


LAB 5 - Web cache poisoning via an unkeyed query string

Lab Description

image

Solution

Overview: Exploiting Cache Implementation Flaws

While traditional web cache poisoning focuses on manipulating unkeyed headers or cookies, exploiting cache implementation flaws involves abusing how caching systems generate and handle cache keys. These flaws arise from misconfigurations or inconsistencies in how specific caches normalize, transform, or ignore parts of HTTP requests.

Instead of relying on classic attack vectors, this advanced methodology requires a deeper understanding of cache behavior, probing how the cache responds to subtle changes in requests, and chaining these quirks with other client-side vulnerabilities (like reflected XSS, open redirects, or resource imports) to escalate the impact.

This approach significantly expands the attack surface, allowing attackers to:

The process generally involves:

  1. Identifying a cache oracle to observe cache behavior.
  2. Probing key handling to spot anomalies or exclusions.
  3. Finding an exploitable gadget to deliver a high-impact attack.

Common flaws include:

These techniques—when combined with tools like Burp Suite and Param Miner—enable attackers to bypass normal caching logic, create persistent exploits, and even poison high-traffic pages, potentially impacting thousands of users.


image

Using below 4  cache bluster orgin stand out to be work
	Accept-Encoding: gzip, deflate, cachebuster
           Accept: */*, text/cachebuster
           Cookie: cachebuster=1 
	Origin: https://cachebuster.vulnerable-website.com

image

In red arrow we can see that how do apply differnet cache bluster technique

image

Remove the cache-buster Origin header.In other word elict harmful reponse without cache bluster sending request 15 to 20 times solved the lab

image

image


LAB 6 - Web cache poisoning via an unkeyed query parameter

Lab Description

image

Overview: Unkeyed Query Parameters in Cache Poisoning

Some web applications selectively exclude specific query parameters from the cache key—typically ones used for analytics or advertising, such as utm_content. These parameters are considered irrelevant by the backend and thus ignored when generating the cache key.

While these excluded parameters generally don’t affect the response significantly, they can still pose a threat in certain situations:

In short, although unkeyed parameters may seem harmless, they can be exploited on pages that mishandle the full URL or fail to sanitize input, making them a valid vector for advanced web cache poisoning attacks.

Solution

First we can see that how website look like in below image

image

Sending the above request to rpeater we can see that cache hit or mis and age cache control which tell us that it application is using cacahe of server to get website

image

Now adding cache buster we can see that it is relected in reponse we can try to break and get xss ,In our case we used utm_parameter whioch gives higher chance xss then our norrmla parameter equest

image

We can see that utm parameter below

image

Identifying parameter

image

Uisng a parm miner we have idenfified utm pa=armeter

image

End a request with a utm_content parameter that breaks out of the reflected string and injects an XSS payload:

GET /?utm_content=random'/><script>alert(1)</script>

image

And sendng multiple time above request generate alert and lab is solved

image


LAB 7 - Parameter cloaking

Lab Description

image

Overview: Cache Parameter Cloaking

Cache Parameter Cloaking is a powerful web cache poisoning technique that takes advantage of inconsistencies between how caching systems and backend applications parse query parameters.

In many real-world applications, certain query parameters—typically used for analytics or tracking—are excluded from the cache key. While these excluded parameters are not considered by the caching layer, they are still processed by the backend. This opens up a unique opportunity for attackers to inject malicious input that gets processed by the server but doesn’t affect the cache key.


How It Works

The technique relies on parameter parsing quirks—especially when the cache and the backend parse requests differently. For example:

GET /?example=123?excluded_param=bad-stuff

If example is used in a context like a reflected script or file path, the injected data (bad-stuff) becomes part of the response, allowing for persistent XSS or script injection without altering the cache behavior.


Realistic Exploitation Scenario

Say the server is using JSONP and reflects a callback parameter like:

GET /jsonp?callback=innocent

You might poison the cache using:

GET /jsonp?callback=innocent?callback=alert(1)

Other Cloaking Tricks

You can also exploit parsing quirks using:

For example:

GET /?keyed=abc&excluded=123;keyed=poison

This mismatch can allow you to inject unexpected behavior without interfering with the cache key.


Solution

First intercept the requets and we see that it using cache and we can also See that cookie is seeing

image

Using cacke bluster we can see that it is cache and refletced in reponse we can also see callback function in red rectangle

image

Try xss but characters are blocks

image

Observe that every page imports the script /js/geolocate.js, executing the callback function setCountryCookie(). Send the request GET /js/geolocate.js?callback=setCountryCookie to Burp Repeater. Notice that if you use a semicolon (;) to append another parameter to utm_content, the cache treats this as a single parameter. This means that the extra parameter is also excluded from the cache key. Alternatively, with Param Miner loaded, right-click on the
request and select “Bulk scan” > “Rails parameter cloaking scan” to identify the vulnerability automatically.

We can see the code of callback functionwhich we have idenfied.

image

Notice that you can control the name of the function that is called on the returned data by editing the callback parameter. However, you can’t poison the cache for other users in this way because the parameter is keyed Study the cache behavior. Observe that if you add duplicate callback parameters, only the final one is reflected in the response, but both are still keyed. However, if you append the second callback parameter to the utm_content parameter using a semicolon, it is excluded from the cache key and still overwrites the callback function in the response: Send the request again, but this time pass in alert(1) as the callback function:

    ```
     GET /js/geolocate.js?callback=setCountryCookie&utm_content=foo;callback=alert(1)
    ```

image

Get the response cached, then load the home page in the browser. Check that the alert() is triggered and lab is solved.

image


LAB 8 - Web cache poisoning via a fat GET request

Lab Description

image

Overview: Exploiting Fat GET Support

In some rare but critical scenarios, a web server or application may improperly handle HTTP request bodies on GET requests, leading to what’s known as a fat GET request. This opens the door for advanced cache poisoning attacks, even when classic vectors fail.


What is a Fat GET Request?

A fat GET is a GET request that includes a message body—a behavior that technically violates the HTTP standard but is still processed by some misconfigured applications.

Example:

GET /?param=innocent HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 20

param=bad-stuff-here

This discrepancy between what the cache sees and what the server processes creates an opportunity to inject malicious input that is cached and later served to others.


Solution

When we open proxy and look at target we can see that cachable https response.

image

Observe that every page imports the script /js/geolocate.js

image

Executing the callback function we can see in response setCountryCookie()

image

We can change the callback function parameter value and response is reflected which is kinge

image

Now change callback function to alert(1) but I doesnot generate alert which means some validation is applied In header we have cache bluster in origins

image

Now we have same callback function in header but alert callback In body Send the request again, but this time pass in alert(1) as the callback function. Check that you can successfully poison the cache.

image

Remove any cache busters and re-poison the cache. The lab will solve when the victim user visits any page containing this resource import URL.

image


LAB 9 - URL normalization

Lab Description

image

Solution

First we intercept the request and we can see that it is performing cache in the server.

image

Adding random in header or any other path is giving us error Not Found /Random,so to solve the lab we have deliver url to vixtum which will do xss,So we will try to brae the paragraph tag and add script tag for xss.

image

Now adding /random</p><script>alert(1)</script><p> foo wiil break url and add script tag.

image

Copying the response of url.

image

So copy url and deliver to victum Notice that if you request this URL in the browser, the payload doesn’t execute because it is URL-encoded So you have to hit cache and the immediately DELIVER PAYLOAD TO VICTUM.

This time, the alert() is executed because the browser’s encoded payload was URL-decoded by the cache, causing a cache hit

image

Lab is solved

image