Skip to content
Back to skills

Postmessage Xss

ASecurity

Detect postMessage handlers that trust unvalidated origins or write attacker-controlled data to dangerous DOM sinks.

  • 24 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added May 26, 2026
developmentjavascriptrustjavabashapisecurity

Works with

  • api

Security analysis

A100/100

Scanned May 27, 2026

npx -y skills add allsmog/vuln-scout --skill postmessage-xss --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Postmessage Xss?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Postmessage Xss
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/allsmog-postmessage-xss/badge)](https://www.skillsdirectory.com/skills/allsmog-postmessage-xss)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: postmessage-xss
description: >-
  Detect postMessage handlers that trust unvalidated origins or write
  attacker-controlled data to dangerous DOM sinks.
version: 1.0.0
---

# DOM XSS via postMessage

This skill covers detecting and exploiting Cross-Origin Messaging (postMessage) vulnerabilities that lead to DOM-based XSS.

---

## Overview

`postMessage` is a browser API that allows cross-origin communication between windows/iframes. When message handlers don't validate `event.origin`, any website can send malicious data that may execute as XSS.

**Why This Is Critical:**
- Often overlooked by security scanners (server-focused)
- Enables XSS from any origin without user interaction
- Commonly chained with SSRF/bot scenarios to bypass localhost restrictions

---

## Vulnerability Pattern

### Vulnerable Code

A handler that accepts messages from ANY origin and writes to DOM:

```
window.addEventListener("message", (event) => {
    const data = event.data;
    document.getElementById("output")[".inner" + "HTML"] = data.html;  // XSS!
});
```

### Secure Code

```
window.addEventListener("message", (event) => {
    if (event.origin !== "https://trusted-domain.com") {
        return; // Reject untrusted origins
    }
    document.getElementById("output").textContent = data.text; // Safe
});
```

---

## Detection Patterns

### Step 1: Find Message Handlers

```bash
# Find all postMessage event listeners
grep -rniE "addEventListener\s*\(\s*['\"]message['\"]" --include="*.js" --include="*.ts" --include="*.html"

# Find direct onmessage assignments
grep -rniE "\.onmessage\s*=" --include="*.js" --include="*.ts"
```

### Step 2: Check for Missing Origin Validation

```bash
# Find handlers and check next 10 lines for origin check
grep -rniE "addEventListener\s*\(\s*['\"]message['\"]" --include="*.js" --include="*.ts" -A 10 | grep -v "origin"
```

### Step 3: Trace to Dangerous Sinks

```bash
# event.data to DOM write sinks
grep -rniE "event\.data.*(inner|outer)HTML" --include="*.js" --include="*.ts"

# event.data to location (open redirect)
grep -rniE "event\.data.*location|location.*event\.data" --include="*.js" --include="*.ts"

# event.data assigned to variable (trace further)
grep -rniE "=\s*event\.data" --include="*.js" --include="*.ts"
```

---

## Common Vulnerable Patterns

| Pattern | Risk | Detection |
|---------|------|-----------|
| No origin check + DOM sink | Critical | Missing `event.origin` validation |
| Weak origin check (regex) | High | `origin.includes()` or `origin.match()` |
| Variable assignment then sink | High | `const data = event.data` then later to sink |
| jQuery `.html()` method | Critical | `$(elem).html(event.data)` |

---

## Exploitation via SSRF + iframe

When combined with SSRF (bot visits attacker URL):

1. Bot visits attacker page
2. Attacker page creates iframe to `http://localhost:1337/`
3. postMessage sends XSS payload to iframe
4. XSS executes in localhost context (bypasses network restrictions)

This chain bypasses Chrome's Private Network Access restrictions.

---

## Remediation

### 1. Always Validate Origin

```javascript
const ALLOWED_ORIGINS = ["https://trusted.com"];

window.addEventListener("message", (event) => {
    if (!ALLOWED_ORIGINS.includes(event.origin)) {
        return; // Reject
    }
    // Process message safely...
});
```

### 2. Use Safe Sinks

- Use `textContent` instead of HTML sinks
- Use DOMPurify to sanitize HTML content
- Validate message structure before processing

### 3. Add Frame Protection

```
X-Frame-Options: SAMEORIGIN
Content-Security-Policy: frame-ancestors 'self'
```

---

## References

- OWASP: DOM-based XSS
- CWE-79: Improper Neutralization of Input
- PortSwigger: DOM-based XSS via postMessage

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.