Engineering Journal
Schema Editor
Schema Editor

postMessage With '*' Origin Sends Your Messages to Everyone. Use window.location.origin.

2026-06-04

TLDR

Using window.parent.postMessage(data, '') in iframe-embedded tools, VS Code webviews, or Electron apps disables browser target origin validation. Passing '' allows any embedding frame on any domain to inspect outgoing messages, a documented OWASP security misconfiguration (A07:2021). Replacing '*' with window.location.origin (or specific domain strings) and validating e.origin on receivers ensures secure cross-frame data transport.
Messaging ModelTarget Origin ParameterReceiver Origin ValidationSecurity Assessment
Wildcard PostMessage'*' (Delivers to any domain)None (addEventListener unfiltered)Vulnerable (OWASP A07:2021)
Origin-Restricted Bridgewindow.location.originStrict e.origin checkSecure & Isolated

Problem statement: the wildcard PostMessage fallacy

Developers building webview extensions or embedded iframe tools frequently pass '*' as the target origin in postMessage calls during early prototyping:

// VULNERABLE: Wildcard target origin allows any embedding parent to intercept data
window.parent.postMessage({ type: 'tool:ready', payload: sessionData }, '*');

Tutorials recommend '' under the guise of "use this when you don't know the parent's origin."*

In reality, passing '*' creates an open broadcast channel, bypassing the browser's same-origin policy.


Technical failure mode: data leakage to malicious parent frames

If an application is loaded inside a hidden <iframe> on a malicious website, any postMessage(data, '*') call delivers its payload directly to the malicious parent frame. If the payload contains user credentials, document structures, or session tokens, the embedding page can intercept them silently.


The fix & architecture: centralized bridge wrapper & strict validation

Step 1: restrict target origins

Replace '*' with window.location.origin for same-origin communication, or explicit origin URLs for cross-domain parents:
// REFACTORED: Restrict delivery strictly to same-origin parent frames
window.parent.postMessage({ type: 'tool:ready' }, window.location.origin);

Step 2: receiver origin verification

Validate e.origin on all incoming message event listeners:
// REFACTORED: Incoming message origin verification
const ALLOWED_ORIGINS = new Set([
  window.location.origin,
  'vscode-webview://' // VS Code extension host scheme
]);

window.addEventListener('message', (e) => { const isAllowed = [...ALLOWED_ORIGINS].some(origin => e.origin.startsWith(origin)); if (!isAllowed) return; // Reject unauthorized origins!

handleMessage(e.data); });

Step 3: centralized typed bridge module

Route all cross-frame messaging through a single bridge utility to eliminate ad-hoc postMessage calls across the codebase:
// Centralized Security Bridge
export const Bridge = {
  targetOrigin: window.location.origin,

send(type, payload) { window.parent.postMessage({ type, payload }, this.targetOrigin); },

onMessage(handler) { window.addEventListener('message', (e) => { if (e.origin !== this.targetOrigin && !e.origin.startsWith('vscode-webview://')) return; handler(e.data); }); } };

Rule of thumb: Never use '*' as a target origin in postMessage. Route all cross-frame communication through a centralized bridge wrapper that enforces target origin matching and receiver verification.
Read this post in the full Engineering Journal →