# Inject page in admin panel via Shopify.API.pushState

DOM XSS via Shopify.API.pushState path traversal in adminPath lets an attacker page load a storefront page into the admin iframe and execute script in admin context.

- Payout: $500
- Severity: low
- Program: Shopify
- Credited: tiago-danin
- Disclosed: 2019-09-09
- Write-up quality: 7/10
- Original: https://hackerone.com/reports/662083
- Library page: https://bugbountylibrary.com/r/h1%3A662083
- Tags: domain:web impact:ato kind:bounty platform:hackerone sev:low tech:rest technique:chained technique:source-review vuln:path-traversal vuln:xss

**Target:** Shopify admin panel route handler (Shopify.API.pushState / handleRoutePushEvent)
**Root cause:** handleRoutePushEvent concatenates adminPath ('/admin') with attacker-controlled pathname without normalizing '..' segments, so '/admin/../pages/xss' resolves to '/pages/xss' and loads a non-admin page into the admin AppFrameMain.
**Steps:**
1. Create a storefront page at /pages/xss containing a <script> that reads document.cookie and the csrf serialized element.
2. Create a second page /pages/xss-play whose script opens `window.open(location.origin+'/admin/themes','_blank')` and repeatedly `ctx.postMessage(JSON.stringify({message:'Shopify.API.pushState',data:{pathname:'/../pages/xss'}}))`.
3. Visit https://[store].myshopify.com/pages/xss-play and click the attack link.
4. Admin window receives the postMessage, pushState resolves to /pages/xss, and the XSS payload executes inside the admin AppFrameMain with admin session access.
**How found:** Noticed handleRoutePushEvent concatenates adminPath with pathname; hypothesized '..' segments would traverse out of /admin and load arbitrary storefront pages into the admin frame.
**Exploitation:** Attacker hosts a storefront page that opens the admin panel in a new window and spams postMessage with a crafted Shopify.API.pushState message using pathname '/../pages/xss'. The admin route handler concatenates '/admin' + pathname, traversal escapes to the storefront page, which is loaded into the admin iframe and executes in the admin origin, exposing CSRF token and store config.
**Insight:** When a SPA route handler concatenates a fixed base path with a user-controlled pathname, test '..' traversal to escape the privileged namespace and load attacker-controlled pages into the privileged frame; postMessage handlers accepting route commands are a prime vector.
