Medium CVSS 4.3 webkit Cross Origin 🔧 Commit mapped

Overview

Medium
Severity
4.3
CVSS
No
Exploited ITW
Fixed
Fix Status
DescriptionA malicious website may be able to access script message handlers intended for other origins
ComponentWebCore Page
Bug ClassCross Origin
Tracker307014
Fix commit795ef8a1ac92 (WebKit/WebKit) +84/-16
CWECWE-79, CWE-346 (Cross-site scripting, Origin validation error)
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:N
CISA KEVNot listed
CreditedHongze Wu and Shuaike Dong from Ant Group Infrastructure Security Team, and webb
Disclosed2026-03-24

Background

UserMessageHandler
The WebCore object backing window.webkit.messageHandlers.<name>, bridging page script to a host-registered script message handler for a specific frame.
UserMessageHandlerDescriptor
The registered named handler (added via the WebKit2 API) that a UserMessageHandler dispatches messages to.
Same-origin policy
The web security rule that content from one origin must not access resources or capabilities bound to a different origin.
SecurityOrigin / isSameOriginAs
WebCore’s representation of an origin (scheme, host, port) and the comparison used to enforce same-origin access decisions.
scriptExecutionContext
The context (document/worker) associated with a JSDOMGlobalObject, from which the caller’s actual security origin is obtained.

Root Cause Analysis

UserMessageHandler implements the WebKit script message handler bridge (window.webkit.messageHandlers.<name>.postMessage / postLegacySynchronousMessage) that lets page script deliver messages to a host-registered WKScriptMessageHandler. A UserMessageHandler is constructed for a specific LocalFrame and wraps a UserMessageHandlerDescriptor (the named handler registered via the WebKit2 API). Before the patch, postMessage() and postLegacySynchronousMessage() only checked that the descriptor still existed; they did not verify that the JavaScript caller’s security origin matched the origin of the frame the handler belongs to. The violated invariant is that a message handler registered for a given frame/origin must only be reachable by script from that same origin. Because a handler object obtained in one frame could be invoked with a JSGlobalObject (script execution context) belonging to a different-origin frame, a malicious page could grab another frame’s messageHandlers object (e.g. via iframe.contentWindow.window.webkit.messageHandlers.<name>) and post to a handler intended for a different origin, leaking access to handlers not meant for it.

The fix adds passesSameOriginCheck(globalObject, frame): it takes the calling JSGlobalObject, resolves the caller’s scriptExecutionContext->securityOrigin(), resolves the handler frame’s document()->securityOrigin(), and requires securityOrigin->isSameOriginAs(frameSecurityOrigin), returning false (and rejecting the promise / returning an InvalidAccessError exception) on any mismatch or missing object. Both entry points now perform this check before dispatching to the descriptor. The API signatures were also tightened: postMessage now returns void and rejects the promise directly, while postLegacySynchronousMessage now returns ExceptionOrJSC::JSValue so it can surface the InvalidAccessError. The new test MessageHandlerFromIframe confirms that grabbing a cross-origin iframe’s testhandler1 and posting to it is rejected with ‘InvalidAccessError: Failed same-origin check.’, while a same-origin handler still succeeds.

Key insight
Script message handlers were dispatched based only on the descriptor’s existence, never checking that the caller’s origin matched the frame the handler belonged to, so a cross-origin frame reference could reach another origin’s handler; the fix adds an explicit same-origin check on both post paths.

Attack Path

  1. Host registers a named message handler An embedding app registers a WKScriptMessageHandler under a name (e.g. testhandler1), expecting only its own trusted content to use it.
  2. Attacker page loads a cross-origin frame The malicious top-level page (or a frame it controls) creates an iframe pointing at the origin/content for which the handler is intended, or otherwise obtains a reference into that frame.
  3. Grab the other frame's messageHandlers Script reads iframe.contentWindow.window.webkit.messageHandlers.<name>, obtaining a UserMessageHandler tied to the other frame while the calling script’s origin differs.
  4. Invoke postMessage cross-origin The attacker calls handler.postMessage(…) so UserMessageHandler::postMessage runs with a JSGlobalObject from the attacker’s origin but a handler bound to another frame’s origin.
  5. Reach the unintended handler (pre-patch) Without the same-origin check, the message is delivered to the host handler intended for the other origin, letting the attacker drive privileged app-side functionality or spoof messages from a trusted origin.

Impact Assessment

This is a same-origin-policy enforcement gap (a cross-origin access / logic bug), not a memory-safety issue, so there is no corruption primitive or direct code-execution path from the diff itself. The impact depends on what the host app’s registered message handlers do: an attacker script could reach handlers intended for another origin, potentially invoking privileged native functionality or injecting spoofed messages attributed to a trusted origin, so severity is app-dependent but can be significant. It sits in WebCore in the WebContent process bridging to host-side handlers; the fix restores the invariant that a handler is only usable by same-origin script.

Changed Functions

FunctionChangeNotes
passesSameOriginCheck
Source/WebCore/page/UserMessageHandler.cpp
added New static helper that compares the calling JSGlobalObject's scriptExecutionContext security origin against the handler frame's document security origin, returning false on any mismatch or missing object.
UserMessageHandler::postMessage
Source/WebCore/page/UserMessageHandler.cpp
modified Now returns void and rejects the promise directly; adds a passesSameOriginCheck gate that rejects with InvalidAccessError 'Failed same-origin check.' before dispatching to the descriptor.
UserMessageHandler::postLegacySynchronousMessage
Source/WebCore/page/UserMessageHandler.cpp
modified Signature changed to ExceptionOr<JSC::JSValue>; returns InvalidAccessError when the descriptor is missing or the same-origin check fails, otherwise dispatches.
UserMessageHandler (declarations)
Source/WebCore/page/UserMessageHandler.h
modified Updates postMessage/postLegacySynchronousMessage return types to match the new error handling and marks descriptor() const.
webkit_dom_dom_window_webkit_message_handlers_post_message
Source/WebKit/WebProcess/InjectedBundle/API/gtk/DOM/WebKitDOMDOMWindow.cpp
modified Adapts the GTK DOM binding to postMessage's new void return by dropping the hasException() check.
MessageHandlerFromIframe test
Tools/TestWebKitAPI/Tests/WebKit/WKWebView/WKWebViewEvaluateJavaScript.mm
added New test proving a cross-origin iframe handler rejects with 'Failed same-origin check.' while a same-origin handler still receives the message.

Files Changed

  • Source/WebCore/page/UserMessageHandler.cpp
  • Source/WebCore/page/UserMessageHandler.h
  • Source/WebKit/WebProcess/InjectedBundle/API/gtk/DOM/WebKitDOMDOMWindow.cpp
  • Tools/TestWebKitAPI/Tests/WebKit/WKWebView/WKWebViewEvaluateJavaScript.mm

Audit Directions

  • Other UserMessageHandler / descriptor entry points
    In UserMessageHandler.cpp and UserMessageHandlerDescriptor grep for didPostMessage / didPostLegacySynchronousMessage callers to confirm every dispatch path now flows through passesSameOriginCheck and none bypass it.
  • Objects reachable across frames via contentWindow
    Audit other WebKit-exposed objects fetched through iframe.contentWindow.window.webkit.* or cross-frame property access that act on their owning frame without re-checking the caller’s origin; grep for scriptExecutionContext()->securityOrigin() usage vs. its absence.
  • Frame-bound WebCore APIs missing origin checks
    Search page/ and bindings for methods that capture a LocalFrame& in their constructor and later use m_frame without comparing to the calling globalObject’s origin (isSameOriginAs), a general tell for this bug class.
  • Port bindings assuming old return types
    Grep across ports (gtk DOM bindings, JS bindings) for callers of postMessage/postLegacySynchronousMessage to ensure none silently ignore the new InvalidAccessError or reintroduce a path that skips the check.

Original Bug Report

The reporter's bug is still restricted on the tracker.