CVE-2026-43708
Overview
Background
- Partitioned cookies
- Opt-in cookie partitioning isolates third-party cookies per top-level site to prevent cross-site tracking/leakage.
- respondsToSelector on nil
- Objective-C sends to nil are no-ops and -respondsToSelector: on nil returns NO, so a nil-guarded block silently does nothing.
- ensureMutableRequest
- Lazily materializes the mutable NSURLRequest; without calling it the request may be nil when checked.
Root Cause Analysis
This fixes a third-party cookie partitioning bypass on WebSocket requests that let cookies leak cross-site. In NetworkSessionCocoa::createWebSocketTask, the code that applies opt-in cookie partitioning was guarded by [mutableRequest respondsToSelector:@selector(_setAllowOnlyPartitionedCookies:)]. mutableRequest is produced lazily via ensureMutableRequest(); at that point it could be nil/unmaterialized, and -respondsToSelector: on nil returns NO, so the entire block that computes the third-party cookie blocking decision and calls _setAllowOnlyPartitionedCookies: was skipped.
As a result, a cross-site WebSocket did not have partitioned-cookie / third-party-cookie-blocking policy applied, so it could carry the user’s full (unpartitioned) first-party cookies to a third-party host — cross-site data exfiltration / tracking.
The fix changes the guard to [ensureMutableRequest() respondsToSelector:…], forcing the mutable request to be materialized so the selector check succeeds and the partitioning decision (thirdPartyCookieBlockingDecisionForRequest … AllExceptPartitioned) is actually applied via _setAllowOnlyPartitionedCookies:.
The restored invariant is that WebSocket requests receive the same third-party cookie partitioning/blocking decision as other requests. The regression test loads siteB, which opens a WebSocket to siteA, and asserts the WebSocket handshake to siteA carries NO Cookie header (third-party cookies blocked/partitioned).
Attack Path
- Set cookies on the target The user visits siteA which sets cookies (including SameSite=None).
- Open a cross-site WebSocket From attacker siteB, script opens a WebSocket to siteA (a third-party context).
- Skip partitioning Because the guard tested a nil mutableRequest, the partitioned-cookie policy is never applied to the WebSocket.
- Leak cookies cross-site The WebSocket handshake carries siteA’s unpartitioned cookies to the third-party connection, exfiltrating them cross-origin.
Impact Assessment
Changed Functions
| Function | Change | Notes |
|---|---|---|
NetworkSessionCocoa::createWebSocketTaskSource/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.mm |
modified | Uses ensureMutableRequest() (materializing the request) in the respondsToSelector guard so _setAllowOnlyPartitionedCookies: and the third-party cookie blocking decision are actually applied to WebSocket requests. |
Files Changed
Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.mmTools/TestWebKitAPI/Tests/WebKit/WKWebView/WKHTTPCookieStore.mm
Audit Directions
- Same file: nil-guarded policy blocksGrep NetworkSessionCocoa.mm for respondsToSelector: on mutableRequest/lazy objects guarding security policy application; ensure the object is materialized first.
- WebSocket vs HTTP parityCompare createWebSocketTask against the HTTP request path to confirm cookie partitioning, privacy proxy, and tracker-blocking decisions are applied identically.