July 13, 2026
Cache Poisoning: From Cache Hits to Bounty
How I Hunt for Web Cache Poisoning Vulnerabilities in Applications
By Jayesh kunwal
11 min read
How I Hunt for Web Cache Poisoning Vulnerabilities in Applications
Web Cache Poisoning is one of those vulnerabilities that sounds extremely advanced when we first hear about it.
But honestly? The initial hunting process is surprisingly simple.
Most of the time, it starts with casually browsing a website and paying attention to tiny behavioral differences. Over time, I realized that cache poisoning bugs hunting don't start with complicated exploitation chains. They start with simple observation.
Things like:
- A strange header.
- A weird cache hit.
- An unexpected reflection.
- A response that behaves slightly differently. That's it!!
The hard part isn't the exploitation. The hard part is noticing what everyone else overlooks.
In this blog, I'll walk you through the exact practical methodology I personally use to hunt for Web Cache Poisoning vulnerabilities during bug bounty hunting from the initial reconnaissance to identifying cache behaviors and discover real world exploitation opportunities.
Not heavy theory. Not academic explanations. Just a practical, hacker first workflow that you can apply during real bug bounty engagements.
The kind of workflow where you fire up Burp Suite, browse the target like a normal user, and let the application gradually reveal how its caching infrastructure behaves.
But before we dive into the methodology, let's quickly understand what a cache is and what Web Cache Poisoning actually means especially if you're completely new to the concept.
Imagine a popular tea shop where hundreds of people order masala chai every morning. If the shop owner brewed a fresh cup from scratch for every single customer, the queue would grow quickly, and everyone would have to wait much longer.
Instead, the shop owner prepares a large batch of tea in advance and keeps it ready. Whenever a customer arrives, he simply pours it into a cup and serves it immediately.
Fast. Efficient. Scalable.
That large container of ready-made tea is a perfect analogy for a web cache. Instead of preparing the same response for every visitor, the server stores a pre-generated copy and serves it repeatedly until it needs to be refreshed.
In technical terms: A cache is a temporary storage layer that keeps a copy of previously generated responses. Instead of generating the same content for every incoming request, the server (or a caching layer like a CDN or reverse proxy) simply serves the cached response. This reduces processing overhead, improves response times, and allows websites to handle far more traffic efficiently.
Content that doesn't change from one user to another such as images, JavaScript, CSS files, and many public web pages is often cached. Instead of generating the same response repeatedly, the server simply serves the cached version, improving performance and reducing server load.
Normal flow
Poisoned flow:
Understanding the Goal
Now comes the interesting part.
Before we start hunting, it's important to understand what we're actually trying to achieve.
In simple terms, the goal of Web Cache Poisoning is straightforward:
Trick the cache server into storing a malicious or manipulated response so that will later be served to other users.
Normally, a cache stores legitimate responses to improve performance. But if an attacker can inject malicious data/Payloads into a response before it gets cached, the cache may treat that manipulated response as legitimate.
From that point on, every user requesting the same resource may receive the poisoned response instead of the original one until the cache expires or is purged.
That's where the fun begins.
The rest of this blog is about understanding how to make that happen in a real-world bug bounty hunting.
My Initial Recon Process
Whenever I start testing a target, I don't immediately jump into payloads.
Instead, I behave like a completely normal user.
I simply:
- Open the website normally
- Browse random pages
- Click around the application
- Register or login if possible
- Use the search functionality
- Visit product pages
- Explore blogs, dashboards, APIs, profile pages, and anything else I can access.
At this stage, I'm not "attacking" anything.
I'm observing.
I want to understand:
- How the application behaves
- Which pages appear to be static or cacheable.
- Which responses seem to be served by a CDN or reverse proxy.
- Whether different pages behave differently
Sometimes you'll notice certain pages loading suspiciously fast.
Sometimes refreshing the page changes the response headers
Sometimes an endpoint suddenly start returning X-Cache:Hit
That tiny header can become the beginning of a very interesting night 🌌. (And probably the reason your sleep schedule gets destroyed.)
Identifying Cache Infrastructure
This is where the real hunting begins.
While browsing, I continuously keep my eyes 👀 on response headers. it tell you a lot about the infrastructure sitting behind the application. At this stage, I'm not trying to exploit anything. I'm simply fingerprinting the caching layer without touching a single exploit payload yet. Some common headers I look for in Response:
X-Cache:
CF-Cache-Status:
Cache-Status:
Age:
X-Proxy-Cache:
X-Served-By:
Via:
Server:X-Cache:
CF-Cache-Status:
Cache-Status:
Age:
X-Proxy-Cache:
X-Served-By:
Via:
Server:These headers can tell you things like:
- Whether the response is being cached.
- Whether you're receiving a cache hit or a cache miss.
- Which CDN, reverse proxy, or caching technology is handling the request.
- Whether multiple users are likely receiving the same cached response.
And this is exactly what attackers love.
The Age Header
One header I pay close attention to is Age.
Age: 1200Age: 1200This means the cached object has been stored for 1,200 seconds.
Mini Tip:
If the Age value generally increases across repeated requests to the same resource (without resetting), there's a good chance you're interacting with a real caching layer. congratulations!!
My Methodology To Hunt For Web Cache Poisoning
Now that we know how caching works and what we're trying to achieve, the next question is: where do we start looking?
This is honestly one of the easiest and most effective techniques I use during reconnaissance.
Step 1: Identify Cacheable Endpoints
I basically use Burp Suite like a search engine.
First, I:
- Add the target domain to Burp's scope.
- Browse the application normally.
- Generate traffic naturally by interacting with different features.
Once I've collected enough traffic, I use Burp Suite's search and filter functionality to look for cache-related headers.
Some of the keywords I commonly search for are: Cache:,X-cache:,hit:,cache-status:,Cache-Status,AgeX-Proxy-Cache,X-Served-By
Within a few seconds, Burp highlights the responses that appear to be interacting with a caching layer. Now instead of blindly testing every endpoint in the application, I can focus only on the responses that show signs of caching.
That makes a huge difference. It saves an incredible amount of time during bug bounty hunting.
Because trust me…
Testing Web Cache Poisoning on endpoints that aren't cacheable is a fantastic way to waste your entire evening.
Step 2: Analyzing Cached Endpoints
Finding cacheable endpoints is only the first step. The next challenge is determining whether they're actually worth testing.
Once I've identified responses that appear to be cacheable, I start analyzing them more carefully.
At this point, I'm trying to understand what is being cached and whether it's actually interesting.
Some of the questions I ask myself are:
- Which pages are being cached?
- Are only static assets cached?
- Are HTML pages cached?
- Are personalized or user-specific responses being cached?
- Is any sensitive content ending up in the cache?
Sometimes you'll find that only harmless static resources are cached. But every now and then, an application accidentally caches dynamic content.
That's when things start getting interesting.
I also pay close attention to response headers such as:
Cache-Control
Vary
Age
ETag
ExpiresCache-Control
Vary
Age
ETag
ExpiresFor example:
Cache-Control: public, max-age=3600Cache-Control: public, max-age=3600Interesting. Very interesting!! Now I know the response is intended to be stored in a shared cache for up to one hour. That immediately makes me curious to see whether I can influence what gets stored.
Step 3: Time to Experiment
Once I've found an endpoint that looks being cached, it's time to stop observing and start experimenting.
This phase is mostly about experimentation.
Once I find an interesting endpoints, I send all the filtered request to Burp Repeater.
Now the fun starts!! 😈
I start modifying the request by injecting various HTTP headers and carefully watch how the application responds after each change.
Some headers I frequently inject are:
X-Forwarded-Host
X-Host
X-Forwarded-Scheme
X-Original-URL
X-Rewrite-URL
ForwardedX-Forwarded-Host
X-Host
X-Forwarded-Scheme
X-Original-URL
X-Rewrite-URL
ForwardedFor Example: X-Forwarded-Host: blackdustbb.com
Forwarded: host=blackdustbb.com
Another easy approach is to send the request to Burp Intruder, place payload markers $$ around any of the header value, load a header payload list, and start the attack.
Then I carefully observe the response and ask myself:
Did anything change? Did the application reflect my input?, Did redirects behavior change? Did absolute URLs change? Did JavaScript or CSS references change? Did the cache headers behave differently?
Step 4: Hunt for Tiny Differences (Response Analysis)
Injecting headers is easy.
Understanding what the application's responses are telling you is where the real skill comes in.
This is where patience matters. Web Cache Poisoning vulnerabilities don't scream: "I AM VULNERABLE." Instead, they whisper. "TINY DIFFERENCE MATTER" That's why I analyze every response carefully.
At this stage, I'm looking for indicators that my injected input is influencing the application's response and may eventually become part of the cached response.
Some of the things I usually look for are
- Reflected input
- Header differences
- Cache HIT vs MISS behavior
- Timing differences
- Unexpected redirects
- Unexpected HTML changes
- Modified resource URLs
- Changes to absolute URLs or generated links
- Response splitting or any other unusual behavior
Example: First request response haveX-Cache: MISSSecond request response have X-Cache: HITNow things become interesting.
Seeing X-Cache: HIT tells me that the response is now being served from the cache.
The next question I ask myself is:
Has the value I injected into the request whether through an HTTP header, a query parameter, or another part of the request been reflected or incorporated into the response, and has that modified response also been stored in the cache?
That's the key question.
If I can't immediately tell whether my injected value is being cached, I continue testing until I can confirm it.
I continue testing by trying different request variations, such as:
- Changing the injected header values
- Combining multiple headers
- Modifying the request path
- Adding or changing query parameters
- Testing different URL formats
After every change, I compare the responses carefully and look for even the smallest behavioral differences.
Sometimes changing a single header value causes it to be reflected in the response.
Sometimes modifying the request path changes how the application generates URLs.
Sometimes adding a query parameter changes the cache behavior.
Every small difference is another clue.
Once I can consistently verify that my injected value or the response it influences is being stored and served from the cache, I know I'm heading in the right direction.
Step 5: From Observation to Exploitation
This is where things get serious.
Up until now, I've been experimenting and collecting clues. But once I notice that the value I've injected into an HTTP header is actually influencing the application's response for example, it's reflected in the HTML, changes a redirect, modifies resource URLs, alters generated links, or affects the cached response I know I've found something worth investigating further.
At this point, my goal is no longer to find interesting behavior. My goal is to determine whether that behavior can be turned into a real Web Cache Poisoning vulnerability.
From this point onward, every request has a purpose.
Now I start asking myself questions like:
- Can I make the cache store my manipulated response?
- Can I make other users receive that manipulated response?
- Can I inject attacker-controlled JavaScript into the cached response?
- Can I poison cached HTML pages?
- Can I manipulate cached redirects?
- Can I make the application generate attacker-controlled URLs or resource references?
- Can I reproduce the behavior consistently?
If the answer to any of these questions is yes, I've likely moved beyond an interesting observation and into a genuine Web Cache Poisoning vulnerability.
Finally comes the most important step validation.
Does the manipulated behavior persist for other users?
I verify my findings by accessing the page from:
Another browser, Incognito mode, Another session, Another IP sometimes And then…
If the manipulated response is served there as well, that mean the cache not just my own session is serving the poisoned content to other users.
That moment is beautiful.
Terrifying for the target. But beautiful for bug bounty hunters.
Putting It All Together: Real-World Example
One of the Web Cache Poisoning vulnerabilities I reported involved a cached XSS through the X-Forwarded-For header.
Vulnerability: XSS via X-Forwarded-For Header Cached by CloudFront
High-Level Reproduction Overview
The application reflected the value supplied in the X-Forwarded-For header into the response. Once that modified response was cached by CloudFront, subsequent visitors requesting the same page received the cached response, resulting in the injected script executing in their browsers.
The key observation was that the response transitioned from a cache MISS to a cache HIT, confirming that the modified response had been stored and served from the shared cache.
Steps to Reproduce
- Open Burp Suite and enable Intercept.
- Browse to the target application:
https://au.blackdustbb.com/(In this target application, the homepage was being served from the cache, You know how to observe) - Capture the request in Burp Suite.
- Right-click the intercepted request and select Send to Repeater.
- In Repeater, add the following HTTP header:
X-Forwarded-For: "><script>alert(document.domain)</script> - Send the request repeatedly until the response contains:
X-Cache: Hit from cloudfront - This indicates that the modified response has been cached by CloudFront.
- Open the application in a different browser, an Incognito/Private window, or a new session. Visit:
https://au.blackdustbb.com/ - Observe that the cached response executes the injected JavaScript in the browser, resulting in:
alert(document.domain)
Impact
Exploitation allows an attacker to poison the CDN cache with malicious JavaScript that executes in the browsers of other users visiting the affected page. An attacker may be able to:
- Execute arbitrary JavaScript in victim browsers
- Hijack authenticated user sessions
- Steal session tokens or sensitive information
- Perform actions on behalf of victims
- Deface application content
- Deliver phishing or malware payloads
- Compromise multiple users through shared cached responses
Bonus: Practical Tips That Help Me Find Web Cache Poisoning:
Fingerprint the cache first read X-Cache, Age, Cache-Control, and especially Vary (lists keyed headers anything reflected but not in Vary is a candidate). Identify the CDN: Cloudflare, Fastly, Akamai, Varnish each has its own quirks.
Use Param Miner to discover hidden headers such as X-Forwarded-Host, X-Forwarded-Scheme, X-Host, and similar request inputs. If the application uses one of these headers to modify the response
Always test with a cache buster (for example, ?cb=random123). This creates a fresh cache entry for your testing. Send the same request twice and watch for X-Cache: HIT or an increasing Age header to verify that the response is being served from the cache.
No impact, no bounty. Chain it reflected XSS, malicious <script src>, poisoned open redirect → token theft, or DoS over a critical endpoint. Write up the victim impact, not just the X-Cache: hit.
Don't Rush Into Exploitation first understand cache behaviour. Most beginners instantly throw payloads everywhere without understanding whether caching even exists. Infrastructure understanding comes first.
Static Pages Are Gold blogs landing pages, product pages, documentation pages these are often heavily cached. Always inspect them carefully.
Observe Repeated Requests refresh the same request multiple times. Sometimes cache behavior only becomes visible after repeated requests.
Burp Repeater Is Your Best Friend most real cache poisoning findings come from manual observation inside Repeater. Automation helps. But manual testing finds the weird edge cases.
Keep Your Own Payload Notes over time, build your own collection of Interesting headers, CDN-specific tricks, Reverse proxy quirks, Cache bypass payloads That personal knowledge base becomes incredibly valuable. I have my own if you want that please ping me any time.
Final Thoughts: The Right Mindset Matters
Web Cache Poisoning is not just about payloads.
It's about observation!! It's about curiosity!! And above all, it's about patience!!
The best researchers are usually the ones who notice tiny Behavioral differences others ignore. A reflected header, A strange Age value, A cached redirect, An unexpected X-Cache: HIT. Those small observations often become the starting point for critical vulnerabilities.
Many high impact vulnerability begin with a simple thought: "Hmm… that looks slightly weird." That curiosity matters. A lot.
The methodology I shared in this blog isn't a magic checklist that guarantees you'll find a vulnerability on every target. It's simply the practical workflow I personally follow whenever I hunt for Web Cache Poisoning Vulnerabilities.
Sometimes you'll spend an hour/days and find nothing. Sometimes one unusual response header leads to a critical report. That's bug bounty!! Keep observing!! Keep experimenting!! And never ignore the tiny differences.
Because sometimes, that's exactly where the bug is hiding. So next time you're browsing a target during bug bounty hunting…
Slow down!!! Observe more carefully!!!!! Open the headers!!!! Watch the cache behaviour!!!!!
Keep exploring, keep testing, and most importantly — stay curious.
Stay tuned !!