Skip to content

fix: validate event.origin in handleConnect to prevent channel hijacking#9

Open
kapeka0 wants to merge 1 commit into
vercel:mainfrom
kapeka0:fix/origin-validation-handleconnect
Open

fix: validate event.origin in handleConnect to prevent channel hijacking#9
kapeka0 wants to merge 1 commit into
vercel:mainfrom
kapeka0:fix/origin-validation-handleconnect

Conversation

@kapeka0

@kapeka0 kapeka0 commented Jul 1, 2026

Copy link
Copy Markdown

handleConnect accepts any incoming bidc-connect message as long as the
channelId matches — it never checks where the message came from. Since the
default channelId is "bidc_default" and any window with a handle to the
target (opener, parent, named frame) can postMessage to it, a malicious
window that knows or guesses the channelId can complete the handshake and
hijack a legitimate channel, intercepting all subsequent communication.

A possible fix is to add an optional origin argument to createChannel. When provided:

  • Inbound: connections whose event.origin differs from the declared
    origin are rejected in handleConnect.
  • Outbound: the origin is used as the targetOrigin for postMessage
    instead of '*', so handshake messages aren't broadcast to other origins.

The expected origin has to be declared by the caller — it can't be derived
from a cross-origin target (contentWindow.origin throws a SecurityError),
and deriving it from the first handshake (trust-on-first-use) is a race an
attacker can win, so it wouldn't actually be safe.

createChannel(target)                        // unchanged, no validation
createChannel(target, channelId)             // unchanged
createChannel(target, channelId, origin)     // NEW: validate against origin
createChannel(channelId, origin)             // NEW: iframe side (no target)

Fully backward compatible: without origin, behaviour is identical to before.

A malicious window that knows the channelId can hijack a legitimate BIDC
channel by sending a bidc-connect message with a matching channelId, since
handleConnect never checked the message origin.

Add an optional `origin` argument to createChannel. When provided, incoming
connections whose event.origin differs are rejected, and the origin is used
as the targetOrigin for outbound postMessage calls instead of '*'. The origin
must be declared by the caller because it cannot be derived from a
cross-origin target. Behaviour is unchanged when origin is omitted.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant