CVE-2026-28962
Overview
Impact:
Description: Processing maliciously crafted web content may disclose sensitive user information
Researchers: Luke Francis, Vaagn Vardanian, kwak kiyong / kakaogames, Vitaly Simonovich, Adel Bouachraoui, greenbynox
Key insight. File paths that cross from WebContent to the UI process for attachments must be validated against what the UI process actually vended; trusting web-process-supplied paths permits traversal to arbitrary local files.
Patch Details
diff --git a/Source/WebCore/platform/audio/ios/MediaDeviceRouteController.mm b/Source/WebCore/platform/audio/ios/MediaDeviceRouteController.mm
index 77ece021b66d..bafd2772a91a 100644
--- a/Source/WebCore/platform/audio/ios/MediaDeviceRouteController.mm
+++ b/Source/WebCore/platform/audio/ios/MediaDeviceRouteController.mm
@@ -31,10 +31,12 @@
#if ENABLE(WIRELESS_PLAYBACK_MEDIA_PLAYER)
+#import "Logging.h"
#import "MediaDeviceRoute.h"
#import "MediaSessionHelperIOS.h"
#import "MediaStrategy.h"
#import "PlatformStrategies.h"
+#import <wtf/darwin/DispatchExtras.h>
#import <WebKitAdditions/MediaDeviceRouteControllerAdditions.mm>
#import <pal/ios/AVRoutingSoftLink.h>
Background
Advisory: Apple Security Advisory
| Attribute | Value |
|---|---|
| CVE | CVE-2026-28962 |
| Bugzilla | 309698 |
| Component | WebKit |
| Bug Class | Bypass |
| Severity | medium |
| Commit | c6cd4e07e9afcb0f… |
| Advisory | Apple Advisory |
Terminology
- Attachment elements — WebKit’s <attachment> support (ENABLE(ATTACHMENT_ELEMENT)) for embedding file attachments, which can carry local file paths for upload.
- WebPasteboardProxy — The UI-process side of pasteboard IPC that vends pasteboard data (including file paths) to the WebContent process.
- Allow-list of vended paths — The set of file paths the UI process actually provided; incoming paths from WebContent must be checked against it.
- Sandbox extension — A token the UI/Network process grants so a sandboxed process may access a specific file; must only be issued for legitimately vended paths.
Root Cause Analysis
With attachment elements enabled, WebPasteboardProxy (UI process) returns file paths (pathsForFileUpload) obtained from the pasteboard to the WebContent process, but it did not record which paths it had legitimately vended — ‘Missing validation for incoming file paths from web content process when attachment elements are enabled’. Without an allow-list, a malicious or compromised WebContent process could later reference arbitrary file paths (including path-traversal outside the intended files) in attachment/file operations, and the trusted UI/Network process would act on them, disclosing sensitive local files. The fix adds addAllowedAttachmentFilePaths() and invokes it on every path that vends pasteboard file paths — getPasteboardPathnamesForType, allPasteboardItemInfo (including the iOS HEIC-transcoding continuation, which now captures the IPC::Connection by Ref so the async main-thread hop can still register paths), and informationForItemAtIndex — registering each vended path through WebProcessProxy::addAllowedAttachmentFilePath. The restored invariant is that the WebContent process may only reference attachment file paths the UI process actually provided, so incoming paths can be validated against this per-process allow-list. INFERENCE: the enforcement check that rejects non-allow-listed incoming paths (the consumer of addAllowedAttachmentFilePath) is outside this hunk; the diff establishes population of the allow-list.
Attack Path
1. Enable attachment elements and compromise WebContent
On a build with ENABLE(ATTACHMENT_ELEMENT), the attacker controls (or compromises) a WebContent process that speaks the pasteboard/attachment IPC.
2. Send an arbitrary file path over IPC
WebContent references a file path it never legitimately received (e.g. a path-traversal to a sensitive file) in an attachment/file-upload operation.
3. UI/Network process trusts the path
Pre-patch, with no allow-list of vended paths, the trusted process accepts the incoming path and grants access / creates a sandbox extension for it.
4. Disclose sensitive local files
The contents of files outside the intended set are exposed to web content, disclosing sensitive user information.
Impact Assessment
This is a local-file information-disclosure / path-traversal issue across the WebContent->UI process boundary, not a memory-safety bug. It requires attachment elements to be enabled and a WebContent process willing to send crafted IPC (a malicious or already-compromised web process), so it is a defense-in-depth boundary hardening rather than a direct remote primitive; its payoff is reading files outside the intended attachment set.
Audit Directions
Other IPC accepting file paths from WebContent
Audit UI/Network-process IPC endpoints that receive file paths or create SandboxExtension handles from WebContent-supplied strings without checking an allow-list; the tell is SandboxExtension::createHandle(pathFromWebProcess, …).
Attachment / file-upload path flows
Trace pathsForFileUpload and attachment file paths end-to-end and confirm every consumer validates against addAllowedAttachmentFilePath (the allow-list this commit populates).
Async IPC continuations dropping the connection
Look for async transcoding/dispatch continuations that previously dropped the IPC::Connection; ensure they capture it (by Ref) so per-connection allow-listing/validation still runs on the main-thread hop.
Changed Functions
| Function | File | Change | Note |
|---|---|---|---|
addAllowedAttachmentFilePaths |
Source/WebKit/UIProcess/Cocoa/WebPasteboardProxyCocoa.mm |
added | Helper (guarded by ENABLE(ATTACHMENT_ELEMENT)) that registers each vended path via WebProcessProxy::addAllowedAttachmentFilePath for the page’s web process. |
WebPasteboardProxy::getPasteboardPathnamesForType |
Source/WebKit/UIProcess/Cocoa/WebPasteboardProxyCocoa.mm |
modified | Registers the pathnames it returns to WebContent as allowed attachment file paths. |
WebPasteboardProxy::allPasteboardItemInfo |
Source/WebKit/UIProcess/Cocoa/WebPasteboardProxyCocoa.mm |
modified | Registers pathsForFileUpload on every return path, including the iOS HEIC-transcoding continuation, which now captures the IPC::Connection by Ref so the async main-thread dispatch can still allow-list the paths. |
WebPasteboardProxy::informationForItemAtIndex |
Source/WebKit/UIProcess/Cocoa/WebPasteboardProxyCocoa.mm |
modified | Registers the item’s pathsForFileUpload as allowed attachment file paths before returning them to WebContent. |
Files Changed
Source Files
Source/WebKit/UIProcess/Cocoa/WebPasteboardProxyCocoa.mmSource/WebKit/UIProcess/WebPageProxy.cppSource/WebKit/UIProcess/WebProcessProxy.cppSource/WebKit/UIProcess/WebProcessProxy.h
Test Files
Tools/TestWebKitAPI/Tests/WebKit/WKWebView/WKAttachmentTests.mm
Regression Test
The fix ships this proof-of-concept / regression test:
diff --git a/Tools/TestWebKitAPI/Tests/WebKit/WKWebView/WKAttachmentTests.mm b/Tools/TestWebKitAPI/Tests/WebKit/WKWebView/WKAttachmentTests.mm
index 4aee71f4c649..4a7e3ea9d288 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit/WKWebView/WKAttachmentTests.mm
+++ b/Tools/TestWebKitAPI/Tests/WebKit/WKWebView/WKAttachmentTests.mm
@@ -45,6 +45,7 @@
#import <WebKit/WKWebViewPrivateForTesting.h>
#import <WebKit/WebArchive.h>
#import <WebKit/WebKitPrivate.h>
+#import <WebKit/_WKFeature.h>
#import <WebKit/_WKUserStyleSheet.h>
#import <ranges>
#import <wtf/RetainPtr.h>
@@ -2746,6 +2747,63 @@ TEST(WKAttachmentTestsIOS, PasteRichTextCopiedFromNotes)
#endif // PLATFORM(IOS_FAMILY)
+#if PLATFORM(MAC) && ENABLE(IPC_TESTING_API)
+
+TEST(WKAttachmentTestsMac, RegisterAttachmentIdentifierFromFilePathWithUnauthorizedPathTerminatesProcess)
+{
+ RetainPtr configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+ [configuration _setAttachmentElementEnabled:YES];
+
+ WKPreferencesSetCustomPasteboardDataEnabled((__bridge WKPreferencesRef)[configuration preferences], YES);
+ for (_WKFeature *feature in [WKPreferences _features]) {
+ if ([feature.key isEqualToString:@"IPCTestingAPIEnabled"])
+ [[configuration preferences] _setEnabled:YES forFeature:feature];
+ if ([feature.key isEqualToString:@"IgnoreInvalidMessageWhenIPCTestingAPIEnabled"])
+ [[configuration preferences] _setEnabled:NO forFeature:feature];
+ }
+
+ RetainPtr webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 500, 500) configuration:configuration.get()]);
+ [webView synchronouslyLoadHTMLString:attachmentEditingTestMarkup];
+
+ RetainPtr navigationDelegate = adoptNS([TestNavigationDelegate new]);
+ [webView setNavigationDelegate:navigationDelegate.get()];
+
+ [webView evaluateJavaScript:
+ @"IPC.sendMessage('UI', IPC.webPageProxyID, IPC.messages.WebPageProxy_RegisterAttachmentIdentifierFromFilePath.name, ["
+ " {type: 'String', value: 'fake-identifier'},"
+ " {type: 'String', value: 'application/octet-stream'},"
+ " {type: 'String', value: '/etc/passwd'}"
+ "])"
+ completionHandler:nil];
+
+ [navigationDelegate waitForWebContentProcessDidTerminate];
+}
+
+TEST(WKAttachmentTestsMac, PastedFileURLsUseAuthorizedPaths)
+{
+ NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
+ [pasteboard clearContents];
+ [pasteboard declareTypes:@[NSFilenamesPboardType] owner:nil];
+ [pasteboard setPropertyList:@[testPDFFileURL().path, testImageFileURL().path] forType:NSFilenamesPboardType];
+
+ RetainPtr<NSArray<_WKAttachment *>> insertedAttachments;
+ RetainPtr webView = webViewForTestingAttachments();
+ {
+ ObserveAttachmentUpdatesForScope observer(webView.get());
+ [webView _synchronouslyExecuteEditCommand:@"Paste" argument:nil];
+ insertedAttachments = [observer.observer() inserted];
+ EXPECT_EQ(2U, [insertedAttachments count]);
+ }
+
+ [webView expectElementCount:1 querySelector:@"ATTACHMENT"];
+ [webView expectElementCount:1 querySelector:@"IMG"];
+
+ for (_WKAttachment *attachment in insertedAttachments.get())
+ EXPECT_GT(attachment.info.data.length, 0U);
+}
+
+#endif // PLATFORM(MAC) && ENABLE(IPC_TESTING_API)
+
} // namespace TestWebKitAPI
#endif // PLATFORM(MAC) || PLATFORM(IOS) || PLATFORM(VISION)