[3] WebContent-supplied origin forwarded as authorization key at four UI-process IPC sites
Severity: Medium | Component: WebKit UIProcess permission and authorization plumbing | 5ca4d87
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
void WebPageProxy::requestGeolocationPermissionForFrame(IPC::Connection& connection, GeolocationIdentifier geolocationID, FrameInfoData&& frameInfo)
{
+ Ref process = WebProcessProxy::fromConnection(connection);
RefPtr frame = WebFrameProxy::webFrame(frameInfo.frameID);
- if (!frame)
- return;
+ MESSAGE_CHECK(process, frame);
+
+ if (!frame->url().host().isEmpty())
+ frameInfo.securityOrigin = frame->securityOrigin()->data();
+
+ WebCore::RegistrableDomain mainFrameDomain;
+ if (RefPtr mainFrame = m_mainFrame.get(); mainFrame && !mainFrame->url().host().isEmpty())
+ mainFrameDomain = WebCore::RegistrableDomain { mainFrame->url() };
- auto request = protect(internals().geolocationPermissionRequestManager)->createRequest(geolocationID, protect(frame->process()));
+ auto request = protect(internals().geolocationPermissionRequestManager)->createRequest(geolocationID, protect(frame->process()), WTF::move(mainFrameDomain));
Source/WebKit/UIProcess/WebGeolocationManagerProxy.cpp
- auto isValidAuthorizationToken = protect(page->geolocationPermissionRequestManager())->isValidAuthorizationToken(authorizationToken);
- MESSAGE_CHECK(proxy.connection(), isValidAuthorizationToken);
+ auto authorizedDomain = protect(page->geolocationPermissionRequestManager())->registrableDomainForAuthorizationToken(authorizationToken);
+ MESSAGE_CHECK(proxy.connection(), !!authorizedDomain);
+ MESSAGE_CHECK(proxy.connection(), authorizedDomain->isEmpty() || *authorizedDomain == registrableDomain);
Source/WebKit/UIProcess/Cocoa/SOAuthorization/SOAuthorizationSession.mm
- if (RefPtr sourceOrigin = m_navigationAction->sourceFrame() ? m_navigationAction->sourceFrame()->securityOrigin().securityOrigin().ptr() : nullptr; sourceOrigin && !sourceOrigin->isOpaque())
- initiatorOrigin = sourceOrigin->toString();
- if (m_page->mainFrame()) {
- if (m_action == InitiatingAction::SubFrame)
- initiatorOrigin = WebCore::SecurityOrigin::create(m_page->mainFrame()->url())->toString();
+ if (RefPtr mainFrame = page ? page->mainFrame() : nullptr) {
+ Ref mainFrameOrigin = WebCore::SecurityOrigin::create(mainFrame->url());
+ if (m_action == InitiatingAction::SubFrame || !mainFrameOrigin->isOpaque())
+ initiatorOrigin = mainFrameOrigin->toString();
Tools/TestWebKitAPI/Tests/WebKit/WKWebView/PermissionsAPI.mm
+ const realBytes = enc.encode('localhost');
+ const evilBytes = enc.encode('evil.host');
+ // byte-replace real host with forged host in captured IPC and replay
+ EXPECT_WK_STREQ(host, "localhost"_s);
+ EXPECT_FALSE(host.contains("evil"_s));
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.
Aaa Aaaaaaaaaaa Aaaa Aa Aaa Aaaaaaaa Aaaaaaaaa Aaa Aaaaa Aa Aaaaaa Aaa Aaa Aaaaaaaaaaaaa Aaaaaaa Aaa Aaaaaaaaaaaaaaa Aaaaa Aaaaa Aaa Aaaaa Aa Aaaa Aaaaaaa Aa Aaa Aaaaaa Aaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaa a Aaaaa Aaaaa Aaa Aaaaaaaaa Aaa Aaaaaaaaaa Aaaaa Aaaaa Aaa Aaaaaaaaaaa Aaaaaaaa Aaa Aaa Aaa Aaaaaaa Aaa a Aaaaaaaaa Aaa Aaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa a Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaa Aaa Aaaaaaaaaaaaaa Aaa Aaaa Aaaa Aaaaaaaaaaaaa Aaaa a Aaaaaa Aaa Aaaaaaaaaaaaa Aaaaaa Aaaaaaa Aaa Aaaaaaaaaaa Aaaaaaaaaaaaa Aa Aaaaaaaa Aaaaaaa Aaa Aaaaaaaa a Aaaaa Aaaaa Aaa Aaaaa Aaaaaaaaaaaaaaa Aaaa a Aaaaaa Aaaaaaaaaaaaaaaaaaaa Aaaaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaa Aaa Aaaaa Aaaaaaaaaa Aa Aaaaaaa Aa Aaaaaaaaa Aaaaa Aa Aaaaaaaa Aaaaa a Aaaaaaa Aaaa Aaaa Aaa Aaaaaaaaaaaaaaaaaaaaaa Aaaaaaa Aaa Aaaaaaaaaaaaaaaa Aaaaaa Aaaaa Aaa Aaaaaa Aaaaaaa Aaaaa Aaa Aaaaaaa Aa Aaaaaaaaa Aa Aaa Aaaaaa Aaaaaaa
Aaaa Aaaaaaaaaaaaa Aaaaaaa Aaaaaaaaaaaaa Aaaaaa Aaaaaaaaaa Aaa Aa Aaaaaaa Aa Aaa Aaaaaaa Aaaaaa Aaaa Aaaaaaaa a Aaaaaa Aaaaaaaa Aaaa a Aaaaaaaaaa Aaaaaa Aaa Aaaaaa Aaa Aaa Aaaa Aaaaaaaa Aaaaa Aa Aaaaaaaa Aa Aaa Aaaaaaaaa Aaaaaaaaaa Aaaaaaaa Aaa Aaaaaaaa Aaaaaaaaa Aa Aaaa a Aaaaaaaa Aaaaaaaaaa Aaaaaaaa Aaaaaaaaaaaa Aaaaaaa Aaaaaa Aaaaaaaaa Aaaaaaa Aaaaaaaaaaaaaa Aaa Aaaaaaa Aa Aaaaa Aa Aaa Aaaaaa Aaaaaaaa Aaaaaaaaa Aa Aaa Aaaaaa Aa Aaaaa Aaaaaaaa Aa Aaaaaaaa Aaa Aaa Aaaaaaa Aaaaaaaaaaa a Aaaaaaaaaa Aaaaaaa Aaaaa Aaaa a Aaaaaa Aaaaaaa Aaaaa Aaaaaaa Aaaaaa Aaaaaaaaaa Aaaaaaaa a Aaaaaaaaaa a Aaaaaa Aaaaaa Aaaaaaaa Aaaaaaaaaaa Aaaaaa Aa Aaaaaaaaaa a Aaaaaa Aaaaaa Aa Aaaaaaaaaaaaaaaaaaaaa a a Aaaaaaaaaa Aaaaaaaaaaaaaaaaaaa Aaaaa Aaaa Aaaaaaaaaaa Aaa Aaaaaaa Aa Aaaa a Aaaaaa Aaaaaaaaaa Aaa Aaaaaaaa
Aaaa Aa Aaa Aaa Aaaaa Aaaaa Aa Aaaa Aaaaaaaaaaa Aaaaaa Aaaaa Aaaaaaaa Aaaaaaaa Aaa Aaaa Aaaaaaaaaaaa Aa Aaaaaa Aa Aaaaa Aaaaaaaaaa Aaaaaaaa Aaaaaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaa Aaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaa Aaaaaa Aaaaaaaaaa Aaaaaa a Aaaa Aaa Aaaaaaaa Aaaaaa Aa Aaaaaa a Aaaaaaaa Aaaa Aaaa Aaaaa Aaaaaaaa a Aa Aaaaaaaaa Aaa Aaa Aaaaaaaaaaaaaaaaaaaa Aaaaaaaa Aaa Aaaaa Aaaaa Aaaaaa Aaa Aa Aaaaaaa Aaaaaa Aaaaaaaaaaaaaaa Aaaaaaaa
Aaaaaaaaa Aaa Aaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaa Aaaaaaaa Aaaaa Aaa Aaaaaaa Aaaaaaa Aaaaaaaaaaa Aaaaaaaaaaaaaaaaa Aaaaa Aaa Aaa Aaaaaaaaaaaaaaaaaaaaa Aaaa Aaaa Aaa Aaaaaaaa Aaaa Aaa Aaaaaa Aaaaaaa Aaa Aaaa Aaaaa Aaaaaa Aaaa Aaaaa Aaaaa Aa Aaa Aaaaa Aaa Aaaa Aaaaaaaaaaaaaa Aaaa Aaa Aaa Aaaaaaa Aaaaaaaaaaaaa Aaa Aaa Aaaaaaaa Aaaaaaaaa Aa Aaa Aaaaaa
🔒The cross-process trust model behind these four handlers, and what a compromised renderer could actually claim, is examined in depth.
Subscribe to read more
Audit directions
a Aaa Aaaaaaaaaa Aaa Aaaaaaa Aaaaaa a Aaaaaaaaaa Aaaaaaaa Aa Aa Aaaaaaaaaaaaa Aaaaa Aaaa a Aaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaa Aaaaaa Aaaa Aaaaaaaaaaa Aaaa Aaaaaaaaa Aaaaaaa Aaaaaaaa Aaaaa Aaaaa Aaaaaaaaa Aaaaaaa Aaaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaa Aaaaaaaaaa Aa Aa a Aaaaaaaaaa Aa Aaaaaa Aaaaaaaa Aaaa Aaaaaaaaaaaaaaaaaaaaaaaaa Aaa Aaaaaaaaaaaaaaaaa Aaa Aaaaaaaaaaa Aaaa Aaaaaa Aaaaaaa Aaaaaaaaa Aaa Aaaaa Aaaaaaa Aaaa Aa Aaaaaaaaaaa Aaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaa Aaaa
a Aaa Aaaaaaaaaa Aaaaa Aaaaaaaaa Aaaa Aaa Aaaaaaaaaa Aaa Aaa Aaaaaaa Aa Aaa Aaaaaaaaa Aa Aaa Aaaaaa Aaaaa Aaaaa Aaaaa Aaaaaaaaa Aaaaaaaaaaaaaaaaaaa Aaaaaa Aaa Aaa Aaaa Aaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaa Aaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaa Aaaaaa Aaaa Aaaaa Aaaaaa Aaa Aaaaaaaaa Aaa Aaaaa Aaaaaaaaaaaaaaaaaa Aa Aaaaaaaaaaa Aaaaa Aaaa Aaaaaaaaaa Aaaaaaaa Aaaaa Aaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaa Aaaaaaaaaaaaaa Aaaaaaaaaaaaaaa Aaaaaaa Aaa Aaaaaaa a Aaaaaaaaaaaaa Aaaaaaaa Aaaaaaaaaaaaaaa Aaaaaa Aa Aaa Aaa Aaaaa
a Aaa Aaaaaaaa Aaaaaaaaa Aaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaa Aaaaaaa Aaaa Aa Aaaaaaaa Aaa Aaaaaaaaaaaaaaaaaaa Aaaaaaaa Aaaaaaa Aaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaa Aaa Aaaaa Aaaaaaa a Aaaaaaaaaa Aaaaaaa Aaa Aaaaaaaaaaaa Aaaaa a Aaaaa Aaaa Aaa Aaaaaaaaaaaaaaaaa Aaaaa Aa Aaaaaaaaa Aaa Aaaaaaaa Aaaaaaaa Aaaaaa Aaaaa Aaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aa Aaaaaaaa Aaa Aaaaaaaaaa Aaa Aaaaaaaa Aaaaaaaa
a Aaaaaaaaa Aaaaaaaaaaaaaaa Aa Aaaaa Aaaaaaaaaa Aa Aaaaaaaaaa Aaaaaaaaaaa Aaaaaa Aaaaaaaaa Aaa Aaaaaaaa Aaaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaa Aaaaaa Aaaa Aaaaaaaaaaaaaaa Aaa Aaaaaa Aaaaaa Aaaa Aaaaaaaa Aaaaaaaaaaaaa Aaaaa Aa Aaaaaaaaaa Aa Aaaaaaaaaaaaaaa Aaaaa Aa Aaa Aaaaaaaaa Aaaaaa Aaa Aaaaa Aaaaaaaaaa Aaaa Aaaaaaaaa Aaa Aaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaa Aaaaaaa Aaaaaaaaa
🔒Four reusable audit patterns identified, with concrete UIProcess starting points for finding sibling instances of this trust-boundary flaw.
Subscribe to read more