back to blog

Cache, Cache, and More Cache.

Published: 28 Aug 2026 · by 0xcdn

I was browsing my X account, formerly Twitter, when I came across something that stuck with me. Someone was tweeting about a blog post on web cache poisoning. I was intrigued, so I clicked through and read it, and then closed the tab thinking, what the hell did I just read. I didn't understand it.

I need to be honest about why. I didn't come from a cybersecurity background. I came from a warehouse job, nothing to do with IT or security. The only real foothold I had was a course I did back in 2008, HTML and CSS, basic website design. It wasn't that I had no idea what web cache poisoning was as a concept, it was that some of the technical language in that specific write-up hadn't landed for me yet. That's how it usually goes for me with a new vulnerability class: reading about it only gets me so far. I don't really understand something until I've exploited it myself, and once I've pulled off that first successful exploit, it clicks, and I get confident enough to go looking for it everywhere.

That should have been the end of it, but it wasn't. I went to PortSwigger's web cache poisoning labs, the CTF-style ones, and worked through them. The one rule I set myself was that I had to crack them without reading the hints or solutions. If I got stuck, I sat with it instead of peeking at the answer.

Once I actually felt confident in web cache poisoning as a class, I went and read blog posts and disclosed reports from past years, to see how the bug played out in the real world instead of a lab. I asked some friends about cache response behaviors too, and looked through roughly a hundred disclosed web cache poisoning reports on HackerOne.

All of that is what led me back to Rachid Allam's (zhero___) blog post, about a month after I'd first read it. This time it gave me real understanding of what he'd actually written.

From there I turned into a crazy raccoon, running around testing every Next.js site I could find against the pattern, by hand, site after site. It took almost a week or two of grinding, with some AI-assisted vibe coding along the way, before I had an actual scanner running.

Before testing anything, I needed to know which sites were even running Next.js in the first place. Both request and response headers give this away if you know what to look for: framework-internal headers like X-Middleware-Prefetch or X-Nextjs-Cache, certain default behaviors, certain response shapes that Next.js leaves behind whether or not a team has customized their stack. Once I could reliably fingerprint "this is Next.js" from the outside, I had a filter I could point at basically anything.

Here is a header using the RSC: 1 header, which caused the response to cache with a malformed JavaScript response.

RSC header applied to a 404 response

Wait, did you not notice something in the screenshot? Look closely.

Zoomed in on the Cf-Cache-Status header showing DYNAMIC

Notice how the response was DYNAMIC. Yet ever since I started hunting this vulnerability class, I've made it a habit to always check the browser to see if it actually cached the response, regardless of what any header claims. Why? Because some servers don't respect their own headers. DYNAMIC on paper doesn't always mean dynamic in practice, and the only way to know for sure is to go check. This one alone was a $5-6k payout, with DYNAMIC sitting right there in the response 😂.

By that point I was basically just testing the same pattern everywhere I found Next.js. One thing I got wrong early on was how quickly I would cross a target off my list. If I tested one part of a site and it wasn't vulnerable, I'd usually move on and assume they had it handled.

There was one program where I did exactly that. I tested a public-facing part of the site, got nothing, and moved on. A few weeks later I came back to the same program and tried a completely different section. That one was vulnerable. Then a few weeks after that, I went back again and found a language-specific version of that same section. It was a separate deployment, and that was vulnerable too. I think those three findings on the same program came to around $20,000 altogether.

After that I stopped treating one endpoint as meaning much for the rest of the site. Big companies have different teams, different deployments, regional versions, old sections of the site, all sorts of things running slightly differently. So now if I test something and don't find anything, I still come back to it later. Sometimes I try a different section, sometimes a regional site, sometimes just another path that looks like it might be handled differently.

A lot of the value has just come from testing the same idea in more places instead of assuming the first result tells you everything.