Postmessage Xss
npx machina-cli add skill allsmog/vuln-scout/postmessage-xss --openclawDOM 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):
- Bot visits attacker page
- Attacker page creates iframe to
http://localhost:1337/ - postMessage sends XSS payload to iframe
- 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
textContentinstead 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
Source
git clone https://github.com/allsmog/vuln-scout/blob/main/whitebox-pentest/skills/postmessage-xss/SKILL.mdView on GitHub Overview
This skill covers detecting and exploiting Cross-Origin Messaging (postMessage) vulnerabilities that lead to DOM-based XSS. It explains how handlers that don’t validate event.origin can be abused to inject malicious data into the DOM from any origin, enabling XSS without user interaction.
How This Skill Works
postMessage enables cross-origin communication between windows and iframes. If a message handler accepts event.data from any origin and writes it directly to DOM sinks (for example via innerHTML), an attacker can inject and execute malicious HTML. Secure handling requires validating event.origin against a whitelist and using safe sinks such as textContent or HTML sanitization before insertion.
When to Use It
- Auditing web apps that embed third-party widgets or iframes and rely on postMessage
- Testing for XSS when messages may originate from untrusted sources
- Reviewing code paths that use insecure origin checks (e.g., weak or regex-based checks)
- Investigating SSRF/bot chains that leverage postMessage to reach localhost or internal frames
- During secure code reviews for cross-origin messaging implementations
Quick Start
- Step 1: Find all postMessage listeners (addEventListener('message') and onmessage handlers)
- Step 2: Check for origin validation; flag missing or weak checks and dangerous sinks (innerHTML, location)
- Step 3: Replace with safe patterns (validate origin, use textContent or sanitize HTML) and add frame protections
Best Practices
- Validate event.origin against an explicit whitelist on every message
- Use safe DOM insertion: prefer textContent over innerHTML, or sanitize HTML with DOMPurify
- Validate the message structure and type before processing (not just data length)
- Avoid assigning event.data directly to DOM sinks; implement strict processing routines
- Apply frame protections and origin enforcement: X-Frame-Options and frame-ancestors CSP; restrict origins and targets
Example Use Cases
- Handler accepts any origin and writes data.html to innerHTML (XSS risk)
- Weak origin check implemented with origin.includes() bypassed by crafted origins
- event.data directly assigned to DOM (innerHTML or outerHTML) without sanitization
- Using jQuery .html(event.data) as a sink for untrusted data
- SSRF/bot-driven iframe chain reaching localhost, using postMessage to inject XSS payload