· 19 min read Sam Verified author

Web-Cache Deception

My notes about Cache Deception in web applications

Web-Cache Deception Vulnerability OWASP

Category: [Server-Side]
Severity: [High to Critical]
Impact: [Data theft, Session/Token leakage, Account Takeover, etc...]


1. Concept

This vulnerability enables the attacker to trick web cache into storing sensitive data, so what attacker can’t access directly, being access via web cache.

Poisoning vs Deception

What is the difference between poisoning and deception? In web cache poisoning, attacker targets a wide range of users or sometimes a specific user, everybody whom request the targeted endpoint will give a poisoned webpage, But in web cache deception, attacker tricks the user to make a request to some dynamic or sensitive data and using the vulnerability, store it in cache.


2. What is Deception?

In this attack, hacker persuades the victim to visit a malicious URL or make a request to that URL, then victim’s browser makes an ambiguous request for sensitive data which is visible ONLY for victim. The cache misinterprets the request for a static resource and stores the response, the attacker make the same request and get that sensitive data. This is the core concept of this vulnerability.


3. A quick look at Cache Rules

It determines what can be cached and for how long. rules often set up to store static resources. Dynamic contents must not be cached as it may contain sensitive data, ensuring that the user get such a data directly from origin server. In this kind of attacks, attacker exploits how cache rules are applied. There are several type of cache rules, for example the string based cache rules:

  • Static file extension rules: like .js or .css files
  • Static directory rules: match all URL paths that starts with a specific prefix, for example: /assets, /statics
  • File name rules: match file names like robots.txt or favicon.ico

4. Constructing a web-cache deception attack

  • Identify vulnerable endpoint
  • Identify discrepancy point between cache and origin server
  • Exploit the vulnerability by crafting a malicious URL

Identify vulnerable endpoint

Search for a vulnerable endpoint which is responsible to generate some sensitive data like profile information of users. as some of these sensitive data may not be visible and rendered directly in webpage, we should check HTTP requests using some tools like Burp Suite. Focus on endpoints that support GET, HEAD, OPTIONS methods, as these methods doesn’t apply any change on the server (What changes the server’s state doesn’t being cached naturally).

So what you should looking for is:

GET
HEAD
OPTIONS
// Or any other method that doesn't change server's state

and sensitive endpoints, for example: /my-account which is being used in some websites to show profile information to user.

Identify discrepancy points

You should identify how cache server and origin server process the same request, if you find any discrepancy, it may be a WCD vulnerability.

This could be a discrepancy in how they:

  • Map URLs to resources
  • Process delimiter characters
  • Normalize paths
URL/Resource mapping

Deciding which file or code should handle the entered URL. example:

URL: https://example.com/profile/view
Resource: /var/www/profile/view/view.php

or it may run a function:

URL: https://example.com/profile/view
Function: getProfile(username, ...)
Delimiter processing

Common delimiters are: / ? & # ; . these characters are being used in different parts of a URL and separate a part from another one, example:

https://example.com/image/photo.jpg;admin=True

In this example, / separate URL paths, ; take the parameter admin and = defines the value of the parameter. We call these characters, Delimiters. Web server should interprets these characters correctly, otherwise it may lead to a WCD attack, example:

https://example.com/image/load?img=photo.jpg;admin=True :: What user enters
image → load → some_loader.php → img=photo.jpg          :: What webserver see
Path normalization

Clean up and standardize the URL path. each entered URL should convert to a standard format of URL. for example:

URL           : https://example.com/img/../admin//panel/.
Normalized URL: https://example.com/admin/panel

Incorrect normalization may lead to some other kind of bugs like LFI.

Craft a Malicious URL

We should then craft a malicious URL which is using the discrepancy to trick the cache into storing a dynamic response. When the victim visits the URL, their response will be stored in the cache, the attacker the send the same request and fetch the sensitive data.

Note: Avoid doing this directly in browser as some applications redirects unauthorized users which can hide the vulnerability


5. Exploiting static extension cache rules

Cache rules often target static resources like .css or .js files. An attacker can use the discrepancies between how the origin server and cache server map URLs to resources.

URL Path Mapping is the process of mapping an incoming path to a site’s resources — connecting the requested path to the intended resource. Various methods exist for mapping, and each framework has its own approach. Two commonly used methods are Traditional URL Mapping and RESTful URL Mapping.

Traditional URL Mapping

This mapping type creates a direct path to a resource that exists on the host filesystem:

https://example.com/resource.html
        │           │           │
        ▼           ▼           ▼
     Server    Filesystem      File
      Host      Directory
RESTful URL Mapping

In contrast, the RESTful model does not load the file directly. Instead, it transforms the path into logical API components:

https://example.com/path/resource/param1/param2
        │              │              │
        ▼              ▼              ▼
     Server      Endpoint of    Parameters
                  Resource

Parameters are used by the server to process the request and load the intended resource.

Illustrative Example URL: https://example.com/user/sam/profile/wcd.css Assume the origin server uses RESTful URL Mapping — it interprets the URL as a request for /user/sam/profile and ignores wcd.css. Now suppose the web cache uses Traditional Mapping — it treats the request as one for /user/sam/profile/wcd.css. If the cache is configured to store responses for URLs ending in .css, the origin server returns the response for /user/sam/profile, but the cache believes the response belongs to wcd.css and caches it. This discrepancy in path mapping is exploited.

Exploiting Path Mapping Discrepancies

To understand how the origin server performs mapping, append an arbitrary string to the URL and observe its effect on the loaded content.

Example: Suppose an endpoint displays a user’s orders in their account. Modify it as follows:

Endpoint TypeURL
Main endpoint/api/order/123
Modified endpoint/api/order/123/abc

If adding the arbitrary string does not change the content loaded by the site, the server is ignoring that string — indicating an opportunity for testing. Since adding a string to the endpoint had no effect on page content, we look for a static file format defined in cache rules, such as .js, and append it to the URL:

/api/order/123/abc.js

By sending similar requests and verifying the response is cached, we confirm the servers interpreted the URL differently:

Origin Server:    /api/order/123
Cache Server:     /api/order/123/abc.js

The origin server sees a request for order 123 information, while the cache server sees a request for abc.js. Since cache rules define .js files for caching, the cache server stores the response. In this scenario we assumed the cache server stores .js files. In reality, you can test a wide range of formats to see which are defined for caching.

Common formats often found in cache rules:

.js, .css, .png, .jpg, .jpeg, .ico, .woff, .woff2, .ttf, .json, .txt, .ts, .cjs, .mjs

Note: A website may have different cache rules for different endpoints. A format cached on one endpoint does not guarantee the same behavior on another.


6. Delimiter discrepancies

Delimiters are special characters in URLs that separate different sections and boundaries. A set of characters is standard across all websites — for example, ? denotes the query string. Although the URI RFC (e.g., RFC 3986) permits customizing these characters, most sites use the standard set. Frameworks also differ in which delimiters they recognize.

Differences in how the origin server and cache server handle these characters can give rise to a WCD vulnerability.

Example: Java Spring Framework Java Spring uses ; (semicolon) as a delimiter for defining parameters. If a server runs Spring, the path /profile;abc.js is interpreted as /profile with parameter abc.js — returning the user’s account info. Many other frameworks do not treat ; as a delimiter. If a cache server uses such a framework, it interprets the URL as /profile;abc.js. If a rule exists to cache .js files, the cache stores the response — enabling an attacker to retrieve the victim’s account info via a similar request.

Other Framework Examples

  • Ruby on Rails uses . (dot) as a delimiter
  • OpenLiteSpeed uses %00 (null byte)

By identifying the technology stack, you can select the appropriate characters for testing this vulnerability.

Exploiting Delimiter Discrepancies

To exploit this, find a character used as a delimiter by the origin server but not by the cache server.

Step 1: Identify delimiters used by the origin server Append an arbitrary string to the endpoint:

Original endpoint:  /settings/users/list
Modified endpoint:  /settings/users/listaaa

Send the request. If the response is unchanged, the server is ignoring the appended string — indicating a delimiter may be at play.

Step 2: Test candidate delimiter characters Insert a suspected delimiter between the endpoint and the appended string:

/settings/users/list;aaa

If the response still matches the original, the server treats ; as a delimiter — aaa is treated as a parameter (or handled per app config). The key insight: the origin server interprets the endpoint as /settings/users/list despite the extra input. If the server treats the full path /settings/users/list;aaa as-is, then ; is not a delimiter — test other characters. Once you have found a delimiter used by the origin server, determine whether the cache server also recognizes it. Append a static file extension (e.g., .js):

/settings/users/list;aaa.js

If the response is cached, this means:

  • The cache server does not treat ; as a delimiter
  • It sees the endpoint as /settings/users/list;aaa.js
  • A cache rule exists for .js files, so the response is stored

The Discrepancy is Clear

ServerInterpretation
Origin/settings/users/list
Cache  /settings/users/list;aaa.js

Attack Execution The attacker sends a link like:

https://example.com/settings/users/list;aaa.js

to a victim who has access to that endpoint. The discrepancy between servers causes the victim’s user list to be cached. The attacker then retrieves it with a similar request.

Note: The victim’s browser may URL-encode certain characters. If the server does not decode them, the exploit fails.


7. Decoding discrepancies

Sometimes websites need to transmit data via URLs containing characters the server treats specially (e.g., delimiters). These characters are typically URL-encoded to ensure they are treated as data. However, some parsers are configured to auto-decode a predefined set of characters.

If a character is decoded, it may become a delimiter. Differences in which characters are decoded by the origin server vs. the cache server cause each to interpret the request differently — creating a vulnerability.

Example 1: Origin Server Decodes, Cache Server Does Not

profile%23file.css        (%23 = #)
  • Origin server decodes %23 to # (a delimiter) → interprets path as /profile → returns sensitive account info
  • Cache server treats # as a delimiter too, but sees the raw /profile%23file.css → configured to cache .css files → stores the sensitive response

Example 2: Cache Server Decodes Before Forwarding

account%3ffile.css        (%3f = ?)
  • Cache server applies rules on the undecoded URL first — sees it ends in .css → decides to cache the response
  • Then decodes the request and forwards to origin: account?file.css
  • Origin server treats ? as a delimiter → file.css becomes a parameter → returns /account (user account info) Result: The cache stores the account info under a .css path.

Exploiting Decoding Discrepancies

Encode a delimiter and use it in the URL, then append a static file extension to observe cache behavior. The scenarios from the delimiter discrepancies section apply here — the only difference is encoding/decoding.

Tip: You can also test non-printable characters like %00, %0A, %09 to see how the web app handles them.


8. Exploiting static directories

Web servers typically have Static Directories — paths where static assets are stored, for example:

  • /assets
  • /static
  • /images Since content in these paths rarely changes, they are often included in cache rules — which can introduce vulnerabilities.

Normalization Discrepancies

Normalization = converting a user-supplied URL to its standard form. This may involve decoding, encoding, and resolving dot-segments (., ..).

Resolving dot-segments example:

https://example.com/static/..%2fprofile     (%2f = /)

The endpoint is effectively /static/../profile. If the server processes .. and goes up one directory, the path becomes /profile. This is called Resolving Dot-Segments.

If the origin server and cache server normalize URLs differently, a WCD vulnerability arises. URL: /static/..%2fprofile

ServerBehaviorInterpreted Path
OriginDecodes + resolves dots/profile → returns user info
Cache  No normalization/static/..%2fprofile

If the cache is configured to store responses for /static/..., the user’s sensitive /profile data gets cached under a static path.

Why URL-Encode the Payload? If the victim enters /static/../profile directly in the browser, the browser auto-normalizes it to /profile before sending — the payload never reaches the server. By encoding (/static/..%2fprofile), the browser treats it as a literal path segment and forwards it intact.

Note: You can encode any part of the URL, but ensure the browser doesn’t pre-process it. Common safe positions: before/after dots, or encode the entire path.

Terminology: /static/..%2fprofile is a Path Traversal Sequence.


9. Detecting normalization behavior

Detecting Origin Server (Root) Normalization

Send a request to a non-cacheable endpoint with a Path Traversal Sequence + arbitrary prefix:

Original:  /profile
Modified:  /aaa/..%2fprofile
  • If responses match → origin decodes and resolves dots
  • If responses differ → origin does not normalize; sees the URL as-is

Tip: Encode different URL parts and test variations — small changes or full encoding may yield different behaviors.

Detecting Cache Server Normalization

  1. Identify likely static directories (e.g., /assets)
  2. Find cached requests to those directories (focus on 2xx responses for .js, .css, images)
  3. Modify a known cached request:
Original:  /assets/js/file.js
Modified:  /aaa/..%2fassets/js/file.js
Cache ResponseInterpretation
No longer cachedCache does not normalize
Still cachedCache does normalize

Test variations like /assets/..%2fjs/file.js to fully map behavior.


10. Exploiting normalization

Exploiting Origin Server Normalization

If the origin normalizes (decodes + resolves dots), use this structure:

/<Static-Directory-Prefix>/..%2f<Dynamic-Path>

This structure comes from PortSwigger research — adapt creatively based on conditions.

Exploiting Cache Server Normalization

If the cache normalizes, use this structure (with full encoding since the cache decodes):

/<Static-Directory-Prefix>%2f%2e%2e%2f<Dynamic-Path>
                          │   /../    │

When the Above Isn’t Enough Example:

URL: https://example.com/profile%2f%2e%2e%2fstatic
  • Cache sees /static (normalized)
  • Origin sees the raw path → 404 (resource not found)

Solution: Find a delimiter used by the origin but not the cache, to turn the extra path into a parameter.

Endpoint: /profile;%2f%2e%2e%2fstatic
ServerInterpretation
Origin/profile → ignores ;... as parameter
CacheNormalizes → /static → caches response

The origin returns user info; the cache stores it as a static resource.


11. Exploiting filename cache-rules

Files like robots.txt, index.html, favicon.ico exist on nearly all web servers and are frequently cached due to high request volume.

Testing If a Filename Is Cached

Send multiple GET requests — if responses show cache hits, the file is cached. This can be exploited when origin and cache are out of sync, similar to previous scenarios.

Example (based on cache normalization scenario) Replace the static directory with a known cached filename:

Endpoint: /profile%2f%2e%2e%2findex.html
  • If response is cached → cache interpreted path as /index.html
  • If not cached → cache processed the raw path

Key Constraint for Filename Exploits

Since caching requires the exact filename unchanged in the request, this exploit only works when:

  • Cache normalizes (resolves path traversal)
  • Origin does NOT normalize In plain terms: Cache normalizes; origin does not.

12. Preventing

#Mitigation
1Use Cache-Control: no-store, private headers to prevent caching dynamic content
2Configure cache/CDN to prevent override of cache-related headers
3Leverage CDN security features designed to block such attacks
4Validate Content-Type matches the requested file extension (many CDNs do this)

← Return to OWASP Notes