[1] WebAuthn UIProcess origin spoofing via unvalidated IPC fields
WebAuthn's entire pitch is phishing resistance — yet the UIProcess took the renderer's word for which origin was actually asking.
Rated High because the diff removes a missing-validation gap at the WebContent-to-UIProcess boundary that let a compromised renderer bind a WebAuthn ceremony to an arbitrary relying-party origin; escalation to cross-site credential impersonation requires only a prior renderer compromise, which is the assumed threat model, though the bug yields no memory-corruption primitive.
A compromised WebContent process could spoof the securityOrigin in FrameInfoData or the parentOrigin parameter when sending WebAuthn MakeCredential/GetAssertion IPC messages to the UI process. This would let an attacker page impersonate a different origin (e.g. a bank) for credential creation or assertion. This patch adds MESSAGE_CHECKs to prevent that.
Source/WebKit/UIProcess/WebAuthentication/WebAuthenticatorCoordinatorProxy.cpp
LayoutTests/http/tests/ipc/web-authenticator-get-assertion-spoofed-origin-crash.html
Patch Details
Both makeCredential and getAssertion now take an IPC::Connection& as their first parameter so the receivers can issue connection-terminating checks. Each handler looks up the real frame via WebFrameProxy::webFrame(frameId), bails with InvalidStateError if none is found, and — when the frame URL is HTTP(S) — recomputes the expected origin with SecurityOriginData::fromURLWithoutStrictOpaqueness(frame->url()) and asserts frameInfo.securityOrigin == expectedOrigin via MESSAGE_CHECK_COMPLETION_BASE. getAssertion additionally walks frame->parentFrame() ancestors and, if any HTTP(S) ancestor exists, requires parentOrigin to equal one of those ancestor origins. Two IPC-testing layout tests send spoofed-origin requests and expect the WebContent process to be terminated.
Trusting an IPC-supplied security origin from the untrusted WebContent process without re-validating it against UI-process-owned frame state.
Background
WebKit splits work between a sandboxed WebContent (renderer) process and a privileged UI process; security-sensitive operations cross this boundary as IPC messages, and the UI process must treat every field as attacker-controlled. The MESSAGE_CHECK/MESSAGE_CHECK_COMPLETION_BASE macros terminate the offending IPC connection — killing the WebContent process — when their predicate fails, which is why the regression tests are named *-crash. FrameInfoData.securityOrigin is the renderer's claim about a frame's origin; WebFrameProxy::webFrame(frameId) returns the UI process's own record of that frame, whose url() is authoritative. WebAuthn MakeCredential/GetAssertion perform credential ceremonies scoped to a relying-party origin, and for cross-origin (iframe) assertions a parentOrigin describes the embedder, which must match an actual ancestor frame's origin.
Analysis
This is an origin-spoofing / authority-confusion bug, not memory corruption. Before the fix, the UI-process WebAuthn receivers consumed frameInfo.securityOrigin (and the parentOrigin argument) directly from the IPC message and propagated them into handleRequest/buildClientDataJson without checking them against the authoritative frame state. In WebKit's IPC trust model the renderer is untrusted: any field it serializes must be re-validated against UI-process-owned ground truth, and here that step was simply absent.
A compromised WebContent process crafts a MakeCredential/GetAssertion message whose FrameInfoData.securityOrigin claims an arbitrary origin (e.g. https://bank.com) while the real frame is hosted elsewhere. Pre-fix, the UI process believed that claim, so the WebAuthn ceremony — including the clientDataJSON origin field and the relying-party scoping — would be performed under the spoofed origin. The cross-origin variant additionally spoofs parentOrigin to claim an arbitrary embedder. This is exploitable as a WebAuthn origin-spoofing bypass by a renderer that can already send IPC; it is not a memory-corruption primitive and requires prior renderer compromise. The downstream propagation of the spoofed origin into buildClientDataJson's origin field is consistent with the provided source, though the full effect on the authenticator ceremony is inferred from how handleRequest consumes the data.
This vulnerability weakens the WebContent-to-UIProcess trust boundary as it applies to WebAuthn origin binding. WebAuthn's entire value proposition — phishing resistance — rests on the relying-party origin presented to the authenticator being the real origin of the requesting frame. An attacker who has compromised the renderer could request creation or assertion of credentials under an arbitrary origin such as a bank, impersonating that site to the platform authenticator. The fix re-derives the origin from UI-process-owned WebFrameProxy state and MESSAGE_CHECKs against the renderer's claim, mirroring how clipboard, media, and getUserMedia receivers already validate caller origins.
Audit directions
- Renderer-asserted origins trusted by a privileged broker. Privileged UIProcess/GPU/Network IPC receivers that consume a renderer-supplied
securityOrigin/SecurityOriginData/FrameInfoDataand act on it without re-deriving the origin from UI-process-owned frame state. Audit other receivers inSource/WebKit/UIProcesstakingFrameInfoData&&orSecurityOriginDataparameters and check whether they re-validate againstWebFrameProxy::webFrame(frameId)->url(). Grep forFrameInfoDataandparentOriginacross UIProcess message handlers and flag any reaching credentials, payments, or permissions without aMESSAGE_CHECK. - Default-pass ancestor walks. Cross-origin ancestor checks that iterate
parentFrame()but allow a default-pass when no qualifying ancestor exists. Review thehasHTTPAncestor/foundMatchingAncestorlogic here and similar ancestor-walks to confirm the non-HTTP (opaque/about:blank) path cannot be abused to skip origin enforcement — theif (hasHTTPAncestor) MESSAGE_CHECK(...)shape silently permits when the loop finds nothing. - Unmodified sibling endpoints. Verify the WebAuthn-adjacent IPC entry points still taking a bare
SecurityOriginData—isUserVerifyingPlatformAuthenticatorAvailable,getClientCapabilities,signalUnknownCredential,isConditionalMediationAvailable— validate that origin against the calling frame, since they were not touched by this patch. Trace each to see whether the origin drives a trust decision or is merely echoed back.