This vulnerability exploits mismatches between how applications and caching layers interpret URLs. It is easy to miss and has impacted large organizations like OpenAI, Paypal, and Netflix. If vulnerable, it can allow attackers to leak sensitive user information from the cache.
A web cache is a system that temporarily stores copies of web content, like HTML, images, JavaScript, and CSS, to improve performance and reduce the load on backend servers. When a user visits a website, certain parts of the page can be saved in a cache so that the next time the same content is requested, it can be served instantly without contacting the original server. This is why your browser can load websites faster on repeat visits; it stores pieces of the site in its local cache.
On the server side, caching is commonly handled by reverse proxies like Nginx. Nginx sits in front of your web application and acts as a gatekeeper, deciding whether to serve a cached response or forward the request to the backend. When configured, Nginx will cache responses based on certain rules, often by looking at the URL. For example, if a URL ends in .css or .js, Nginx may assume it is a static file and cache it to improve performance.
Web caches are primarily used to serve static assets, content that does not change from user to user, because they are safe to reuse across many visitors. However, caching can become dangerous if dynamic or user-specific content is cached by mistake. If a private user page like /account is cached and then served to someone else, it can result in serious information leaks.
To simulate this we can use nginx to set up a caching server and python flask to act as the web server. Setting up nginx is fairly easy first install nginx then modify the config file to match the following image.
As you can see in the image above nginx is configured to only cache things ending in .css or .js . Its doing the caching based on the ending of the url so depending on how the application is designed issues can appear. For example an application might see “/account” and “/account.js” as the same endpoint. If the account endpoint returns sensitive data it could be cached by nginx which means anyone can view the data returned.
To simulate the backend I wrote a quick python api in flask. You can see there is only one request that takes a path parameter. A path parameter in Flask captures part of the URL and passes it into your route function as a variable. In this example, /account/<path:name> matches any URL that starts with /account/ and treats everything after it as the name value.
Pay close attention to the path parameter. Nginx looks at the path parameter to decide if it should cache the response or not. What happens if it were to cache this page? Unauthenticated users would be able to see the response.
As you can see from the image above the API response with sensitive information such as your banking balance and social security number. Normally only users with the correct session will be able to see this page. However, an attacker can abuse the nginx rules and application path parameter to leak this information.
Web Cache Deception is a vulnerability where an attacker tricks a caching system into storing and serving sensitive user specific content as if it were public. This happens when the cache treats a URL as static (like ending in .css), but the backend still returns private data based on the user's session.
As mentioned earlier our nginx server is configured to cache responses where the url ends with the .css or .js extension. Its only looking at the url to decide, nothing else. At the same time the python application is configured to take a path variable. If we pick a path variable that ends with .css or .js it will be cached by nginx exposing the sensitive information.
As shown in the image above if we send an HTTP request to “/account/vuln.css?session=xyz” nginx will cache the response since it thinks the file is static because it ends with “.css”. However, python will respond normally because it thinks the vuln.css part is a path variable.
In the image above you can see that this is true. Looking at the url i used /account/ghostlulz.js . The python api responded with my sensitive information as it is designed to do. However, nginx cached the response since it thinks the page is a javascript file due to the ghostlulz.js ending. You know the page was cached because the response header says “X-Cache-Status = MISS “ . If you see that header then it means the page was cached by nginx.
Now if I visit the page as an unauthenticated user I should still be able to see the response. In this application the session parameter simulation an authentication token, deleting that will simulate an unauthenticated or anonymous user.
As you can see if I browse the same url as an unauthenticated user it responded with the cached response of the previous user. You can tell it's a cached response because the http response header says “X-Cache-Status = HIT” .
As an attacker all you have to do is get an authenticated user to click on your malicious link. If they do, it will cache the response . If the response contains sensitive information you will be able to view it by browsing to the same url.
This bug has been found on very popular sites such as OpenAI, Netflix, Paypal, and many more. As shown in the image above you can see that paypal was vulnerable to this several years ago. As a defender this type of bug can be hard to spot as it normally only appears at the deployment stage .
Web Cache Deception is one of those bugs that’s easy to overlook because everything works “as expected” , just not together. The application returns sensitive data only when it should, and the cache only stores things that look static. But when the two don’t agree on what a URL means, private data can end up getting cached and served to anyone. It’s a simple misconfiguration with serious consequences, and one that slips through the cracks because it depends on how both your proxy and application are configured. It’s a good reminder that even small mismatches between layers in your stack can lead to big vulnerabilities.