# Stored XSS in https://productreviews.shopifyapps.com/proxy/v4/reviews/product

Stored XSS via product title reflected in JSONP endpoint lacking Content-Type header, letting attacker-controlled shop render HTML/JS in victim browser.

- Payout: hidden
- Severity: high
- Program: Shopify
- Found by: zombiehelp54
- Disclosed: 2019-11-08
- Write-up quality: 6/10
- Original: https://hackerone.com/reports/168458
- Library page: https://bugbountylibrary.com/r/h1%3A168458
- Tags: area:web domain:web impact:integrity kind:bounty platform:hackerone sev:high tech:rest technique:source-review vuln:xss

**Target:** productreviews.shopifyapps.com /proxy/v4/reviews/product JSONP endpoint
**Root cause:** Endpoint returns JSON without a Content-Type header when the `callback` param is absent, so browsers sniff it as text/html; attacker-controlled product title is embedded unescaped.
**Steps:**
1. Create a product in attacker shop `zh5403-attacker.myshopify.com` with an XSS payload in the title, note product_id `8254331011`.
2. Request `https://productreviews.shopifyapps.com/proxy/v4/reviews/product?product_id=8254331011&version=v4&shop=zh5403-attacker.myshopify.com&_=cache` (no `callback`) so response lacks Content-Type and is sniffed as text/html.
3. Payload in product title executes in the productreviews.shopifyapps.com origin.
**How found:** Noticed that adding `callback` set Content-Type: application/javascript while omitting it dropped the Content-Type header entirely, causing HTML sniffing of attacker-controlled JSON content.
**Exploitation:** Attacker hosts a product with a script payload in its title; victim visiting the crafted URL on the Shopify apps domain executes attacker JS in that origin.
**Insight:** On JSONP/JSON endpoints, test behavior with and without the callback param: missing Content-Type enables MIME sniffing to text/html, turning reflected/stored JSON fields into XSS.

