# CSRF-tokens on pages without no-cache headers, resulting in ATO when using CloudFlare proxy (Web Cache Deception)

Discourse pages exposing CSRF tokens lacked no-cache headers, letting CloudFlare cache them and enabling account takeover via email change.

- Payout: hidden
- Severity: low
- Program: Discourse
- Found by: fransrosen
- Disclosed: 2018-08-08
- Write-up quality: 8/10
- Original: https://hackerone.com/reports/260697
- Library page: https://bugbountylibrary.com/r/h1%3A260697
- Tags: area:web domain:web impact:ato kind:bounty platform:hackerone sev:low tech:cdn technique:chained vuln:account-takeover vuln:cache-deception vuln:csrf

**Target:** Discourse web app behind CloudFlare proxy (user routes /u/*)
**Root cause:** Routes rendering the user's CSRF token and X-Discourse-Username header (including 404 pages) send no Cache-Control/Pragma/Expires headers, so CloudFlare caches user-specific responses when a cacheable extension like .css is appended.
**Steps:**
1. Victim signed in to Discourse behind CloudFlare visits attacker page.
2. Page loads `img` tags to `/u/$rand.css` three times, tainting the CloudFlare cache with the victim's CSRF token and username.
3. Attacker's PHP script (same CloudFlare region) fetches `/u/$rand.css` server-side and gets `CF-Cache-Status: HIT` with the victim's token.
4. Extract username from `X-Discourse-Username` header and token from `<meta name="csrf-token" content="...">`.
5. Submit `POST /users/$username/preferences/email.json` with body `_method=PUT&email=$attacker_email&authenticity_token=$csrf_token`.
6. Attacker clicks verification email; victim's account email is now attacker-controlled.
**How found:** Noticed a client's Discourse behind CloudFlare; observed that appending `.css` to user routes still returned 200/404 with CSRF token and username, and that responses lacked cache headers, so CloudFlare cached them (CF-Cache-Status: HIT).
**Exploitation:** Attacker lures signed-in victim to a malicious page that requests `/u/<rand>.css` via img tags to poison the CloudFlare regional cache with the victim's CSRF token and username. A server-side PHP fetcher in the same CloudFlare region retrieves the cached response, extracts token and username, and the page issues a credentialed XHR to change the victim's email, leading to account takeover after verification.
**Escalation:** CSRF token leak chained with email-change endpoint yields full account takeover; only 13 CloudFlare regions makes co-region fetching practical.
**Insight:** Appending cacheable static extensions to authenticated dynamic routes can trick CDN caches into storing per-user secrets; check whether token-bearing pages and error pages emit Cache-Control/Pragma headers.

