# XSS via postMessage in chat.mozilla.org

Matrix usercontent iframe trusted a postMessage origin taken from the URL query, letting an attacker inject an HTML blob and execute XSS on chat.mozilla.org.

- Payout: $500
- Severity: medium
- Program: Mozilla
- Credited: Guilherme Keerok
- Disclosed: 2021-05-20
- Write-up quality: 7/10
- Original: https://keerok.github.io/2021/05/09/XSS-via-postMessage-in-chat-mozilla-org-CVE-2021-21320/
- Library page: https://bugbountylibrary.com/r/blog%3Akeerok-github-io-2021-05-09-xss-via-postmessage-in-chat-mozilla-org-cve-2021-21320
- Tags: domain:web impact:integrity kind:bounty platform:blog sev:medium tech:websocket technique:js-analysis technique:source-review vuln:xss

**Target:** Matrix usercontent iframe (matrix-react-sdk)
**Root cause:** The iframe's lockOrigin was parsed from the attacker-controllable `origin` query parameter, so any origin could satisfy the postMessage check. The received blob was passed to createObjectURL without content-type validation.
**Steps:**
1. Read matrix-react-sdk src/usercontent/index.js; note lockOrigin comes from `window.location.search` `origin` param.
2. Open `https://chat.mozilla.org/usercontent/?origin=https%3a%2f%2f<attacker-domain>` so lockOrigin equals attacker origin.
3. From attacker page, `x.postMessage({blob: new Blob(["<script>alert(1337)</script>"],{type:"text/html"}), imgSrc: "<image telling user to open in new tab>", auto:true}, "*")`.
4. Iframe sets `a.href = createObjectURL(blob)` with `a.download`, so user right-clicks image and opens in new tab, executing the HTML blob.
**How found:** Source review of the open-source Matrix webchat; noticed file previews rendered in an iframe via postMessage and traced how the iframe validated message origin, spotting it was read from the URL query.
**Exploitation:** Attacker lures victim to a page that opens the usercontent iframe with origin set to the attacker domain, then postMessages an HTML blob plus a decoy image instructing the victim to open it in a new tab; the blob renders as HTML and runs script in the chat.mozilla.org origin.
**Insight:** When an iframe validates postMessage via `e.origin === lockOrigin`, check where lockOrigin comes from — if it's parsed from the iframe's own URL query, the check is attacker-controlled. Also watch createObjectURL on user-supplied blobs lacking content-type checks.
