Chaining Cache Poisoning To Stored XSS

Rohan Aggarwal
3 min readJul 28, 2019

One of the benefits of being a developer is that you can guess how stuff is working at the server end. You can try to debug how the developer might have coded a certain functionality or how he might have configured his application, especially in the case where the application is built in some framework or CMS.

For example, many developers using Rails framework use Scaffold to quickly generate major pieces of application like model, views and controller in a single operation. Besides this, Scaffold also creates JSON API endpoint for each route automatically which is most of the time overlooked by the devs or they forgot to remove this JSON endpoint while pushing to production.

So a dev who removed sensitive information from a normal route, might forget to remove the same from JSON endpoint of that route. Checking such misconfiguration might leak some sensitive data in a rails application. Therefore, having knowledge about the application technology really gives you differential findings than others.

Recently, I came across a Drupal application in a bug bounty program on Hackerone. Since I’ve used drupal before, I started looking for some common misconfigurations related to drupal. And within 10 minutes, I found one.

If you’ve developed on drupal before, you might know that it has it’s own internal caching system which is enabled by default. Easiest way to find whether caching is enabled is to look for x-drupal-cache header in the response. So you give unique key(endpoint + parameters) in request and in response you get x-drupal-cache: MISS header but if you request again with that same key and you get x-drupal-cache: HIT header in the response, caching is enabled. To learn more about how caching works and its exploitation, read this by albinowax.

After I came to knew that caching is enabled, one of the ways I can exploit is by poisoning the cache with XSS payload. But to do that I need to find an HTTP header that gets reflected in the response. Since drupal just like any other PHP framework sometimes supports X-Original-URL and X-Rewrite-URL headers because of Zend, I tried injecting these headers in request but sadly the application wasn’t accepting. What to do now? If nothing works, try brute-forcing.

So I used a burp suite extension called Param Miner which will brute force common headers. After few seconds I got a hit. It found a header named style which was getting reflected in response. I quickly checked whether it’s vulnerable to XSS and it was.

After that, I knew I can easily chain cache poisoning to stored XSS. I created a unique key & added style header with XSS payload and fired the request.

The response with XSS payload is cached for the above unique request. Now whenever someone visits, our poisoned response will be served by drupal resulting in Stored XSS.

That’s it. A simple drupal misconfiguration leads to Stored XSS.


Jun 14, 2019 — Report Submitted

Jun 15, 2019 — Triaged

Jul 12, 2019 — Resolved

Jul 13, 2019 — Rewarded

If you found this post useful in any way, make it useful for others as well by sharing. More coming.

Get Your Applications Tested Today at DefCore Security



Rohan Aggarwal

AppSec | BugBounty | Speaker | Game Hacking | Founder at Defcore Security