← All reports

App badge IPC sender-origin validation

WebKit UIProcessCrossOrigin

Component: WebKit UIProcess | fd1fbad

Tools/TestWebKitAPI/Tests/WebKit/WKWebView/Badging.mm

@interface BadgeDelegate : NSObject <_WKAppBadgeDelegate>
...
- (void)updatedAppBadge:(NSNumber *)badge fromOrigin:(SecurityOriginData)origin
{
// test now verifies fromOrigin matches expected requesting origin,
// not just that a badge value was received
}

Tools/TestWebKitAPI/Helpers/cocoa/HTTPServer.h

// HTTPResponse::HTTPResponse extended to support multi-origin test setup
// needed to exercise cross-origin badge spoofing scenario

WebKit's multi-process architecture treats the UI process as the trust boundary: WebContent processes are sandboxed and assumed to be compromisable, so any IPC message they send that affects UI-process-controlled state must be independently validated against what that WebContent process is actually permitted to represent. The Badging API lets service workers and pages set a numeric badge on the app icon, and the update flows over IPC from WebContent to the UI process. This commit adds sender-origin validation to that message, so the UI process verifies a WebContent process is actually authorized to update the badge for a given worker origin before applying the change. The test-side changes carry the same shift: the badge delegate now checks that fromOrigin matches the expected requesting origin rather than merely that some badge value arrived, and HTTPServer gains multi-origin setup support so a cross-origin spoofing scenario can be exercised.

Before:                                   After:
WebContent (compromised)                 WebContent (compromised)
  └─ IPC: setAppBadge(origin=X) ──►        └─ IPC: setAppBadge(origin=X) ──►
 UI process                               UI process
  └─ applies badge for origin X            └─ validate: does this WebContent
     (no origin ownership check)              process actually own origin X?
                                             ├─ yes ──► apply badge
                                             └─ no  ──► reject/ignore

Previously a compromised WebContent process could send an arbitrary badge-update IPC claiming any origin, spoofing the app badge as if it came from a different site. That is a sandbox-escape-adjacent privilege issue: the UI process was taking an unvalidated origin claim from the sandboxed renderer at face value, in a message whose effect is user-visible browser chrome outside the renderer's control.

This is a fixed, confirmed IPC origin-validation gap in a privileged UI-process handler — a strong template for sibling bugs elsewhere. Narrow: enumerate every IPC message from WebContent to UI process that carries a self-reported origin or identity parameter and check whether each performs an equivalent sender-origin ownership check; notifications, permission prompts, favicon and title updates, and the other Badging-adjacent APIs are the immediate neighbours. Wider: the same shape recurs wherever a UI-process handler acts on a SecurityOriginData or ClientOrigin argument taken from the message rather than re-derived from the sending connection's known page/frame binding — the match tell in review is a handler signature carrying an origin parameter with no allowsFirstPartyAccess()-style check as its first statement. Widest: the invariant is that a privileged receiver must re-derive a principal from a channel it controls rather than reading it out of the payload, which transfers to any Mojo receiver bound to a RenderFrameHost and to any RPC surface where the caller names its own identity.