# Stored XSS in blog comments through Shopify API

Shopify comment update API accepted an undocumented body_html field, storing unsanitized HTML that executed as stored XSS in the storefront and admin panel.

- Payout: hidden
- Severity: medium
- Program: Shopify
- Found by: prakharprasad
- Disclosed: 2017-03-16
- Write-up quality: 6/10
- Original: https://hackerone.com/reports/192210
- Library page: https://bugbountylibrary.com/r/h1%3A192210
- Tags: area:web domain:api domain:web impact:integrity kind:bounty platform:hackerone sev:medium tech:rest technique:source-review vuln:xss

**Target:** /admin/comments/<id>.json API endpoint and blog comment rendering
**Root cause:** The comment update API accepted an undocumented body_html parameter and stored it without sanitization, unlike the web comment form which strips HTML.
**Steps:**
1. Post a comment on a blog post via browser and note the comment id from HTML like `<div id="comment-2929551246" ...>`
2. Create an app with comment permission on the shop
3. Send JSON to `/admin/comments/<comment-id>.json` with `{"comment":{"id":<comment-id>,"body":"blahblah","body_html":"blah<img src=x onerror=alert(0);>"}}`
4. Send the request twice
5. Visit the blog post; the injected JS executes
**How found:** Researcher noticed web-posted comments are sanitized, hypothesized the API path might not sanitize, and tried adding an undocumented body_html field to the update request.
**Exploitation:** An app with comment permission updates a comment supplying body_html containing an img onerror payload; the stored HTML renders and executes in the storefront blog and in the Shopify admin comment view.
**Escalation:** Payload also executes in the admin panel when viewing comments, raising impact from storefront to admin-context XSS.
**Insight:** When a UI sanitizes a field, probe the backing API for undocumented sibling fields (e.g. body_html alongside body) that bypass the sanitizer; sending twice can be needed for the stored value to render.

