What are the concrete risks of calling `window.postMessage(data, '*')` with a wildcard `targetOrigin`, and when is `'*'` genuinely acceptable?
answer
- who else could be listening
- the window may have navigated
- wildcard skips the delivery check
- '/' means same origin as sender
- never wildcard a token
basics
~20 sA wildcard targetOrigin tells the browser to deliver the message no matter which origin the receiving window is on, so if that window navigated or was replaced, the payload lands in a stranger's page. Use '*' only for data that is safe to publish.
solid answer
~50 s`targetOrigin` is a delivery-time check: the browser compares the receiving window's *current* origin with the string you passed and drops the message on a mismatch. Passing `'*'` removes that check, so the message goes wherever that window now points. Windows move — a popup you opened follows a redirect chain, a frame's `src` is changed by a third party, an OAuth flow bounces through an identity provider — and none of that is visible from your side. If the payload holds a token, a session identifier, or user data, `'*'` turns a race into a disclosure. `'*'` is defensible only when the payload is genuinely public, typically a widget bootstrap that must work on customer origins it does not know. Even then, send a non-secret handshake with `'*'`, learn the peer's origin from `event.origin`, and address every later message explicitly.
go deeper
Know that the second argument is required and that '*' means any origin. Get in the habit of writing the exact origin string, scheme and host and port, with no path.
Explain that the check happens at delivery against the receiving window's current origin, and give a concrete way a window changes origin under you: a popup following a redirect, or a frame whose src another script rewrote.
Show the bootstrap pattern you would ship for a widget that cannot know its embedder: a non-secret hello with '*', then pin every later message to the origin the browser reported on the reply.
Frame it as a data-classification decision. Decide which payloads may ever cross a window boundary at all, publish that rule for the teams shipping embeds, and treat a wildcard carrying anything user-specific as a review-blocking defect.
## What targetOrigin actually does `otherWindow.postMessage(message, targetOrigin)` takes a mandatory second argument. It is not documentation and not a hint: at delivery time the user agent compares `targetOrigin` against the origin of the document currently loaded in `otherWindow`. If they differ, the message is discarded — no exception thrown to the sender, no `message` event fired at the receiver. The argument exists purely to protect the **sender's confidentiality**. Three forms are legal: - an explicit serialized origin, `'https://widget.example.com'` — scheme, host and port only, never a path; - `'/'` — deliver only if the receiving window's origin is identical to the sender's; - `'*'` — deliver unconditionally. The same values apply in the options form, `postMessage(message, { targetOrigin, transfer })`. ## The failure mode: the window you meant is not the window that is there The reason `'*'` is dangerous is that your handle to another window is stable while the *document* inside it is not. A `WindowProxy` obtained from `window.open()` or `iframe.contentWindow` keeps pointing at the same browsing context after it navigates to a completely different site. Realistic sequences: ```js const popup = window.open('https://partner.example/authorize?...'); // ...partner redirects to an identity provider, or to an attacker-supplied // return_to URL, before your code fires. popup.postMessage({ accessToken }, '*'); // lands on whatever origin is loaded now ``` Or the embedded case: you post configuration containing a user identifier to `frame.contentWindow` with `'*'`, and another script on your own page — an analytics tag, a tag-manager snippet — has rewritten that frame's `src` to a third party. You cannot see it, and the browser will not stop you. There is also a subtler variant. Timing matters because the origin is evaluated when the message is delivered, not when you decided to send it. Any redirect that lands between your check and your call is a window of exposure that an explicit `targetOrigin` closes for free. ## Why "it's just convenience" is the wrong framing The usual defence is that the receiver validates `event.origin` anyway, so a wildcard is harmless. That confuses the two directions of the trust boundary. The receiver's `event.origin` check protects the *receiver* from messages it should ignore. `targetOrigin` protects the *sender* from handing data to a page it never intended to talk to. Both checks are needed; neither substitutes for the other. A wildcard send to a hostile page is a completed disclosure regardless of what any well-behaved receiver would have done. ## The legitimate uses `'*'` is acceptable when the payload contains nothing you would mind publishing to an arbitrary origin, and you genuinely do not know the peer's origin. The canonical case is a third-party widget that is embedded on thousands of customer domains: the framed widget cannot enumerate the origins that embed it, so its first message to `window.parent` — a bare `{type:'ready', version:'3'}` — goes out with `'*'`. The pattern that keeps this safe is to treat the wildcard as a bootstrap only: 1. Send a non-secret hello with `'*'`. 2. The peer replies; the browser stamps `event.origin` on that reply, and page script cannot forge it. 3. Validate `event.origin` against your allowlist, keep it, and use it as `targetOrigin` for every subsequent message — or hand over a `MessagePort` at that point so later traffic bypasses the shared bus entirely. For same-origin conversations, `'/'` is strictly better than either `'*'` or a hardcoded origin string: it survives moving between staging, preview and production hostnames while still refusing to deliver to a cross-origin document. ## What targetOrigin does not do It authenticates an **origin**, not code, and not a user. If the target origin is compromised — an XSS on that host, a hijacked subdomain — the message is delivered to the attacker's script exactly as the browser is designed to do. It also says nothing about which *frame* on that origin receives it; if the origin runs several frames, whichever window handle you used gets the message. Finally, it does not encrypt or sign anything. Cross-window messages stay inside the browser process, so there is no wire exposure, but the payload is fully readable by any script running in the receiving document. Treat `postMessage` as a channel whose only access control is the origin pair, and size what you put on it accordingly.
- What does passing `'/'` as `targetOrigin` mean, and when would you use it?`'/'` tells the browser to deliver only if the receiving window's origin is identical to the sender's. It is the right choice for same-origin conversations — between your own frames or a popup you opened on your own site — because it enforces the restriction without hardcoding a hostname that changes across local, preview and production environments.
- Does a correct `targetOrigin` mean the receiving page can be trusted with the payload?No. It proves only that the document currently loaded there is on that origin. If the origin has an XSS, a hijacked subdomain, or simply ships third-party scripts, the attacker's code reads the message like any other script on that page. `targetOrigin` narrows who can receive; it says nothing about what runs there.
- Where does `targetOrigin` go when using the options-object form of `postMessage`?`window.postMessage(message, { targetOrigin: 'https://widget.example.com', transfer: [port] })`. The options form exists on `Window.postMessage`; `MessagePort.postMessage` and worker `postMessage` accept only `{ transfer }`, because a port is already bound to one peer and has no origin to check.
saying these in an interview costs you the question
- Calling '*' a harmless default because the receiver validates
- Assuming a window handle still points at the original site
- Sending tokens or session data with a wildcard
- Writing a path or trailing slash into the origin string
- Believing targetOrigin encrypts or signs the message