Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions src/pentesting-web/postmessage-vulnerabilities/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -232,11 +232,49 @@ For **more information**:
- Link to page about [**XSS**](../xss-cross-site-scripting/index.html)
- Link to page about [**client side prototype pollution to XSS**](../deserialization/nodejs-proto-prototype-pollution/index.html#client-side-prototype-pollution-to-xss)

### Trusted-origin allowlist isn't a boundary

A strict `event.origin` check only works if the **trusted origin cannot run attacker JS**. When privileged pages embed third-party iframes and assume `event.origin === "https://partner.com"` is safe, any XSS in `partner.com` becomes a bridge into the parent:

```javascript
// Parent (trusted page)
window.addEventListener("message", (e) => {
if (e.origin !== "https://partner.com") return
const [type, html] = e.data.split("|")
if (type === "Partner.learnMore") target.innerHTML = html // DOM XSS
})
```

Attack pattern observed in the wild:

1. **Exploit XSS in the partner iframe** and drop a relay gadget so any `postMessage` becomes code exec inside the trusted origin:

```html
<img src="" onerror="onmessage=(e)=>{eval(e.data.cmd)};">
```

2. **From the attacker page**, send JS to the compromised iframe that forwards an allowed message type back to the parent. The message originates from `partner.com`, passes the allowlist, and carries HTML that is inserted unsafely:

```javascript
postMessage({
cmd: `top.frames[1].postMessage('Partner.learnMore|<img src="" onerror="alert(document.domain)">|b|c', '*')`
}, "*")
```

3. The parent injects the attacker HTML, giving **JS execution in the parent origin** (e.g., `facebook.com`), which can then be used to steal OAuth codes or pivot to full account takeover flows.

Key takeaways:

- **Partner origin isn't a boundary**: any XSS in a "trusted" partner lets attackers send allowed messages that bypass `event.origin` checks.
- Handlers that **render partner-controlled payloads** (e.g., `innerHTML` on specific message types) make partner compromise a same-origin DOM XSS.
- A wide **message surface** (many types, no structure validation) gives more gadgets for pivoting once a partner iframe is compromised.

## References

- [https://jlajara.gitlab.io/web/2020/07/17/Dom_XSS_PostMessage_2.html](https://jlajara.gitlab.io/web/2020/07/17/Dom_XSS_PostMessage_2.html)
- [https://dev.to/karanbamal/how-to-spot-and-exploit-postmessage-vulnerablities-36cd](https://dev.to/karanbamal/how-to-spot-and-exploit-postmessage-vulnerablities-36cd)
- To practice: [https://github.com/yavolo/eventlistener-xss-recon](https://github.com/yavolo/eventlistener-xss-recon)
- [Self XSS Facebook Payments](https://ysamm.com/uncategorized/2026/01/15/self-xss-facebook-payments.html)

{{#include ../../banners/hacktricks-training.md}}

Expand Down