# Denial of service to WP-JSON API by cache poisoning the CORS allow origin header

WordPress.com edge cache stores WP-JSON responses with attacker-supplied Origin echoed in Access-Control-Allow-Origin, breaking CORS for legitimate cross-origin consumers.

- Payout: hidden
- Severity: medium
- Program: Automattic
- Found by: nathand
- Disclosed: 2020-04-16
- Write-up quality: 6/10
- Original: https://hackerone.com/reports/591302
- Library page: https://bugbountylibrary.com/r/h1%3A591302
- Tags: area:web domain:web impact:dos kind:bounty platform:hackerone sev:medium tech:rest technique:recon vuln:cache-poisoning vuln:cors vuln:dos

**Target:** WP-JSON REST API endpoint behind edge cache
**Root cause:** WP-JSON echoes the request Origin into Access-Control-Allow-Origin, and the edge cache keys responses without the Origin header, so one origin's response is served to all.
**Steps:**
1. From a non-target HTTPS origin, run `fetch('https://TARGET.com/wp-json/?dontreallypoison1').then(res => res.json()).then(json => console.log(json))` 5-10 times to hit all cache backends.
2. Confirm caching via `X-Cache: hit` on the response.
3. From a different HTTPS origin, run the same fetch.
4. Browser throws CORS error: `Access-Control-Allow-Origin` does not match the new origin, proving poisoned cache.
**How found:** Noticed WP-JSON responses are CORS-aware and echo Origin; hypothesized the edge cache might not key on Origin, then verified by poisoning with a bespoke query string and observing CORS failure from a second origin.
**Exploitation:** Attacker repeatedly requests cached WP-JSON endpoints with a chosen Origin header, poisoning the shared cache; legitimate cross-origin frontends (e.g. headless WordPress, subdomain consumers) then fail CORS checks and cannot load API data.
**Insight:** When a response reflects a request header (Origin, Host, X-Forwarded-*) and is cacheable, test whether the CDN cache key includes that header by poisoning with a unique query string and reading from a different origin/context.

