Skip to main content
Create your own
Lesson illustration

Web Cache Poisoning Exploitation

Hello! Welcome to the next lesson in our advanced web security series.

In our last lesson, we explored HTTP Request Smuggling, a powerful technique for desynchronizing front-end and back-end servers to bypass security controls. You saw how a single, ambiguous request could poison the connection for the next user.

Today, we're going to explore the broader concept of which request smuggling is just one potential trigger: Web Cache Poisoning. This lesson will teach you how to identify and exploit web cache poisoning vulnerabilities to serve malicious content to users.

The core idea is to find a way to trick a web cache—a piece of infrastructure designed to speed up websites—into storing a malicious response. Once poisoned, the cache will then serve this harmful content to every user who requests that page, turning a minor, self-contained vulnerability into a widespread, persistent attack.

1. The Mechanics of Web Caching

Before we can poison a cache, we need to understand how it works. Caches sit between users and the main application server, saving copies of responses to reduce server load and latency.

To do this efficiently, the cache must decide if two different requests are asking for the same resource. It does this using a cache key.

Web cache poisoning | Web Security Academy

Let's start with the fundamentals. This article from PortSwigger's Web Security Academy provides a clear explanation of how caches work, and introduces the two most important concepts for this lesson: cache keys and unkeyed inputs.

Read the sections 'How does a web cache work?' and 'Cache keys'. Focus on understanding why caches exist and how they use a subset of the request (the cache key) to identify equivalent requests.

As you just read, a typical cache key includes the request line (e.g., GET /index.html) and the Host header. Everything else in the request—like cookies, user-agent strings, and other headers—is often ignored by the cache. These are called unkeyed inputs.

Web cache poisoning exploits a simple but critical flaw: what happens when the back-end application uses an unkeyed input to generate its response?

web cache poisoning

This diagram from PortSwigger illustrates the attack. The attacker sends a request with a malicious, unkeyed header. The back-end server processes this header and generates a poisoned response, which the cache then saves. Subsequent legitimate users who request the same page (matching the cache key) are served the attacker's malicious response.

The attacker's goal is to find an unkeyed input that gets reflected in the response without proper sanitization. The cache, blind to this input, sees a normal request and saves the resulting malicious response, serving it to all subsequent visitors.

2. A Methodology for Cache Poisoning

The researcher James Kettle, who revitalized this field of study, developed a clear, three-step methodology for finding and exploiting these vulnerabilities.

Cache Poisoning Methodology Flowchart
This flowchart by James Kettle outlines the systematic process for web cache poisoning. It involves (1) identifying unkeyed inputs, (2) assessing their exploit potential to create a harmful response, and (3) getting that harmful response saved in the cache. The process requires careful use of cache busters to avoid affecting real users during testing.

Let's break down these steps.

Web cache poisoning | Web Security Academy

The PortSwigger article we looked at earlier also details this methodology and introduces the single most important tool for the job: Param Miner.

Read the sections 'Identify and evaluate unkeyed inputs', 'Elicit a harmful response from the back-end server', and 'Get the response cached'. Pay close attention to the role of the Param Miner extension and the concept of using a 'cache buster' during testing.

To summarize the methodology:

  1. Identify Unkeyed Inputs: This is the most crucial step. You need to find headers or cookies that the application uses but the cache doesn't include in its key. Manually, this is extremely tedious. The Burp Suite extension Param Miner is essential here; it automates this discovery process by sending requests with a large dictionary of potential headers and observing which ones affect the response.

  2. Elicit a Harmful Response: Once you have an unkeyed input that is processed by the application, you need to see if you can abuse it. Can you make it reflect a script tag? Can you control a URL that the page uses to import a resource? This is where your creativity and understanding of the application come into play.

  3. Get the Response Cached: Just because you can generate a harmful response doesn't mean it will be cached. The cache might be configured to only store responses with certain status codes, content types, or response headers. You may need to hunt for a specific page on the site (like a blog post or product page) that has favorable caching rules.

3. Practical Exploitation: From Theory to Impact

The true power of cache poisoning lies in its ability to escalate low-impact or "useless" vulnerabilities into critical, site-wide threats.

Practical Web Cache Poisoning: Redefining 'Unexploitable'

Let's watch a segment from James Kettle's seminal Black Hat talk, 'Practical Web Cache Poisoning'. He demonstrates how to take a simple reflected XSS—which is normally useless because it's in a header you can't force a victim to send—and use cache poisoning to make it a stored XSS affecting everyone who visits the site's homepage.

Watch from 10:12 to 12:04. You'll see the methodology in action on Red Hat's website. Notice how the X-Forwarded-Host header, an unkeyed input, is used to inject a cross-site scripting payload that gets cached.

This is the classic example: turning a reflected XSS into a stored XSS. But the possibilities are far more varied and subtle. Given your comfort with reading JavaScript, you'll appreciate how this next attack works.

Practical Web Cache Poisoning: Redefining 'Unexploitable'

Now, let's look at a more advanced technique called DOM Poisoning. Here, the unkeyed input doesn't inject a script directly. Instead, it controls an attribute in the HTML that client-side JavaScript then uses to construct a URL for an API call.

Watch from 15:08 to 17:35. Kettle discovers that X-Forwarded-Host controls a data-site-root attribute. He then figures out what this attribute is used for and crafts a malicious JSON file to deliver the final XSS payload. This is a great example of chaining observations to build an exploit.

These techniques demonstrate how cache poisoning can be used to control the client-side execution environment. But what about controlling the server-side routing itself?

Many modern frameworks, in an attempt to be helpful, support headers that can override parts of the request, such as the path. Headers like X-Original-URL and X-Rewrite-URL are prime examples.

Practical Web Cache Poisoning: Redefining 'Unexploitable'

Let's watch one final clip from the same talk, demonstrating 'Local Route Poisoning'. Here, the X-Original-URL header is used to fool the cache into serving the 'gambling' page when a user requests the 'education' page.

Watch from 33:23 to 34:25. This shows how an unkeyed header can be abused to manipulate server-side path handling, leading the cache to serve entirely incorrect content.

This talk is a treasure trove of real-world examples, including hijacking Mozilla SHIELD updates and taking over any website hosted on HubSpot. I highly recommend watching the full video from the LINK resource when you have time. The full research paper (LINK) is also available for a deeper dive.

Test your understanding!

Imagine you've used Param Miner and discovered that the X-Forwarded-Scheme header is an unkeyed input. When you set it to http on a request to https://example.com/, the server responds with a 301 Moved Permanently redirect back to https://example.com/. By itself, this is harmless.

Based on the chaining techniques discussed, how might you combine this with another unkeyed input, like X-Forwarded-Host, to create a dangerous exploit?

Show answer

You could combine both headers in a single request. If the server processes both, you can craft a request like this:

GET / HTTP/1.1
Host: example.com
X-Forwarded-Scheme: http
X-Forwarded-Host: evil-attacker.com

The server might first process X-Forwarded-Scheme: http and decide it needs to redirect. Then, when constructing the redirect URL, it might use the X-Forwarded-Host header. The resulting response would be a 301 redirect to https://evil-attacker.com/.

If you can get this response cached for the homepage (/), you have effectively replaced the target's website with a redirect to your own, which could be used for phishing or malware delivery. This is an example of chaining two seemingly harmless unkeyed inputs to achieve a high-impact result.

Web Cache Poisoning Attack Chain Leading to Critical Impact
As this diagram illustrates, web cache poisoning is often the first step in a longer attack chain. By poisoning the cache, you can deliver an XSS payload that might steal cookies or perform actions on behalf of a user, ultimately leading to a full account takeover.

4. Prevention

As a professional, you'll need to recommend fixes. The best defense is to avoid the conditions that allow for cache poisoning in the first place.

  • Disable Caching: The most robust defense is to simply turn off caching unless it's absolutely necessary. Many sites enable it by default via CDNs without needing it.
  • Restrict Caching: Only cache purely static responses that you are certain cannot be influenced by user input.
  • Audit for Unkeyed Inputs: Use Param Miner to regularly audit your application to find and remove support for any unnecessary headers.
  • Configure Your Cache: If you must use unkeyed inputs, configure your cache to add them to the cache key. The Vary response header can be used for this, telling the cache to key on additional headers like User-Agent or Accept-Language.

Conclusion

Web cache poisoning is a sophisticated attack that leverages a fundamental trust between different layers of a web application's infrastructure. By understanding the interplay between the cache and the back-end server, you can turn seemingly benign behavior into a powerful exploit delivery mechanism.

Key Takeaways:

  • The Core Problem: Caches ignore "unkeyed inputs" (like headers), but back-end applications may use them to generate responses.
  • The Methodology: A three-step process of identifying unkeyed inputs, eliciting a harmful response, and getting that response cached.
  • Essential Tooling: Param Miner is indispensable for discovering unkeyed inputs.
  • The Impact: Cache poisoning acts as an exploit amplifier, escalating minor vulnerabilities like reflected XSS into persistent, site-wide attacks affecting all users.

Next Lesson Preview:

We will continue our exploration of advanced web attacks by looking at a common, complex, and often misconfigured protocol: OAuth 2.0. In the next lesson, we will dive into exploiting OAuth 2.0 implementation flaws, such as insecure redirect URIs, to achieve account takeovers.

Can't find a good explanation? Sign up and we'll make it for you

Sign up