Fix guide · high · postmessage_wildcard_target

window.postMessage() called with target origin '*'

What this rule means

Code in your bundle calls postMessage(data, '*'). The wildcard target means the browser will deliver the message to whatever origin currently owns the receiving window — including attacker-controlled origins if the receiver navigated away mid-flow.

Why it matters

postMessage's second argument is the *target origin* — the browser uses it to decide whether to deliver the message. Passing '*' means "deliver to whoever owns this window right now, regardless of origin."

The common scenario that turns this into a real bug:

  1. Your page opens a popup or iframe to start a flow (OAuth, payment, SSO).
  2. The flow finishes; the child window calls window.opener.postMessage(authResult, '*') to hand the result back.
  3. Between steps 1 and 2, the child window navigated somewhere else — to an attacker's site (via open-redirect chain), or to a buggy intermediate page that ended up under attacker control, or to a slow-loading provider page where the user got bored and typed a new URL.
  4. The message is delivered to the new origin. The attacker harvests the auth token, payment confirmation, or session ID.

Because '*' accepts any receiver, the bug surface includes any code-path that lets an attacker influence which document loads in the target window. Even seemingly-innocent navigation patterns (Sign in → email confirmation → back to app) can introduce a window where the wrong origin owns the receiving frame.

Real-world precedent: the 2017 Facebook OAuth issue, multiple disclosed wallet/extension bugs in 2021–2024, and most of the "OAuth flow harvested my token" disclosure pattern reduce to wildcard-target postMessage calls in the popup-completion handler.

How to fix it

Replace '*' with the specific expected origin string.

// BAD
window.opener.postMessage(authResult, '*');

// GOOD
window.opener.postMessage(authResult, 'https://app.example.com');

If you don't know the exact origin at message-send time, you have a deeper structural problem — your flow shouldn't be sending tokens to unknown origins.

For popup-based OAuth flows specifically:

  1. The opener page should pass its origin to the popup via the URL: /auth/start?return_origin=${encodeURIComponent(window.location.origin)}.
  2. The popup's completion handler validates that the returned origin is on an allowlist (NEVER just trusts the parameter).
  3. The popup posts back with the validated specific origin: window.opener.postMessage(authResult, validatedOrigin).

On the receiver side, ALWAYS check event.origin (see /fix/postmessage_listener_no_origin_check). Receiver-side validation is the defense-in-depth check that catches even sender-side bugs.

Did vibecheck flag this on your app?

If you reached this page from a vibecheck inspection report, the redacted match in your scan output is the exact string we found in your bundle. After applying the fix above, run the inspection again — the finding should clear.

Run another inspection