cloudflare / cloudflare/cloudflare-docs

Cache Deception Armor: undocumented .js / application/json exception allows Web Cache Deception

Open
#28,820 2 comments 0 reactions 0 assignees View on GitHub
content:edit documentation product:cache stale
Dominant language
MDX
Stars
5.2k
Forks
16.7k
Avg merge
2d 6h
Merged PRs (30d)
337

Description

### Existing documentation URL(s)

- https://developers.cloudflare.com/cache/cache-security/cache-deception-armor/

### What changes are you suggesting?

## Description

The [Cache Deception Armor (CDA) documentation](https://developers.cloudflare.com/cache/cache-security/cache-deception-armor/) states that CDA *"will verify a URL's extension matches the returned Content-Type"* and *"when a mismatch that could result in a Web Cache Deception attack is found, Cloudflare does not cache the response."*

However, CDA does **not** block caching when a `.js` URL returns `Content-Type: application/json`. This exception is not listed in the [documented exceptions](https://developers.cloudflare.com/cache/cache-security/cache-deception-armor/#exceptions), leaving customers unaware that CDA does not protect against this specific mismatch.

## Current documented exceptions

- `application/octet-stream` for any extension
- `.jpg` served as `image/webp`
- `.gif` served as `video/webm`
- *"other cases that we think are unlikely to be attacks"*

## Missing exception

- **`.js` served as `application/json`** - CDA treats these as compatible and does not block caching.

## Why this matters

- `application/json` responses are the **primary target** of Web Cache Deception attacks (session tokens, PII, API keys)
- Cloudflare intentionally excludes `.json` from the [default cached file extensions](https://developers.cloudflare.com/cache/concepts/default-cache-behavior/#default-cached-file-extensions) because JSON carries sensitive data
- Customers enabling CDA reasonably expect it to block `.js` + `application/json` mismatches, since it blocks all other tested extension/Content-Type mismatches (`.css`, `.jpg`, `.png`, `.gif`, `.svg`, `.ico`, `.pdf`)
- Without documentation, customers have no way to know they need additional mitigation for this case

## Verified behavior

Tested with CDA enabled (`cache_deception_armor: true`) and Origin Cache Control active:

| Extension | Origin Content-Type | `cf-cache-status` | CDA Result |
|-----------|--------------------|--------------------|------------|
| `.css` | `application/json` | `BYPASS` | Blocked (documented) |
| `.jpg` | `application/json` | `BYPASS` | Blocked (documented) |
| `.png` | `application/json` | `BYPASS` | Blocked (documented) |
| `.gif` | `application/json` | `BYPASS` | Blocked (documented) |
| `.svg` | `application/json` | `BYPASS` | Blocked (documented) |
| `.ico` | `application/json` | `BYPASS` | Blocked (documented) |
| `.pdf` | `application/json` | `BYPASS` | Blocked (documented) |
| **`.js`** | **`application/json`** | **`MISS → HIT`** | **Not blocked (undocumented)** |

The same behavior applies to `application/json; charset=utf-8`.

## Suggested documentation update

Add the following bullet to the [Exceptions section](https://developers.cloudflare.com/cache/cache-security/cache-deception-armor/#exceptions):

> Cloudflare allows `.js` to be served as `application/json`, because JSON is considered syntactically compatible with JavaScript. If your origin returns sensitive JSON API responses on paths that could end in `.js`, set `Cache-Control: no-store` or `Cache-Control: private` on those responses to prevent caching.

## File to update

`src/content/docs/cache/cache-security/cache-deception-armor.mdx` — Exceptions section.

### Additional information

_No response_

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.