# Web Cache Deception Attack (XSS)

Unescaped X-Forwarded-Host reflected into font-face CSS/HTML on Discourse, cached for 60s, enabling cache-poisoned stored XSS across many instances.

- Payout: $256
- Severity: high
- Program: Discourse
- Credited: bobrov
- Disclosed: 2018-11-18
- Write-up quality: 7/10
- Original: https://hackerone.com/reports/394016
- Library page: https://bugbountylibrary.com/r/h1%3A394016
- Tags: domain:web impact:integrity kind:bounty platform:hackerone sev:high tech:cdn technique:source-review vuln:cache-poisoning vuln:host-header vuln:xss

**Target:** web app font preload template (_special_font_face.html.erb)
**Root cause:** The X-Forwarded-Host header value is interpolated into woff2_url and marked html_safe without escaping, so attacker-controlled markup lands in the preload link and @font-face src.
**Steps:**
1. Send `GET /?xx HTTP/1.1` with `Host: meta.discourse.org` and `X-Forwarded-Host: cacheattack'"><script>alert(document.domain)</script>`
2. Observe response reflects payload unescaped inside `<link rel=preload href=...>` and `@font-face src: url(...)`
3. Note response is cached ~60s keyed on request line, Accept, Accept-Encoding
4. Poison cache with matching Accept/Accept-Encoding headers, then load cached URL to trigger XSS
**How found:** Researcher noticed X-Forwarded-Host reflected into font preload markup, tested escaping, then observed caching behavior enabling persistence.
**Exploitation:** Attacker sends requests with crafted X-Forwarded-Host and common Accept/Accept-Encoding combos to poison the CDN cache; any victim loading the cached page executes the injected script, yielding stored-XSS-equivalent impact.
**Escalation:** Repeated poisoning every minute across popular header combinations scales to all visitors of affected pages.
**Insight:** Headers like X-Forwarded-Host used to build asset URLs are often interpolated into CSS/HTML with html_safe; check font/preload templates and whether responses are cacheable to upgrade reflected XSS to cache-poisoned stored XSS.
