[6] DedicatedWorker WebSocket handshake skips ITP third-party cookie blocking
Severity: Low | Component: WebCore/WebKit WebSocket stack and NetworkProcess ITP | a6b2961
Rated Low because the diff closes a privacy gap where a DedicatedWorker WebSocket handshake carried third-party cookies that ITP intends to strip; the impact is cross-site tracking/identity correlation reachable from ordinary web content, not memory corruption or cross-origin script access, and it only matters when third-party cookie blocking is enabled.
DedicatedWorker WebSocket connections were not subjected to ITP third-party cookie blocking, unlike DedicatedWorker fetch requests which already carried isInitiatedByDedicatedWorker through NetworkResourceLoadParameters. The patch threads a new isInitiatedByDedicatedWorker flag from the worker thread through WorkerThreadableWebSocketChannel::Bridge::initialize() — where it is derived via is<DedicatedWorkerGlobalScope>(scope) — into the WebSocketTaskCocoa constructor, where it replaces the previous shouldBlockCookies() call with thirdPartyCookieBlockingDecisionForRequest(..., isInitiatedByDedicatedWorker), so the same policy applied to worker fetch requests now applies to worker WebSocket handshakes.
Source/WebCore/Modules/websockets/WorkerThreadableWebSocketChannel.cpp
void WorkerThreadableWebSocketChannel::Bridge::initialize(WorkerGlobalScope& scope)
{
...
- m_loaderProxy->postTaskToLoader([&semaphore, &peer, ..., provider = m_socketProvider](ScriptExecutionContext& context) mutable {
- peer = mainThreadInitialize(context, workerThread.get(), workerContextIdentifier, WTF::move(workerClientWrapper), taskMode, WTF::move(provider));
+ auto isInitiatedByDedicatedWorker = is<DedicatedWorkerGlobalScope>(scope) ? IsInitiatedByDedicatedWorker::Yes : IsInitiatedByDedicatedWorker::No;
+ m_loaderProxy->postTaskToLoader([&semaphore, &peer, ..., provider = m_socketProvider, isInitiatedByDedicatedWorker](ScriptExecutionContext& context) mutable {
+ peer = mainThreadInitialize(context, workerThread.get(), workerContextIdentifier, WTF::move(workerClientWrapper), taskMode, WTF::move(provider), isInitiatedByDedicatedWorker);
semaphore.signal();
});
Source/WebKit/NetworkProcess/cocoa/WebSocketTaskCocoa.mm
- // previously: shouldBlockCookies(...)
+ // now: thirdPartyCookieBlockingDecisionForRequest(..., isInitiatedByDedicatedWorker)
LayoutTests/http/tests/websocket/tests/hybi/resources/websocket-blocked-sending-cookie-as-third-party-worker.js
+let ws = new WebSocket("ws://localhost:8880/websocket/tests/hybi/websocket-blocked-sending-cookie-as-third-party");
+ws.onopen = () => { /* PASS: request did not contain cookies */ };
+ws.onerror = () => { /* FAIL: request contained cookies */ };
Patch Details
The patch threads a new IsInitiatedByDedicatedWorker enum (enum class IsInitiatedByDedicatedWorker : bool { No, Yes }) from the worker thread down to the Cocoa network WebSocket task. In Bridge::initialize() the flag is derived via is<DedicatedWorkerGlobalScope>(scope) and captured into the cross-thread task posted to the loader. It is passed through mainThreadInitialize() → Peer::create()/Peer::Peer() → ThreadableWebSocketChannel::create(Document&, ...) → SocketProvider::createWebSocketChannel(). On the WebKit side the same parameter is added to the CreateSocketChannel IPC message and threaded through NetworkConnectionToWebProcess::createSocketChannel(), NetworkSocketChannel, NetworkSession::createWebSocketTask(), and NetworkSessionCocoa::createWebSocketTask() → WebSocketTask. The load-bearing change is in the WebSocketTask (Cocoa) constructor, where the unconditional shouldBlockCookies() call is replaced with thirdPartyCookieBlockingDecisionForRequest(..., isInitiatedByDedicatedWorker). The bulk of the diff is mechanical signature plumbing across Curl/Soup/Legacy/Empty implementations.
Inconsistent enforcement of a privacy policy across sibling request paths: the worker-origin signal that gates third-party cookie blocking was carried for fetch but dropped for WebSocket handshakes.
Background
ITP (Intelligent Tracking Prevention) is a WebKit privacy feature that, among other things, blocks cookies on cross-site (third-party) requests for tracker-classified domains or when third-party cookie blocking is enabled. A DedicatedWorker is a worker tied to a single owning document; is<DedicatedWorkerGlobalScope>(scope) distinguishes it from shared/service workers. A WebSocket handshake is the initial HTTP Upgrade request a new WebSocket(url) issues; like any HTTP request it can carry cookies for the target origin. Because workers run off the main thread, WebSocket setup is marshalled to the main/loader thread via Bridge::initialize() → postTaskToLoader → mainThreadInitialize, which builds a main-thread Peer that owns the real ThreadableWebSocketChannel. thirdPartyCookieBlockingDecisionForRequest and shouldBlockCookies are two NetworkProcess decision routines for whether a request should send cookies; the former takes the worker-origination signal as input so it can apply the same policy used for worker fetches.
Analysis
This is a logic error / privacy-policy bypass — an ITP third-party cookie-blocking gap, not a memory-safety issue. Before the fix, the WebSocket connection path originating from a DedicatedWorker did not propagate the fact that the request was worker-initiated down to the network layer. The Cocoa WebSocketTask constructor decided third-party cookie handling with a plain shouldBlockCookies() call that lacked the worker context the equivalent fetch path already carried.
Aaaaa Aaaaaaaaaaa Aaaaaaaaaaaaaaa Aaaaaaaa Aaaaaaa Aa Aaaaaaa Aaa Aaaaaaa Aa a Aaaaaaaaaaa Aa Aaaaaaaaaaa Aaaaaaa Aaa Aaaaaaa Aa Aaa Aaaaaaaaa Aa a Aaaaaaa Aaaaaaa Aaa Aaaaaa Aaaaaaa Aaa Aaaaaaaaa Aaaaaaaaa Aa a Aaaaaaaaaaaa Aaaaaaaa Aaaa Aaaaaa a Aaaaaaaaaaaaaaa Aaa Aaaaaaaaa Aaaaa a Aaaaaa Aaaa Aaa Aaa Aaaaa Aaaaaaaaaaa Aaaaaaaa Aa Aaa Aaaaaaaaa Aaaaaaa Aaaaaaa Aaa Aaaaaa Aaaaaaa Aa Aaaaaa Aaa Aaaaa Aaaaaa Aaaa Aaaaaaaaa Aaaaaaa Aaaaa Aaaaaaaaaaa Aaaaaaa Aaa Aaa Aa Aaaaaaaaaaaaaaaaaaaaaaaa Aaaa a Aaaaaaaaaaaa Aaaaaaaaa Aa Aaaaaa Aaaa a Aaaaaa Aaaaaaaaa Aa Aaaaaaaa Aaaa Aa Aaaaaaaaaaaaaaaaa Aaaaa Aaa Aaaaaaaaaaa Aaaaaaa Aa a Aaaaaa Aaaaaaa Aaaa Aaaa a Aaaaaaaaaaaaaaa Aaaa a Aaaaaaaaaaaa Aaaaaaaaaaa Aa Aaaa Aaaaaa Aaaaa Aaaaaaaaaaa Aaaaaa Aaaaaaaa Aa Aaaaaaaa Aaaaaa Aaa Aaa Aaa Aaaaaaaaa Aaaaaaa Aaa Aaaaaaaa Aaaaaaa Aa Aaa Aaaaaaaaaaaa Aaaaaaaaa Aaaaa Aaa Aaa Aaaa Aa Aaaaaaaaa Aaaaaaaa Aaaaaa Aaaaaa
Aaaa Aaaaaaaaaaaaa Aaaaaaa Aaa Aaaaaaa Aaaaaaaa Aaaaaaaa Aa Aaa Aaaaaaaaaaa Aaaaaa Aaaaaaaaa Aaa Aaaaaa Aaaaaaa Aaa Aaaaaaaa Aaaaaaaaaa Aa Aaaaa Aaaa Aaaaaaaaaaa Aaaaaa Aaaaaaaa Aa Aaaaaaaa a Aaaaaaaaaaaa Aaaaaaaaa Aaaaaaaaa Aaaa a Aaaa Aa Aaa Aaaaaaa Aaaa Aaa Aaaaa Aaa Aaaaa Aaaaaaa Aaaaaaaa Aaaaaa Aaa Aaa Aaaa Aaaa Aaa Aaaaaaaaaaaaaaa Aaaaa Aaa Aaa Aaaaaaaa Aaa Aaaaaaaaaaaaaaa Aaaaaaaaa Aaaaaaaaaaa Aaaaaaaa Aaaaaaaaaa Aaaaaaaaaaaaaaaaa Aaaaaaaaaaa Aaa Aa Aaaaaaaa Aa Aaaaaaaa Aa Aaaa Aaaaaaaaa Aa Aaaaaaaaaaaa Aaaaaa Aaaaaa Aaaaaaaa
Aaaaaaa Aaa Aaaaaaaa Aaaaaaaa Aa Aaaaaa Aaa Aaaaaaaaaa Aaaaaaaaaa Aaaaaaaaaaaaa Aaaaa Aaaaaaaa Aaaaaaa Aaaaa Aaaaaa Aa Aaaaaaaaa Aa Aaaaaaaaaaaa Aa Aaaaaaaaaaaa Aaa Aaaaaaaa Aa Aaaaaa Aa Aaaaaaaaaaaaaa Aaaaaaaaaaaaa Aaaa a Aaa Aaaaaaaaaa Aaaaaa Aa Aaaaaaaaaa Aaa Aaa Aaaaa Aaaaaaa Aaaaa Aaaaaaaa Aaaaaa Aaa Aaaa Aaaaaa Aaaaaaaa Aaaaa Aaaa Aa Aaaaaaaaaaaa Aaaaaaaa
Aaaaaaaaa Aaa Aaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaaaa Aaaaaaa Aaa Aaaaaaaa Aaaaa Aaaaaaaaaaa Aaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaa Aaa Aaaaaa Aaaaaaa Aa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaa Aaaaaaaaaa Aa Aaa Aaaaaa Aaaaaaaa Aaa Aaaaaaa Aaaa Aaaaa Aaa Aaaaaaaa Aaaaa Aaa Aaaaaaaaaa Aaaaaaaaaaaaaaa Aaaaaa Aaaaa Aa Aaa Aaaaaaaaa Aaaaa Aaaaa Aaa Aaaaaa Aaa Aaa Aaa Aaa Aaaaa Aaa Aaaaaaaaaaaa Aaaaaaaaa Aa Aaa Aaaaaa
🔒How an ITP privacy boundary that held for one request type silently failed for another, and what an embedded third party could observe before the fix.
Subscribe to read more
Audit directions
a Aaa Aaaaaaaaaaaaaaaa Aaaaaa Aaaaaaa Aa Aaa Aaaaaaa Aaaa Aaaaaaa Aaa Aaaaaaa Aa a Aaaaaaa Aaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaa Aaa Aaaaa Aaaaaaaaaa Aaaaaaaaaa Aaaaaaaaaa Aaa Aaa Aaaa Aaaaaaaaaaaaaaaaaa Aaa a Aaaaa Aaaaaaa Aaaaaaaaaaaaaa Aaa Aaaaaaaaaaaaa Aaaaa Aaaa a Aaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaa Aaa Aaaaaaaaaa Aa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaa Aaaaa Aaaaaaaaaaaaaa Aaaaaa Aaaaaaaaaa Aaaaa Aa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaa Aaa Aaaaaaaaaaa Aaaaaa Aaaaa Aaaaaaaaa Aaaaa Aaaaaaaaaaaaa Aaaa Aaaaa Aaaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
a Aaaaaaaaaaa Aaaa Aaaaa Aa Aaaaaaaaaaaaaaaaaaaaa Aa Aaa Aaaaaaaaaaaaaaaaa Aaaaaaa Aaaa Aaaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aa Aaaaaaaaa Aaaaa Aaaaaaaa Aaaaaa Aaaaa Aaaa Aaa Aaaaaaaaaaaaaaaaaa Aaaaaa Aaaaaa Aaaa Aaaaaaaaaa Aaaa Aaaaaaaaaaa Aaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaa Aaa Aaaaaaaaa Aaaaaaaaaaaa Aaaaaa Aaaaaaaa Aaa Aaaaaa Aaa Aaaa Aaaaaaaaaa Aaaaa
a Aaaaaaaaaaaaaa Aaaaaaaaaaa Aaaa Aaaaa Aaaaaaa Aaaaaaaaaaaaa Aaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaa Aa Aaaaaaa Aaaaaa Aaaaaaaaaa Aa Aaaaaaa Aaaaaaaaaaaaaaaaaa Aaaaaaa Aaaaaaaa Aa Aaa Aaaaaa Aaaaaa Aaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aa Aaaaaaaa Aaaa Aaa Aaaaaaaaaaaa Aaaaaa Aaaaaa Aaaa Aaaaaaaaaa Aa Aaa Aaaa Aaaaaa Aaaaa Aaa Aaaaa Aaaa Aaa Aa Aaaaaaaaaaaa Aaaaa Aaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaa Aaaaaaa Aaaaaa Aaaaaaa Aa Aaaaaaaaaaa
🔒Three reusable audit directions covering parallel request paths and cross-thread provenance loss in the worker networking stack, with concrete starting call sites.
Subscribe to read more