# Cache key includes attacker-controlled variable

Does a cache key or Vary depend on callback names, header counts, or reflected request values?

_Area: Web infrastructure and server-side requests. Seen in 2 disclosed reports; 2 confirmed bounties: $1,120 and $1,250; latest 2025-11-18. Updated 2026-11-01._

## How it works
A cache stores a response under a key. If any part of that key is attacker-influenced (a JSONP callback name, a header count, a reflected parameter), the attacker can make the same underlying content land under many keys, or make a security-relevant input fall outside the key entirely. The broken assumption is that the cache key covers everything that changes the response, and that every request is fully evaluated before caching. When a proxy truncates parsing (header count) or a key varies per request, responses get stored or served under conditions the origin never intended.

## Where it shows up
- JSONP/JSON endpoints embedding a per-request callback name in the URL [E2](https://bugbountylibrary.com/r/h1%3A263760.md)
- Documented header-truncation fields (e.g. `http.request.headers.truncated`) or fixed header-parse limits in OpenResty/nginx front ends [E1](https://bugbountylibrary.com/r/h1%3A3027461.md)
- Reflected parameters echoed into cached responses (boardURI/applicationURI style) [E3](https://bugbountylibrary.com/r/h1%3A350847.md)
- Length limits applied after decoding, where multi-byte chars expand byte length [E3](https://bugbountylibrary.com/r/h1%3A350847.md)
- `Vary` headers or cache rules that key on request-derived values

## How to review
Identify the exact cache key and every input that changes the response body. The invariant: every input that alters the response must be in the key, and every security control (WAF, cache rule) must run on the full request, not a truncated view. Check whether header-count limits cause keyed headers to be dropped from evaluation [E1](https://bugbountylibrary.com/r/h1%3A3027461.md). Check whether callback/index parameters vary the key while content stays stale [E2](https://bugbountylibrary.com/r/h1%3A263760.md). Check whether reflected values can exceed the origin's byte limit after decoding [E3](https://bugbountylibrary.com/r/h1%3A350847.md).

## How finders spotted it
- Noticed a preview returned more tweets than expected for a private profile, saw the JSONP callback name varied per request, and hypothesized the cache key included it [E2](https://bugbountylibrary.com/r/h1%3A263760.md)
- Read Cloudflare's documented header-truncation behavior and the 100-header OpenResty limit, then placed keyed headers after an overflow to see if evaluation was skipped [E1](https://bugbountylibrary.com/r/h1%3A3027461.md)
- Knew a prior fix limited URI length after decoding, hypothesized multi-byte chars expand to many encoded bytes, and tested with repeated characters [E3](https://bugbountylibrary.com/r/h1%3A350847.md)

## Variants seen
- Header-count overflow dropping cache-key and WAF evaluation [E1](https://bugbountylibrary.com/r/h1%3A3027461.md)
- JSONP callback name in cache key exposing stale private/deleted data [E2](https://bugbountylibrary.com/r/h1%3A263760.md)
- Post-decode length limit bypassed via UTF-8 amplification, re-enabling cache poisoning [E3](https://bugbountylibrary.com/r/h1%3A350847.md)

## Why fixes fail
E3 shows an incomplete fix: a 1024-char limit applied after decoding was bypassed because multi-byte characters expand up to 12 URL-encoded bytes each, still exceeding the server's ~6169-byte limit.

## Impact and severity
E1 chained cache-key bypass with WAF bypass and origin header reflection to reach stored XSS affecting all Cloudflare customers. E2 exposed private and deleted tweets via stale cached snapshots. E3 caused DoS through cache poisoning of embed JS. Impact rose when the cache flaw combined with another weakness (WAF bypass, reflection) or reached shared infrastructure.

## Evidence
- E1: https://bugbountylibrary.com/r/h1%3A3027461.md
- E2: https://bugbountylibrary.com/r/h1%3A263760.md
- E3: https://bugbountylibrary.com/r/h1%3A350847.md
