[3] WebContent-supplied origin forwarded as authorization key at four UI-process IPC sites
Rated Medium because the diff stops four UI-process handlers from keying privileged decisions on an origin/domain a compromised WebContent process can forge, yielding a cross-site permission/identity spoof (e.g. exercising a victim site's geolocation grant); it is not memory corruption and presupposes the attacker can already emit a forged WebContent IPC message, which bounds the severity below the renderer UAFs above.
Four UI-process IPC handlers accepted an origin/domain field from a DispatchedFrom=WebContent message and forwarded it verbatim to a system service as a per-site authorization key, without comparing it against UI-process-authoritative state. A compromised WebContent process could spoof the origin and have CoreLocation / AppSSO / MarketplaceKit / the geolocation policy decider apply another site's permission decision. The change re-derives each value from UI-process-authoritative state (WebFrameProxy::url() / WebFrameProxy::securityOrigin() / the committed main-frame URL): SOAuthorizationSession derives InitiatorOrigin from mainFrame()->url(); interceptMarketplaceKitNavigation derives the top-origin URL from page.mainFrame()->url(); requestGeolocationPermissionForFrame overwrites FrameInfoData::securityOrigin with the UI-computed origin and MESSAGE_CHECKs the frame; and startUpdatingWithProxy binds the RegistrableDomain to the authorization token and MESSAGE_CHECKs that the WebContent-supplied domain matches. Webarchive/opaque-document loads, whose origin the UIProcess cannot inspect, keep the pre-existing behavior.
Source/WebKit/UIProcess/WebPageProxy.cpp
Source/WebKit/UIProcess/WebGeolocationManagerProxy.cpp
Source/WebKit/UIProcess/Cocoa/SOAuthorization/SOAuthorizationSession.mm
Tools/TestWebKitAPI/Tests/WebKit/WKWebView/PermissionsAPI.mm
Patch Details
The geolocation handler adds MESSAGE_CHECK(process, frame) and, when frame->url().host() is non-empty, overwrites frameInfo.securityOrigin with frame->securityOrigin()->data(); it derives a RegistrableDomain from the committed main-frame URL and threads it into createRequest. The geolocation token store changes from HashSet<String> to HashMap<String, RegistrableDomain> so each token carries its bound domain (exposed via registrableDomainForAuthorizationToken); startUpdatingWithProxy then MESSAGE_CHECKs that the WebContent-supplied registrableDomain matches the token's bound domain, skipping the check only when the UI-derived domain is empty. SOAuthorizationSession always derives initiatorOrigin from SecurityOrigin::create(mainFrame->url()), applying the non-opaque check uniformly. interceptMarketplaceKitNavigation computes the top-origin as SecurityOriginData::fromURL(page.mainFrame()->url()).
Trusting a WebContent-supplied origin as an authorization key in the UI process instead of re-deriving it from process-authoritative frame state.
Background
WebKit splits the browser into a sandboxed WebContent process (runs web JS, untrusted) and a UI process (trusted, talks to system services). They communicate over IPC; a message tagged DispatchedFrom=WebContent originates in the untrusted process, so its fields are attacker-influenced once that process is compromised. MESSAGE_CHECK is a WebKit macro that validates an IPC invariant and terminates the sending process on failure. FrameInfoData::securityOrigin is an origin descriptor serialized inside several IPC messages describing a frame. WebFrameProxy is the UI-process mirror of a frame; WebFrameProxy::securityOrigin() and WebFrameProxy::url() return origin/URL values the UI process computed itself at navigation-commit time, independent of anything WebContent sends. RegistrableDomain is the eTLD+1 grouping used as a site key.
A geolocation authorization token is a UUID the UI process mints when the user approves a site; the WebContent process later presents it on StartUpdating to begin receiving positions. AppSSO/SOAuthorization (InitiatorOrigin) and MarketplaceKit (top origin) similarly take an origin from the UI process and hand it to a system service as the identity of the requesting site. The IPC Testing API (IPCTestingAPIEnabled) lets a test capture and replay raw outgoing IPC bytes, modeling a compromised WebContent that emits forged messages.
Analysis
This is an authorization-key origin-spoofing / confused-deputy logic flaw, not memory corruption. Before the fix, four UI-process handlers used an origin/domain value carried inside a DispatchedFrom=WebContent message as the authoritative per-site key for a privileged decision, without comparing it to state the UI process owns. The WebContent process is the untrusted party; any field it serializes must be treated as attacker-controlled once it is compromised. Concretely, requestGeolocationPermissionForFrame passed FrameInfoData::securityOrigin straight to the embedder's permission UI and later validated StartUpdating only by checking the token existed — never that the requesting domain matched the granted one; SOAuthorizationSession seeded the AppSSO InitiatorOrigin from sourceFrame()->securityOrigin(); and interceptMarketplaceKitNavigation used NavigationRequester::topOrigin.
The geolocation case is the cleanest two-step: the token is minted for the user-approved domain, but StartUpdating never bound the token to that domain, so any forged registrableDomain accompanying a valid token was accepted. The regression tests model the compromised renderer via the IPC Testing API — capturing the real RequestGeolocationPermissionForFrame / DecidePolicyForNavigationActionAsync bytes and byte-replacing the real host (localhost) with a forged one (evil.host) before replay. For geolocation specifically, an attacker obtains (or replays) a valid token and sends StartUpdating with a forged registrableDomain; pre-fix, isValidAuthorizationToken accepted the token regardless of domain, so positions could be obtained under a spoofed site key. For AppSSO/MarketplaceKit, forging the source-frame/top origin makes the system service treat the request as initiated by the victim origin.
This vulnerability weakens cross-process origin isolation. The UI process is the trusted deputy that converts a site's identity into a privileged grant, and before the fix that identity could be supplied by the untrusted WebContent process. The affected invariant is that a per-site permission decision (geolocation access, AppSSO initiator origin, MarketplaceKit top origin) is keyed to the origin actually committed in the frame, as known UI-side. An attacker who has already compromised a WebContent process could have a system service apply another site's permission decision — exercising a victim site's standing geolocation grant, or presenting a victim origin to AppSSO/MarketplaceKit — a cross-site permission/identity spoof that presupposes the ability to send a forged WebContent IPC message.
This is one bug class found at four independent sites, which strongly suggests the same anti-pattern is latent at other UI-process handlers consuming FrameInfoData::securityOrigin, NavigationRequester::topOrigin, or originatingFrameInfoData.securityOrigin. The webarchive/opaque-document carve-out (empty UI-derived domain ⇒ skip the equality check) is itself a residual soft spot worth tracking — it preserves the old trust-the-WebContent behavior for loads whose origin the UI process cannot authoritatively inspect.
Note: The SOAuthorizationSession enclosing function name, the precise pre-fix geolocation delegate-dispatch path, and the NavigationRequester type name are inferred from the commit message and code shape rather than fully shown in the diff. The four trust-boundary gaps and the uniform re-derivation fix are directly supported by the patch.
Audit directions
- A UI-process IPC handler keying a privileged decision on an origin/domain field from a
DispatchedFrom=WebContentmessage rather than re-deriving from committed UI-side state. Audit every UIProcess handler readingFrameInfoData::securityOrigin,NavigationActionData::originatingFrameInfoData, orNavigationRequester::topOriginand forwarding it to a capability or system service. GrepSource/WebKit/UIProcessfor.securityOriginandtopOriginuses inside message handlers, and check whether each is overwritten fromWebFrameProxy::securityOrigin()/url()before use. - A capability token validated only for existence, not for binding to the principal it was issued to. Audit other UIProcess authorization-token stores for the same
HashSet<Token>(membership-only) shapeGeolocationPermissionRequestManagerProxyhad. Verify each token stores and re-checks its bound site/origin/domain at redemption; start with permission managers underSource/WebKit/UIProcess(media, notifications, screen-capture, speech) and confirm a domain/origin equalityMESSAGE_CHECKexists at the use site. - A security carve-out for opaque/local-file/webarchive origins falling back to trusting the WebContent-supplied value. Examine the
authorizedDomain->isEmpty()and!frame->url().host().isEmpty()branches and audit whether a WebContent process can deliberately drive a frame into the empty-host/opaque state to re-enable the bypassed equality check. Trace howWebFrameProxy::securityOrigin()is computed for webarchive and file-URL commits. - Missing
MESSAGE_CHECKon frame resolution in permission handlers. Review UIProcess IPC handlers callingWebFrameProxy::webFrame(frameInfo.frameID)and verify theyMESSAGE_CHECKthe result rather than silentlyreturn-ing, since an unresolved or attacker-chosen frame ID can otherwise select the wrong principal. Grep UIProcess forWebFrameProxy::webFrame(inside message handlers.