← WebKit — 2026-W36
aba0fcd53beabdfab961ba8ca5ee11565a9f2ca7 [IPC] Add the UI process' origin validation procedures
severity medium
class CrossOrigin
confidence 0.5
signal score 11.06
Source/WebKit/Platform
Primitive: framework for validating untrusted IPC origins/domains/sites against a process's first-party authority
Triage note: Adds FirstPartyAuthority/TopLevelFirstPartyAuthority/CommittedClientOriginAuthority IPC validators (via CanValidateUntrusted) that map WebProcessProxy::allowsFirstPartyAccess onto Ignore/Terminate under site isolation. Security hardening infrastructure against origin spoofing, but this diff only defines the header - no concrete call-site bug is fixed here.
Triage note: Adds FirstPartyAuthority/TopLevelFirstPartyAuthority/CommittedClientOriginAuthority IPC validators (via CanValidateUntrusted) that map WebProcessProxy::allowsFirstPartyAccess onto Ignore/Terminate under site isolation. Security hardening infrastructure against origin spoofing, but this diff only defines the header - no concrete call-site bug is fixed here.
Structural signals: smartptr_member_added (+6.47), security_assert (+3.0), null_guard (+2.59), msg_soft (+1.0), large_churn (-2.0)
Commit message
[IPC] Add the UI process' origin validation procedures
https://bugs.webkit.org/show_bug.cgi?id=323100
Reviewed by Zak Ridouh.
This is the second in a series of commits which will eventually result in all
code paths provably validating origins sent from WCP to more privileged processes.
Adds the procedures by which the UI process recovers a trusted origin from an
IPC::Untrusted<T>. Nothing calls them yet - the burn-down is a later commit - so
there is no behavior change.
There is more than one because the UI process has different notions of authority and
they are not interchangeable:
- FirstPartyAuthority answers "is this the registrable domain of the site this
process is for", which is the question site isolation can answer, and it is the
only question available for a bare SecurityOriginData, RegistrableDomain or Site.
It defers to WebProcessProxy::allowsFirstPartyAccess().
- TopLevelFirstPartyAuthority asks the same question of allowsFirstPartyAccess(), but
without the site-isolation guard described below, for the values where that guard
would be wrong. See below.
- CommittedClientOriginAuthority answers "has this process committed a load for
this exact (top origin, client origin) pair", deferring to
WebProcessProxy::hasCommittedClientOrigin(). It is strictly stronger, and it is
only available for ClientOrigin, which is why it cannot be merged with the others.
Both functions already existed and are already used by a handful of hand-written
MESSAGE_CHECKs; this commit does not invent a policy, it makes the existing one
reachable through the type.
allowsFirstPartyAccess() is three-way: SilentFailure becomes
ValidationFailure::Ignore because it means the process is serving several sites
at once, which happens legitimately as a new load starts, and terminating there
would kill processes during normal navigation.
FirstPartyAuthority's site-isolation guard is the one piece of new logic, and it is
there because the value it is handed may name any origin on the page, including a
subframe's. Without site isolation a single process hosts a page and every cross-site
subframe it pulls in, while WebProcessProxy records only the main frame's site, so for
such a value the comparison has no useful answer and could only produce false denials.
FirstPartyAuthority therefore passes everything when siteIsolationEnabled is off or the
process is the single web process.
That guard must not silently weaken a check that ships today, so there is a third
procedure. TopLevelFirstPartyAuthority asks exactly the same question with no guard,
and is correct only for a value that is by construction the process's own top-level or
worker origin - where WebProcessProxy's record of the main frame's site is the right
thing to compare against with or without site isolation. The two app-badge messages,
SetAppBadgeFromWorker and WebFrameProxy::SetAppBadge, are the existing unconditional
callers of allowsFirstPartyAccess(), and they use this procedure, so their behaviour is
unchanged in every configuration. CommittedClientOriginAuthority needs no guard for the
same reason: hasCommittedClientOrigin() answers from what the process has actually
committed, which is exact either way, so the Web Locks checks that already call it are
unchanged too.
Alternative considered for CommittedClientOriginAuthority: validating only the top
origin, as the network process does. Rejected because storage and Web Locks
partition on both halves of a ClientOrigin, so the top origin alone is only half of
the key they are keyed on.
If the WebProcessProxy has gone away by the time we do one of these queries, we
assume that the process is already going through destruction rather than being
malicious. Alternative considered: hold a strong reference to the WebProcessProxy.
We don't want to do that because we don't want to inadvertently extend lifetimes
via this change.
Also documents, next to the primitive, the EXTRACT_WITH_MESSAGE_CHECK shape that
callers will use. It cannot live in a shared header: the macro has to expand to the
receiver's own MESSAGE_CHECK, whose argument order differs between translation
units, so each defines its own. The definitions land with their first users in a
later commit rather than sitting unused here.
* Source/WebKit/Platform/IPC/Untrusted.h:
* Source/WebKit/UIProcess/FirstPartyAuthority.h: Added.
(WebKit::checkFirstPartyAccess):
(WebKit::FirstPartyAuthority::FirstPartyAuthority):
(WebKit::FirstPartyAuthority::checkUntrusted const):
(WebKit::FirstPartyAuthority::checkUntrustedDomain const):
(WebKit::TopLevelFirstPartyAuthority::TopLevelFirstPartyAuthority):
(WebKit::TopLevelFirstPartyAuthority::checkUntrusted const):
(WebKit::CommittedClientOriginAuthority::CommittedClientOriginAuthority):
(WebKit::CommittedClientOriginAuthority::checkUntrusted const):
Canonical link: https://commits.webkit.org/320248@main
Before / after
Loading diff…
On This Page