Validate message event source and origin in receive()#85
Open
thistehneisen wants to merge 1 commit into
Open
Conversation
The window "message" listener accepted any message whose data.action started with "web-eid:" without checking event.source or event.origin. This allowed an embedded iframe, a framing parent, or any other window to forge extension responses and resolve/reject the library's pending authenticate(), sign(), getSigningCertificate() and status() promises with attacker-controlled data (CWE-346 / CWE-940). Reject messages whose source is not the page's own window or whose origin is not the page's own origin, matching how the extension content script posts responses back into the same window. Tests are updated to dispatch responses as the content script would, plus regression tests covering foreign-source and foreign-origin responses.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #84.
Problem
WebExtensionService.receive()registered awindowmessagelistener thataccepted any message whose
data.actionwas a string starting withweb-eid:, without validatingevent.sourceorevent.origin. Any contextable to deliver a
messageevent to the page — an embedded iframe (ad, widget,user-rendered content), a malicious framing parent, or another window — could
forge
web-eid:*-success/*-failure/*-ackresponses and drive theresolution of the library's pending
authenticate(),sign(),getSigningCertificate()andstatus()promises with attacker-controlled data(CWE-346 / CWE-940).
This is inconsistent with the extension content script in
web-eid-webextension, which already enforcesevent.source === windowbeforerelaying messages.
Fix
Reject messages whose
event.sourceis not the page's own window or whoseevent.originis not the page's own origin. Legitimate responses are posted bythe content script into the same window, so both checks pass for real traffic.
Tests
window.postMessage, which in jsdomsets
sourcetonullandoriginto"". They now dispatch aMessageEventwithsource: window/origin: window.location.origin, asthe content script does.
WebExtensionService-sender-validation-test.ts: foreign-source andforeign-origin success/failure responses are ignored (request times out
instead of resolving with forged data), while a legitimate same-window
response still resolves.
Full suite (56 tests),
eslint, andtsc --noEmitpass.Note
This is not a server-side authentication bypass — the token's certificate and
signature are verified server-side and the origin is bound by the trusted
extension/native app. The impact is client-side: flow hijack/abort, response
pre-emption, and spoofing of any client-side trust placed in a response before
server verification. Additional defense-in-depth hardening (a per-request
correlation nonce,
warningsinput validation, and an allow-list indeserializeError) is described in #84 and left out of this change to keep itfocused.