# XSS and cache poisoning via upload.twitter.com on ton.twitter.com

upload.twitter.com accepted unknown file extensions, served them without Content-Type, enabling browser-sniffed XSS and AppCache poisoning on ton.twitter.com.

- Payout: hidden
- Severity: high
- Program: X / xAI
- Found by: filedescriptor
- Disclosed: 2019-05-01
- Write-up quality: 7/10
- Original: https://hackerone.com/reports/84601
- Library page: https://bugbountylibrary.com/r/h1%3A84601
- Tags: area:web domain:web impact:integrity kind:bounty platform:hackerone sev:high technique:chained vuln:cache-poisoning vuln:file-upload vuln:xss

**Target:** upload.twitter.com audience-data upload endpoint / ton.twitter.com
**Root cause:** Upload validation only rejects known-bad extensions; unknown extensions pass and are served without a Content-Type header, so browsers sniff HTML and execute it.
**Steps:**
1. Go to Twitter Ads > Tools > Audience manager > Create new list audience
2. Upload a normal file under 'Upload your data file' and intercept the request
3. Change `blobstore_url` suffix from e.g. `1440354519600.txt` to `1440354519600.test`
4. Replace `content` with `<script>alert(1)</script>`
5. Uploaded file now contains XSS and is served without Content-Type
6. Sign the file URL with an OAuth token so victims can access it
**How found:** Noticed that `foobar.html` was rejected but `foobar.test` passed, then observed the response lacked a Content-Type header, leading to browser MIME sniffing.
**Exploitation:** Attacker uploads HTML/JS payload under an unrecognized extension, signs the resulting URL with an OAuth token, and lures victims to it; browser sniffs and executes the script in ton.twitter.com origin. An HTML5 AppCache manifest can then be uploaded to persist the payload and override other ton.twitter.com content in the victim's browser.
**Escalation:** Chained XSS with AppCache manifest upload to achieve persistent XSS and control of all content returned on ton.twitter.com from the victim's browser.
**Insight:** When upload filters blocklist known-bad extensions, try arbitrary/unknown extensions; if the server omits Content-Type for unrecognized types, browsers sniff and may render HTML/JS. Also test whether uploaded files can be served as AppCache manifests to persist and override content.

