# XSS on hardware.shopify.com

Nested array in properties[builder_id] on Shopify cart/add rendered as JSON into HTML attributes, enabling stored XSS via onmouseover on product pages.

- Payout: hidden
- Severity: high
- Program: Shopify
- Found by: virtualhunter
- Disclosed: 2016-04-09
- Write-up quality: 6/10
- Original: https://hackerone.com/reports/123125
- Library page: https://bugbountylibrary.com/r/h1%3A123125
- Tags: area:web domain:web impact:ato kind:bounty platform:hackerone sev:high tech:php technique:param-pollution technique:source-review vuln:xss

**Target:** cart/add endpoint on *.shopify.com storefronts
**Root cause:** The cart/add endpoint accepts properties[builder_id] as a nested array; cart.js serializes the two-level array as a JSON object ({"second_parameter":"value"}) and injects it unescaped into HTML attributes (tr/div/a/insert tags), breaking out of the attribute context.
**Steps:**
1. Send a request to `*.shopify.com/cart/add` with `properties[builder_id][%20onmouseover%3dalert(document.cookie)%20]=value` alongside a valid product id.
2. The two-level array is stored and later rendered by cart.js as `"builder_id":{" onmouseover=alert(document.cookie) ":"value"}` inside an HTML tag attribute.
3. Victim visits the crafted cart URL; hovering the product triggers the injected handler.
**How found:** Noticed that supplying a second array level to properties[builder_id] produced corrupted HTML tags because cart.js serializes the nested array as a JSON object rather than a flat string, revealing an attribute-injection sink.
**Exploitation:** Attacker crafts a cart/add URL with a nested properties[builder_id] array whose key contains an event handler; the value is persisted to the victim's cart and rendered unescaped in cart.js HTML, executing on mouseover for any visitor (stored, unauthenticated).
**Insight:** When a parameter is expected to be a scalar but the backend accepts arrays, check how the client-side JS serializes nested structures into HTML — a two-level array can become a JSON object whose keys land inside an attribute, giving attribute injection without needing quote-breaking.

