# DOM XSS on multiple Automattic domains through postMessages

DOM XSS on widgets.wp.com plus Jetpack Likes' unvalidated postMessage avatar_URL innerHTML sink yields XSS on 100k+ WordPress sites.

- Payout: hidden
- Severity: high
- Program: Automattic
- Found by: renniepak
- Disclosed: 2024-02-26
- Write-up quality: 8/10
- Original: https://hackerone.com/reports/2371019
- Library page: https://bugbountylibrary.com/r/h1%3A2371019
- Tags: area:web domain:web impact:integrity kind:bounty platform:hackerone sev:high tech:wordpress technique:chained technique:source-review vuln:misconfiguration vuln:xss

**Target:** widgets.wp.com sharing-buttons-preview and Jetpack Likes postMessage listener
**Root cause:** sharing-buttons-preview template injects the custom[0][name] param unescaped into DOM; Jetpack Likes listener trusts widgets.wp.com origin and writes liker.avatar_URL into innerHTML without encoding.
**Steps:**
1. Open `https://widgets.wp.com/sharing-buttons-preview/?custom[0][icon]=iconurl&custom[0][name]=%22%3E%3Cimg%20src%20onerror=alert()%3E` to confirm DOM XSS on widgets.wp.com.
2. On a Jetpack Likes-enabled site, the page registers a postMessage listener accepting only origin `https://widgets.wp.com`.
3. From the XSS'd widgets.wp.com context, postMessage a `showOtherGravatars` payload with `liker.avatar_URL` set to `"><img src onerror=alert(document.domain)>`.
4. Listener writes avatar_URL into innerHTML, executing script in the target site's origin.
**How found:** Reading minified preview.js revealed custom[0][icon]/[name] params rendered via _.template into DOM; then code review of Jetpack Likes listener showed origin check on widgets.wp.com and avatar_URL written to innerHTML, suggesting chaining the two.
**Exploitation:** Attacker hosts a page that opens widgets.wp.com with the crafted custom[0][name] payload (XSS on trusted origin), then from that frame sends a postMessage to the victim Jetpack Likes site with a malicious avatar_URL, achieving script execution in the victim domain.
**Escalation:** Chaining the widgets.wp.com XSS with the origin-trusting postMessage listener turns a single-domain XSS into XSS across 100k+ sites using Jetpack Likes.
**Insight:** When a widget/iframe origin is whitelisted by postMessage listeners, hunt for XSS on that trusted origin to bypass the origin check; also grep for innerHTML sinks fed by postMessage fields like avatar_URL.
