[2] WebPasteboardProxy missing frame-ancestry check under Site Isolation
Severity: High | Component: WebKit UI-process WebPasteboardProxy (Cocoa) | 69aa562
Rated High because the diff adds the missing subtree-membership check on attacker-supplied frame identifiers that a compromised WebContent process could name in a pasteboard IPC, where the pre-fix path could collect an unrelated cross-site frame's serialized DOM; escalation to a sandbox escape is not implied — the impact is a cross-site information disclosure gated on addressing the target FrameIdentifier and reading the pasteboard back.
WebPasteboardProxy performed no subtree checks on the remote frame IDs it was given, so it could cause content from an unrelated cross-site remote frame to be written to the pasteboard. The fix adds message checks ensuring every remote frame ID used within WebPasteboardProxy is a descendant of the root frame ID being copied.
Source/WebKit/UIProcess/Cocoa/WebPasteboardProxyCocoa.mm
+// Only allow exploring frames that descend from the provided root frame.
+static bool validateFrameIdentifiers(FrameIdentifier rootFrameIdentifier, const HashMap<FrameIdentifier, Ref<WebCore::LegacyWebArchive>>& localFrameArchives, const Vector<FrameIdentifier>& remoteFrameIdentifiers)
+{
+ auto isInSubtree = [&](WebFrameProxy& frame) {
+ for (RefPtr ancestor = &frame; ancestor; ancestor = ancestor->parentFrame()) {
+ if (ancestor->frameID() == rootFrameIdentifier)
+ return true;
+ }
+ return false;
+ };
+ auto isAllowed = [&](FrameIdentifier identifier) {
+ if (identifier == rootFrameIdentifier)
+ return true;
+ RefPtr frame = WebFrameProxy::webFrame(identifier);
+ return !frame || isInSubtree(*frame);
+ };
+ for (auto& [frameIdentifier, archive] : localFrameArchives) {
+ if (!isAllowed(frameIdentifier))
+ return false;
+ Ref protectedArchive = archive;
+ if (auto archiveFrameIdentifier = protectedArchive->frameIdentifier(); archiveFrameIdentifier && !isAllowed(*archiveFrameIdentifier))
+ return false;
+ for (auto subframeIdentifier : protectedArchive->subframeIdentifiers()) {
+ if (!isAllowed(subframeIdentifier))
+ return false;
+ }
+ }
+ for (auto identifier : remoteFrameIdentifiers) {
+ if (!isAllowed(identifier))
+ return false;
+ }
+ return true;
+}
+ // writeWebContentToPasteboard
+ MESSAGE_CHECK(validateFrameIdentifiers(*rootFrameIdentifier, content.localFrameArchives, content.remoteFrameIdentifiers), connection);
+ // writeWebArchiveToPasteBoard
+ MESSAGE_CHECK_COMPLETION(validateFrameIdentifiers(rootFrameIdentifier, localFrameArchives, remoteFrameIdentifiers), connection, completionHandler(WriteWebArchiveToPasteBoardResult::FailureDueToInvalidFrameIdentifiers, 0));
LayoutTests/http/tests/ipc/resources/write-web-archive-frame-ancestry-check-iframe.html
+ // Forge a WriteWebArchiveToPasteBoard IPC that names an out-of-process frame ID (the parent
+ // frame) as a remote subframe. This should fail with the FailureDueToInvalidFrameIdentifiers error.
+ let r = IPC.sendSyncMessage('UI', 0, IPC.messages.WebPasteboardProxy_WriteWebArchiveToPasteBoard.name, 1000, [
+ S(pbName), FrameID(myFrameID), u64(0n), u64(1n), FrameID(parentFrameID),
+ ]);
Patch Details
A new static helper validateFrameIdentifiers(rootFrameIdentifier, localFrameArchives, remoteFrameIdentifiers) walks each supplied frame identifier and confirms it is a subtree descendant of the root frame being copied. isAllowed() returns true for the root frame itself or — via WebFrameProxy::webFrame(identifier) and the isInSubtree lambda that walks parentFrame() up to the root — for any frame whose ancestry chain reaches rootFrameIdentifier; an unknown (null) frame is also allowed. The helper validates every key in content.localFrameArchives, each archive's own frameIdentifier() and subframeIdentifiers(), and every remoteFrameIdentifiers entry. writeWebContentToPasteboard gains a MESSAGE_CHECK, and writeWebArchiveToPasteBoard a MESSAGE_CHECK_COMPLETION. The WriteWebArchiveToPasteBoard reply type is widened from a bare int64_t changeCount to (WriteWebArchiveToPasteBoardResult result, int64_t changeCount) — a new enum class (Success / FailureDueToInvalidFrameIdentifiers / FailureOther) — so the WebProcess and test can observe rejection.
Missing frame-ancestry (subtree-membership) authorization on attacker-supplied frame identifiers crossing an IPC trust boundary in the Site Isolation pasteboard broker.
Background
Site Isolation is WebKit's architecture that places cross-site iframes in separate WebContent processes, where each frame has a process-spanning FrameIdentifier used by the UI process to address frames. WebPasteboardProxy is a UI-process IPC message receiver that brokers pasteboard operations on behalf of WebContent processes. LegacyWebArchive is WebKit's serialized representation of a frame and its subframes (a .webarchive); createOneWebArchiveFromFrames assembles one archive from a root frame plus its local-frame archives and remote (out-of-process) subframe identifiers. WebFrameProxy::webFrame(identifier) resolves a FrameIdentifier to the UI-process proxy for that frame, whose parentFrame() chain expresses the frame tree.
MESSAGE_CHECK / MESSAGE_CHECK_COMPLETION are IPC validation macros that, on failure, treat the message as invalid (terminating the sender or returning an error) — the standard mechanism for enforcing invariants on attacker-controlled IPC input. The IPCTestingAPI is a test-only facility that lets layout tests synthesize raw IPC messages, used here to forge a request naming a non-descendant frame.
Analysis
This is a missing authorization / cross-process capability check on an IPC handler — a Site Isolation boundary bypass. Before the fix, writeWebArchiveToPasteBoard and writeWebContentToPasteboard accepted a rootFrameIdentifier plus an arbitrary set of local-frame-archive keys and remoteFrameIdentifiers straight from an IPC message and passed them to createOneWebArchiveFromFrames without ever confirming those identifiers belonged to the subtree rooted at rootFrameIdentifier.
Under Site Isolation, cross-site subframes live in different WebContent processes but their FrameIdentifiers are globally addressable across the UI process. The UI process's WebPasteboardProxy is the trusted broker that assembles a multi-frame web archive, reaching into other frames' processes to collect their serialized DOM. With no ancestry validation, a WebContent process serializing a copy of its own frame could name a completely unrelated cross-site remote frame as a "remote subframe", causing that frame's content to be collected and written to the pasteboard.
Aaa Aaaaaaaaaa Aaaa Aaaaaaaaaaaa Aaa Aaaaaaaa Aa Aaaaaa Aaaaaa Aaa Aaa Aaaaaa Aaa Aaaaaaaaaaaaaa Aaaaaa Aaaaaaa Aaaaaaaaaaaaaaaaa Aa a Aaaaaa Aaaaaaaaa Aaaaaaa Aaaa Aaa Aaaaaaaaa Aaaaaaaa Aa Aaaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaa a Aaaaaaaaaa Aaaaaaaa Aa Aaaaaaaa Aaaaa a Aaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaa Aaaaaaaaaaaaaaaaaaaaa Aa Aaa Aaa Aaaaa Aaa Aaaaa Aaaaaaaaaaaaaaaaaaaaaaaa Aaa a Aaaaa Aaaaaaaaa Aaaaaaaa Aaaaaaaaaaaa Aaaa Aa Aaaaaaaaa Aaaaaaaaaa Aaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaa Aaaaaaa Aaaa Aaaaaaaaaaaaaa Aaaaaaa Aaaaaaaaaa Aaaaaaa Aaaa Aaa Aaaaaaa Aaaaaaa Aa Aaa Aaaaaaaaaaa Aaaaa Aaaaaaaa Aaaaaa Aaaaa Aaaa Aaaa Aaaa a a Aaaaaaaaaa Aaaaaaaaaaaaaaaaaa Aaaaaaaaa Aaaaa Aa Aaaaaaa Aaa Aaaaaa Aaaaaaaaaaaaaaaaaa
Aaaa Aaaaaaaaaaaaa Aaaaaaa Aaa Aaaa Aaaaaaaaa a Aaaaaaaaaaa Aaaaa Aaaaaaaaa Aaa Aaaaaaaa Aaaaa Aaaaaaa a Aaaaaaaaaa Aaaaaaa Aaa Aaaa Aaaaa Aaa Aaa Aaaaa Aaaaaaa Aa Aa Aaaaaaaaaa Aaaa Aaa Aaaaaaaaaa Aaaaaa a Aaaaa Aaa Aaaaaaaaaa Aaaaaa Aa Aaaaaaaa Aa Aaaaaaa Aaaa Aaa Aaaaa Aaaaaa Aaaaaa Aa Aaa Aaaaaaa Aaaaaaa Aaaaaaaa Aaaaaa Aaa Aaa Aaaa Aaaaaaaaa Aaa Aaaaaaaaaaa Aa a Aaaaaaaaa Aaaaaaaaaa Aaaaaaa Aaaaa Aaaaaaaaaa Aaaaaaa Aaaaaaaa Aaaaaaaaaaaaa Aaaaa Aaaa Aaaa Aa a Aaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaaa Aaaaaa Aaaaaa Aaa Aaaaaaaa Aaaaaaa Aaaaaa Aaa a Aaaaaaa Aaaaaaa Aaaa Aaa Aaaaa Aaaaaaaaaa Aaaaaaaaaa Aa Aaaaaaaaaaaa Aaaaaaaaaa Aaaaaaaaaa Aa Aaaaaaa Aa Aaaaaaaaa Aaaaaa Aaaa Aaaaaaaaa Aa Aaaaa Aaaaaaaa Aaaaaaaaaa Aaaaaaaaaaaaaaaa Aaaaaaa
Aaaaaaaaa Aaa Aaaaaaaaa Aaaaaaaa Aaaa Aaa Aaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaa Aaa Aaaaaaa Aaaaaaa Aaaaaaaa Aa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaa Aaaaa Aaaaaaaaaa Aaa Aaa Aaaaaa Aaaaa Aaaaaa Aaaaaa Aaa Aaaaaaaa Aaaa Aaa Aaaaaa Aaaaaaa Aaa Aaaa Aaaaa Aaaaaa Aaaa Aaaaa Aaaaaaa Aa Aaa Aaaaa Aaa Aaaaaaaaaaaaa Aaaa Aaaaa Aaa Aaa Aaaaaaaaa Aaaa Aaa Aaaaaaaa Aaaaaaaaa Aa Aaa Aaaaaa
🔒Examines how a trusted UI-process broker handled untrusted frame identifiers across the Site Isolation boundary, and what cross-origin exposure the gap allowed.
Subscribe to read more
Audit directions
a Aaaaaaaaaaaa Aaa Aaaaaaaa Aaaa Aaaaaaaaa Aa Aaaaaaa Aaaaaaaaaaaaaa Aaaaaaa Aa Aaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaa Aaaaaaa Aaaaaaaaaaaaa Aaaaaaaaaaaaaaaa Aaaaaaa Aaa Aaaaaaaaaaaaa Aaaaaaaaaaaaaaa Aaaaaaa Aaaaa Aaaaa Aaaaaaaaaaaaaaaaaaaa Aaa Aaaaaaaaaaaaaa Aaaaaaaa Aaaa Aaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaa Aa Aaaaaaaaa Aaaaa Aa Aaaaaaaaaaaaaaaaa Aaaaa Aaaa Aaaaaaaaaa Aaaaaa Aaaa Aaaaaaaa Aaaaaaaaaaa Aaa Aaaaaaaaaaaaaaaaaaaaaaaaa Aaa Aaaaaa Aaaaaaaaaaaaaaa Aaaaaaaaa Aaaaa Aa Aaaaaaaa Aaaaaaaaa Aaa Aaaaaaaaaaaaaaaaaaaaaaaa Aaa Aaaaaaaaaaaaaaaaa Aaaaaaaaaa Aa Aaaaaaaaaaaaaa Aaaaaa
a Aaaaaaaaaa Aaaaaaaaaa Aaaaaaa Aa Aaaaaaaa Aaaaaaaaa Aaaaaaaa Aa Aaaaaaaaaa Aaaaaaaaa Aaaaaa Aaa Aaaaaaa Aaaaaa Aa Aaaaaaaaaaaaaaaaaaaa Aaaaaa Aa Aaaaaaaaaaaaaaaaaaaaaaaaaa Aaa Aaa Aaaaaaa Aaaaaa Aaaaaaaaaa Aaaaaaaaaa Aaaaaaaaaaa a Aaaaaaa a Aaaaaaaaaaaaaaaa Aaaaa Aaaaaa Aaaaaaa Aaaaaaaa Aaaaa Aaaaaaa Aa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aa Aaa Aaaa Aaaaaaa Aaaa a Aaaaa Aaaaa Aaaaaaaa Aaaaa Aa Aa a Aaaaaaaaa Aaaaaaaa
a Aaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaa Aaaa Aaaa Aaa Aaaa Aaaaa Aaaaaaaaaa Aaaaaaaaaaaa Aaaaaaa Aaaaaaaaaaaaaaaaaa Aaaaaaaa Aaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaa Aa Aaaaaaaaaaaaaaaaaaaaaaaa Aa Aaaaaa Aaa Aaa Aa Aaaaaa Aaaaa Aaa Aa Aaaaaaaaa Aa Aaaaaaa Aa Aaa Aaaaaaaaaa Aaaaaaa Aaaaaaa Aa Aaaaa Aaaaa Aaaaaa Aaa Aaaa Aaa Aaa Aaaaaaa Aaaaa
🔒Multiple reusable audit directions for cross-process identifier validation under Site Isolation, with concrete IPC entry points to start from.
Subscribe to read more