← WebKit Silent-Fix Report — 2026-W25

0d3713dbb6  GetPasteboardPathnamesForType IPC allows types-only pasteboard access to read file paths

severity high class Bypass confidence 0.85 WebKit UIProcess Pasteboard exploitable-grade
Charlie Wolfe Mon Jun 15 21:11:06 2026 -0700 full: 0d3713dbb6d9bfab077d388293fca5beb3a05e29 bug report ↗ view on GitHub ↗
Primitive: read file paths with types-only pasteboard access
Triage note: Access-control bug allowing a web process to exfiltrate pasteboard file paths without proper permission.
Contents

The bug at a glance

This is an access-control bypass in the UI process pasteboard IPC that lets a sandboxed WebContent process read local filesystem paths (and their sandbox extensions) during a drag-over, before any drop or user confirmation. Disclosure of absolute file paths and, worse, sandbox extension handles undermines the sandbox boundary and can seed further exploitation, but it is an information-disclosure/permission bug rather than direct memory corruption. Reachable by any page during an ordinary drag interaction, so high severity is appropriate.

When a user drags a file over a web page, the UI process temporarily grants the web process ’types-only’ pasteboard access (it may learn what kinds of data exist, but not read them) until the user actually drops. A confused check on the GetPasteboardPathnamesForType IPC treated types-only access as sufficient, so a page could, purely from a dragover handler, ask the UI process for the dragged files’ pathnames and sandbox extensions before dropping.

Root cause

WebPageProxy::dragEntered() grants the web process ’types-only’ pasteboard access during drag-over so scripts can react to available data types without reading the underlying data. The privilege ladder has two rungs: canAccessPasteboardTypes() (true for types-only, granted at drag-enter) and canAccessPasteboardData() (requires both types and data access, granted only at drop time).

WebPasteboardProxy::getPasteboardPathnamesForType() runs in the UI process and returns, to the web process, the absolute pathnames of files on the pasteboard together with sandbox extension handles that let the web process actually open those files. It was gated by canAccessPasteboardTypes(connection, pasteboardName) – with a standing FIXME noting this should consult canAccessPasteboardData() instead. Because types-only access satisfies canAccessPasteboardTypes(), a WebContent process could invoke this IPC during drag-over, before any drop, and receive local file paths and sandbox extensions it was never authorized to see. That is both a filesystem-layout information leak and a handing-out of sandbox extensions ahead of user consent.

The primary fix changes the gate to if (!canAccessPasteboardData(connection, pasteboardName)) return completionHandler({ }, { }); so pathnames and extensions are only returned once data access exists, i.e. at drop time.

Tightening that check would have broken a legitimate drag-over consumer: DragData::containsPromise() previously called getPathnamesForType(legacyFilesPromisePasteboardTypeSingleton()) during drag-over to decide whether the drag carried a file promise, which under the stricter check would now be denied. The patch reworks containsPromise() to instead consult m_promisedFileMIMETypes – already populated by the UI process from NSFilePromiseReceiver items in draggingEntered/draggingUpdated and sent to the web process, so it needs no pasteboard access at all. containsPromise() becomes return !m_disallowFileAccess && !m_promisedFileMIMETypes.isEmpty();, which also drops the old (incorrect) files.size() == 1 restriction. The new API test PasteboardPathnamesRequireDataAccess uses the IPC testing API to send WebPasteboardProxy_GetPasteboardPathnamesForType during a dragover with types-only access and asserts the reply contains no pathnames (pathnameCount == 0).

Key code

Fixed access gate in WebPasteboardProxy::getPasteboardPathnamesForType

    MESSAGE_CHECK_COMPLETION(!pasteboardType.isEmpty(), connection, completionHandler({ }, { }));

    // FIXME removed: previously gated on canAccessPasteboardTypes(), which is true for types-only access.
    if (!canAccessPasteboardData(connection, pasteboardName))
        return completionHandler({ }, { });

    auto dataOwner = determineDataOwner(connection, pasteboardName, pageID, PasteboardAccessIntent::Read);

Patch walkthrough

  • Source/WebKit/UIProcess/Cocoa/WebPasteboardProxyCocoa.mm — getPasteboardPathnamesForType() now gates on canAccessPasteboardData() instead of canAccessPasteboardTypes(), so file paths and sandbox extensions are only returned when full data access exists (drop time). Removes the stale FIXME.
  • Source/WebCore/platform/cocoa/DragDataCocoa.mm — containsPromise() no longer calls pasteboardStrategy()->getPathnamesForType() during drag-over; it returns !m_disallowFileAccess && !m_promisedFileMIMETypes.isEmpty(), relying on already-sent promise MIME types and removing the old files.size() == 1 heuristic.
  • Tools/TestWebKitAPI/Tests/WebKit/WKWebView/mac/DragAndDropTestsMac.mm — Adds PasteboardPathnamesRequireDataAccess (gated on ENABLE(IPC_TESTING_API)): during a dragover it sends the GetPasteboardPathnamesForType IPC via window.IPC and asserts the reply carries no pathnames, proving types-only access can no longer read file paths.

Background

Pasteboard access tiers — WebKit distinguishes ’types-only’ access (the web process may enumerate available data types) from full data access. canAccessPasteboardTypes() is satisfied by the former; canAccessPasteboardData() requires both types and data access.

Drag-over vs drop — During drag-over (dragenter/dragover) the UI process grants only types-only access so pages can respond to hovering without reading contents. Full data access is granted at drop, reflecting the user’s intent to hand the data to the page.

Sandbox extensions — Tokens the UI process issues to let the sandboxed WebContent process open specific files it otherwise cannot. Returning them prematurely via pathname queries would grant filesystem reach before the user dropped anything.

getPasteboardPathnamesForType IPC — A UIProcess message that returns dragged/copied file pathnames plus their sandbox extension handles to the web process. Its access gate determines whether a page can learn local file paths.

File promises / m_promisedFileMIMETypes — macOS drags can carry NSFilePromiseReceiver ‘promise’ items describing files that will be materialized on drop. The UI process extracts their MIME types in draggingEntered/draggingUpdated and forwards them, so the web process can detect promises without touching the pasteboard.

Vulnerability window

  1. Introduction — getPasteboardPathnamesForType() was gated by canAccessPasteboardTypes(), with a FIXME acknowledging it should require data access.
  2. Grant — User begins dragging a file over the page; WebPageProxy::dragEntered() grants the web process types-only pasteboard access.
  3. Trigger — A dragover handler sends WebPasteboardProxy_GetPasteboardPathnamesForType for NSFilenamesPboardType while only types-only access exists.
  4. Leak — The UI process returns absolute file pathnames and sandbox extensions to the web process before any drop or confirmation.
  5. Impact — The page learns local filesystem paths (usernames, directory structure) and gains sandbox extensions ahead of consent, weakening the sandbox boundary.
  6. Fix — 315268@main requires canAccessPasteboardData() and reworks containsPromise() to use m_promisedFileMIMETypes, so paths/extensions are withheld until drop.

Proof of concept

The added API test’s dragover handler uses the IPC testing API to send WebPasteboardProxy_GetPasteboardPathnamesForType with the drag pasteboard’s name and NSFilenamesPboardType while only types-only access has been granted. Pre-fix the reply buffer contained the dragged file’s pathname/sandbox-extension data (pathnameCount would be 1); post-fix the reply is empty and pathnameCount is 0. The test asserts EXPECT_EQ(0, count). This requires ENABLE(IPC_TESTING_API); a real attacker would instead send the raw IPC directly from the WebContent process, but the observable primitive – receiving file paths during drag-over – is the same.

document.body.addEventListener('dragover', function(e) {
    e.preventDefault();
    if (pathnameCount >= 0 || !window.IPC || !window.pasteboardName)
        return;
    var reply = IPC.sendSyncMessage('UI', 0,
        IPC.messages.WebPasteboardProxy_GetPasteboardPathnamesForType.name,
        1000,
        [
            {type: 'String', value: window.pasteboardName},
            {type: 'String', value: 'NSFilenamesPboardType'},
            {type: 'bool', value: 0}
        ]);
    if (reply && reply.buffer) {
        var buf = new Uint8Array(reply.buffer);
        pathnameCount = buf.length > 32 ? 1 : 0;
    } else {
        pathnameCount = 0;
    }
});

Exploitation

  1. Setup — Attacker page registers dragover handlers; the attack only requires the user to drag a file (or file promise) over the page, a common interaction.
  2. Primitive — From WebContent, send GetPasteboardPathnamesForType during drag-over to receive absolute file pathnames and sandbox extension handles without a drop.
  3. Info disclosure — Leaked paths reveal the username and directory layout; leaked sandbox extensions can grant the web process read access to those files ahead of user consent.
  4. Escalation — Path/username disclosure aids targeting of further exploits; premature sandbox extensions can broaden a compromised WebContent’s filesystem reach. No memory corruption on its own.

Detection & hunting

For defenders and SOC / detection engineers:

  • GetPasteboardPathnamesForType during drag-over
  • Pages that query pasteboard paths from dragover handlers
  • Unexpected sandbox-extension issuance

Audit directions

  • Other pasteboard IPCs
  • Drag-over consumers of pathnames
  • Sandbox extension lifetimes
  • iOS/UIKit parity

Before / after

Loading diff…