Skip to content
Security
Skill

/postmessage-xss

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

From plugin
vuln-scout
2435 skills9 agents15 commands
Install
$ npx -y skills add allsmog/vuln-scout --skill postmessage-xss --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/postmessage-xss

Context preview

The summary Claude sees to decide when to auto-load this skill.

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

SKILL.md

postmessage-xss.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

# 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

# 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

# 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

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
Read more
Ships withvuln-scout

AI-powered whitebox penetration testing plugin for Claude Code. 9 languages, 22 skills, 7 autonomous agents. STRIDE threat modeling, OWASP 2025 coverage, polyglot monorepo support.

Get the whole plugin

Other skills on vuln-scout.