Digital Credentials: UI process independently verifies user activation
The privileged process trusted the sandbox to say the user tapped.
Source/WebKit/UIProcess/WebPageProxy.cpp
Source/WebKit/UIProcess/WebPageProxyInternals.h
Transient activation ("user gesture") is normally tracked and checked inside the WebContent process, which is the sandboxed, attacker-reachable renderer in WebKit's multi-process architecture. The UI process is the privileged process that owns real input events and presents native chooser UI. This commit makes the UI process independently verify transient user activation before presenting the Digital Credentials chooser, instead of trusting the WebContent process's check: it compares its own lastActivationTimestamp (set only from real input events) against the transient-activation window, and records a lastConsumedDigitalCredentialsActivationTimestamp so a single gesture can't authorize more than one chooser presentation.
Before: After:
WebContent (untrusted) WebContent (untrusted)
checks activation, sends IPC sends IPC regardless
UIProcess UIProcess (trusted)
trusts IPC, shows chooser compares own lastActivationTimestamp
vs transient-activation window
AND vs lastConsumed...Timestamp
shows chooser only if fresh & unconsumed
Significance
Closes a spoofing vector where a compromised renderer could pop a native credential picker (mobile driver's licenses, IDs) with no real user gesture, and blocks replaying one gesture to open multiple choosers.
Any security decision that relies solely on a check performed in WebContent is suspect under WebKit's process-trust model: a renderer compromise (via a JS engine or DOM bug) lets an attacker forge IPC arguments and skip that check. Moving attestation into the UI process — the same trust-boundary pattern used for permission dialogs and file pickers — makes the gesture proof authoritative.
Audit directions
This UI-process-side gating is worth pattern-hunting forward rather than only re-auditing the fix. Narrow: check whether other digital-credentials or similarly gated IPC entry points — any showXChooser or permission-prompt handler reaching native UI — still rely on WebContent-side-only activation checks without an equivalent UI-process re-verification. Wider: audit every UI-process handler that acts on a security decision (activation, permission, origin) computed in the renderer and passed over IPC; the pattern is a privileged action gated by an untrusted-process assertion. Widest: any two-process split where the privileged side consumes a trust claim minted by the sandboxed side without re-deriving it from state only the privileged side owns (input events, real timestamps). The review tell is a UI-process IPC handler that reads an activation/permission flag straight out of the message payload instead of consulting internals().lastActivationTimestamp or an equivalent locally-owned source — and, for the consumed-timestamp idiom specifically, a "last consumed" field that is compared but never updated (or updated non-atomically across racing requests) is the TOCTOU tell to carry into other single-use-gesture gates.