Web Cache Deception Attacks

Web Cache Deception is a vulnerability first described in 2017. It occurs when a caching system — such as a reverse proxy or CDN — can be tricked into caching sensitive, dynamic content that should only be delivered to authenticated users but ends up being publicly available. This is usually due to poorly thought-out or inconsistent configurations in how the cache interprets and stores different types of requests. The logic behind the vulnerability Many caching systems have simple rules for deciding what can and cannot be cached. A common pattern is to only cache "static" files — such as those ending in .js, .css, .png, .ico, etc. The problem arises when the cache relies solely on the structure of the URL path to make this decision, ignoring the actual behavior of the server behind it. Imagine this: the caching system is instructed to cache any request whose path ends in .js. At the same time, due to a poorly understood limitation or "feature", this system also ignores anything that comes after a semicolon (;) in the URL. Now, think of a URL like this: https://example.com/account/profile;a.js To the cache, this looks like a legitimate JavaScript file. But to the application server, it ignores the colon and everything that follows. If /account/profile returns private information about the logged-in user, that response may end up being stored and made publicly available. You can identify this type of behavior by monitoring HTTP headers like X-Cache:, Cf-Cache-Status:, and others, especially if they return values ​​like hit, miss, or dynamic. Also be aware of the value in the Age: header. Exploitation Scenarios Now let’s combine this flaw with business logic to show how the impact can be even more severe. Suppose you have a Discord-style application where users can create invite links to access groups or servers. These invites can be temporarily valid or manually disabled. Naturally, when they are invalidated, the system should prevent any reuse. But now imagine someone exploiting Web Cache Deception in the following way: 1 - A user creates a valid invite, for example: https://example.com/invite/ABC-DEF 2 - This user accesses this modified URL: https://example.com/invite/ABC-DEF;a.js Even though ;a.js is meaningless to the application server, the caching system may interpret it as a static resource. The response is then cached. Another exploit is using a line-feed (\n, URL-encoded as %0a), instead of the colon, or even %00, if you're dealing with Akamai, Fastly or OpenLiteSpeed. 3 - The original invitation is then deleted or expires. The "official" URL /invite/ABC-DEF now returns a 404, as expected. 4 - However, when accessing the version with ;a.js again, the response is served directly from the cache — and is still valid. This is because the cache has stored the previous response as if it were static and public. If the response includes the content of the invitation or an automatic redirect, the attacker can reuse the link even after it has been revoked.

May 9, 2025 - 19:30
 0
Web Cache Deception Attacks

Web Cache Deception is a vulnerability first described in 2017. It occurs when a caching system — such as a reverse proxy or CDN — can be tricked into caching sensitive, dynamic content that should only be delivered to authenticated users but ends up being publicly available. This is usually due to poorly thought-out or inconsistent configurations in how the cache interprets and stores different types of requests.

The logic behind the vulnerability

Many caching systems have simple rules for deciding what can and cannot be cached. A common pattern is to only cache "static" files — such as those ending in .js, .css, .png, .ico, etc. The problem arises when the cache relies solely on the structure of the URL path to make this decision, ignoring the actual behavior of the server behind it.

Imagine this: the caching system is instructed to cache any request whose path ends in .js. At the same time, due to a poorly understood limitation or "feature", this system also ignores anything that comes after a semicolon (;) in the URL. Now, think of a URL like this:

https://example.com/account/profile;a.js

To the cache, this looks like a legitimate JavaScript file. But to the application server, it ignores the colon and everything that follows. If /account/profile returns private information about the logged-in user, that response may end up being stored and made publicly available.

Image description

You can identify this type of behavior by monitoring HTTP headers like X-Cache:, Cf-Cache-Status:, and others, especially if they return values ​​like hit, miss, or dynamic. Also be aware of the value in the Age: header.

Exploitation Scenarios

Now let’s combine this flaw with business logic to show how the impact can be even more severe. Suppose you have a Discord-style application where users can create invite links to access groups or servers. These invites can be temporarily valid or manually disabled. Naturally, when they are invalidated, the system should prevent any reuse.

But now imagine someone exploiting Web Cache Deception in the following way:

1 - A user creates a valid invite, for example:

https://example.com/invite/ABC-DEF

2 - This user accesses this modified URL:

https://example.com/invite/ABC-DEF;a.js

Even though ;a.js is meaningless to the application server, the caching system may interpret it as a static resource. The response is then cached. Another exploit is using a line-feed (\n, URL-encoded as %0a), instead of the colon, or even %00, if you're dealing with Akamai, Fastly or OpenLiteSpeed.

3 - The original invitation is then deleted or expires. The "official" URL /invite/ABC-DEF now returns a 404, as expected.

4 - However, when accessing the version with ;a.js again, the response is served directly from the cache — and is still valid. This is because the cache has stored the previous response as if it were static and public.

If the response includes the content of the invitation or an automatic redirect, the attacker can reuse the link even after it has been revoked.