Skip to main content

postMessage Receiver Without Origin Validation

A cross-document message listener trusts event.data without ever checking event.origin, so any page that can get a handle on the window may post into it. When the message data reaches a DOM sink the bug becomes a DOM XSS or an open-navigation primitive.

What Vulkro detects

POSTMSG-001 (Medium) fires on a window.addEventListener('message', ...) or window.onmessage = ... handler whose body performs no origin validation. Confidence is raised to High when the body also writes attacker-controlled data into a DOM sink. Severity stays Medium because the trusted origin is application-specific and this is a shape heuristic, not a taint proof.

This rule deliberately covers the receiver side only. The send-side wildcard target origin (postMessage(data, '*')) is owned by other detectors.

How it reads the code: the detector walks every file under the scan root once and only parses JS/TS-family files (.js, .jsx, .ts, .tsx, .mjs, .cjs, .vue, .svelte) that actually contain a message listener. It is a textual shape pass, so it reads the handler body and skips any handler that references an origin comparison. Named-function and single-expression handlers, whose body is not inline, are only flagged when the whole file contains no origin validation at all.

Remediation. Compare event.origin against an exact expected origin string before touching event.data, return early on a mismatch, and validate the message payload shape as well. An origin allowlist belongs in a constant, not in a regular expression built from a wildcard.

Non-compliant code (examples)

Browser - message handler with no origin check

window.addEventListener('message', (event) => {
document.getElementById('panel').innerHTML = event.data.html; // any origin can post
});

Compliant code (examples)

Browser - exact origin check plus payload validation

const TRUSTED_ORIGIN = 'https://widget.example.com';
window.addEventListener('message', (event) => {
if (event.origin !== TRUSTED_ORIGIN) return;
if (typeof event.data?.text !== 'string') return;
document.getElementById('panel').textContent = event.data.text;
});

See also

  • Confidence model - what High, Medium, and Low mean for findings in this category.
  • Safety - what Vulkro does and does not access on your machine.

References


This page is generated by vulkro rules export <out-dir> from Vulkro's built-in detector catalogue. Edits made by hand are overwritten on the next regeneration.