Medium CVSS 6.5 webkit Logic Error 🔧 Commit mapped

Overview

Medium
Severity
6.5
CVSS
No
Exploited ITW
Fixed
Fix Status
DescriptionA maliciously crafted webpage may be able to fingerprint the user
ComponentWebCore Workers
Bug ClassLogic Error
Tracker271159
Fix commitc33df2d32360 (WebKit/WebKit) +215/-41
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:N
CISA KEVNot listed
CreditedJoe Rutkowski (@Joe12387) of Crawless and @abrahamjuliot
Disclosed2024-05-13

Background

Canvas fingerprinting
Deriving a stable identifier from subtle per-device/OS differences in canvas/OffscreenCanvas pixel output.
Noise injection (Advanced Privacy Protections)
In Private Browsing WebKit perturbs canvas readback using a per-origin hash salt so the pixels cannot be used as a fingerprint.
Shared/service workers and remote Page
These workers run in a separate, potentially-remote Page; state like the noise salt must be explicitly plumbed to them or it is absent.
WorkerParameters plumbing
The mechanism that carries context state (including privacy flags/salt) from the originating document to a worker global scope.

Root Cause Analysis

This fixes a canvas anti-fingerprinting gap: in Private Browsing, pixel-readback noise injection was not applied to OffscreenCanvas used inside shared workers and service workers. In Private Browsing (Advanced Privacy Protections), each ScriptExecutionContext carries a per-origin noise-injection hash salt and AdvancedPrivacyProtections flags, sourced from the document loader, and these are used to perturb pixels read back from canvas/OffscreenCanvas so the output cannot be used as a stable fingerprint. For dedicated workers the salt/flags were already plumbed via WorkerParameters to the WorkerGlobalScope, so OffscreenCanvas there got noise. But shared workers and service workers run their OffscreenCanvas code in a separate, potentially-remote Page that had neither the hash salt nor the AdvancedPrivacyProtections flags, so readback in those contexts received NO noise — letting a site fingerprint the device/OS via OffscreenCanvas from a shared/service worker, bypassing the Private Browsing protection.

The fix extends the AdvancedPrivacyProtections plumbing to those two worker types: it adds an override point (ScriptExecutionContext::advancedPrivacyProtections, implemented by Document via the top document’s loader and by workers via passed-in parameters), threads the flags through WorkerScriptLoader / WorkerInitializationData / WorkerParameters, and lets Page::setupForRemoteWorker receive the privacy protections when initializing the remote Page.

The restored invariant is that canvas/OffscreenCanvas readback noise is applied in all worker types (dedicated, shared, service) when Private Browsing protections are active. The test verifies noise injection for OffscreenCanvas in a shared worker.

Key insight
The canvas noise-injection salt and privacy flags were plumbed to dedicated workers but not to shared/service workers, whose remote Page had neither, so OffscreenCanvas readback there was un-noised; extending the plumbing restores noise in all worker types.

Attack Path

  1. Enter Private Browsing The user browses privately, expecting canvas readback to be noised against fingerprinting.
  2. Use OffscreenCanvas in a shared/service worker The page renders to an OffscreenCanvas inside a shared or service worker, whose remote Page lacked the salt and privacy flags.
  3. Read back un-noised pixels Because noise injection was not applied in that context, the readback returns the true, un-perturbed pixels.
  4. Fingerprint the device Derive a stable device/OS fingerprint from the un-noised output, defeating the Private Browsing protection.

Impact Assessment

A privacy/anti-fingerprinting gap in the WebContent process with no memory corruption: OffscreenCanvas readback in shared/service workers escaped Private Browsing noise injection, allowing device/OS fingerprinting that the protection is meant to prevent. The risk is tracking/deanonymization of Private Browsing users, not code execution.

Changed Functions

FunctionChangeNotes
ScriptExecutionContext::advancedPrivacyProtections (override) / Document::advancedPrivacyProtections / noiseInjectionPolicy
Source/WebCore/dom/Document.cpp
modified Adds an override point returning the active advanced-privacy-protection flags; Document sources them from the top document's loader.
Page::setupForRemoteWorker
Source/WebCore/page/Page.cpp
modified Lets shared/service workers pass in privacy protections when initializing the remote Page, so its contexts carry the flags.
WorkerScriptLoader (advancedPrivacyProtections) / WorkerInitializationData / WorkerParameters
Source/WebCore/workers/WorkerScriptLoader.cpp
modified Tracks the active privacy protections for the loading worker and plumbs them into WorkerInitializationData/WorkerParameters for shared/service workers.
WorkerGlobalScope / WorkerOrWorkletGlobalScope constructors
Source/WebCore/workers/WorkerGlobalScope.cpp
modified Propagates the passed-in privacy-protection state into the worker global scope so OffscreenCanvas readback applies noise.

Files Changed

  • Source/WebCore/Modules/webaudio/AudioWorkletMessagingProxy.cpp
  • Source/WebCore/dom/Document.cpp
  • Source/WebCore/dom/Document.h
  • Source/WebCore/dom/EmptyScriptExecutionContext.h
  • Source/WebCore/dom/ScriptExecutionContext.h
  • Source/WebCore/page/Page.cpp
  • Source/WebCore/page/Page.h
  • Source/WebCore/workers/Worker.cpp
  • Source/WebCore/workers/WorkerGlobalScope.cpp
  • Source/WebCore/workers/WorkerInitializationData.h
  • Source/WebCore/workers/WorkerMessagingProxy.cpp
  • Source/WebCore/workers/WorkerOrWorkletGlobalScope.cpp
  • Source/WebCore/workers/WorkerOrWorkletGlobalScope.h
  • Source/WebCore/workers/WorkerScriptLoader.cpp
  • Source/WebCore/workers/WorkerScriptLoader.h
  • Source/WebCore/workers/WorkerThread.cpp
  • Source/WebCore/workers/WorkerThread.h
  • Source/WebCore/workers/service/ServiceWorkerClientData.cpp
  • Source/WebCore/workers/service/ServiceWorkerClientData.h
  • Source/WebCore/workers/service/context/ServiceWorkerThread.cpp
  • Source/WebCore/workers/service/context/ServiceWorkerThread.h
  • Source/WebCore/workers/service/context/ServiceWorkerThreadProxy.cpp
  • Source/WebCore/workers/service/server/SWServer.cpp
  • Source/WebCore/workers/service/server/SWServer.h
  • Source/WebCore/workers/service/server/SWServerToContextConnection.h
  • Source/WebCore/workers/shared/SharedWorkerScriptLoader.cpp
  • Source/WebCore/workers/shared/context/SharedWorkerThreadProxy.cpp
  • Source/WebCore/worklets/WorkletGlobalScope.cpp
  • Source/WebCore/worklets/WorkletParameters.h
  • Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerConnection.cpp
  • Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerToContextConnection.cpp
  • Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerToContextConnection.h
  • Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in
  • Source/WebKit/WebProcess/Storage/WebSWContextManagerConnection.cpp
  • Source/WebKit/WebProcess/Storage/WebSWContextManagerConnection.h
  • Source/WebKit/WebProcess/Storage/WebSWContextManagerConnection.messages.in
  • Source/WebKit/WebProcess/Storage/WebSharedWorkerContextManagerConnection.cpp
  • Tools/TestWebKitAPI/Tests/WebKit/AdvancedPrivacyProtections.mm

Audit Directions

  • Privacy-flag plumbing across contexts
    Audit every ScriptExecutionContext subtype (Document, dedicated/shared/service workers, worklets) for consistent propagation of the noise salt and AdvancedPrivacyProtections used by canvas/OffscreenCanvas.
  • Remote-Page state gaps
    Grep Page::setupForRemoteWorker and remote-worker init for other per-origin privacy/security state that a remote Page may be missing.
diff --git a/Source/WTF/wtf/PlatformEnable.h b/Source/WTF/wtf/PlatformEnable.h
index 38d367cb578c..eef9de469a96 100644
--- a/Source/WTF/wtf/PlatformEnable.h
+++ b/Source/WTF/wtf/PlatformEnable.h
@@ -421,10 +421,6 @@
 #define ENABLE_MOUSE_FORCE_EVENTS 1
 #endif
 
-#if !defined(ENABLE_NETSCAPE_PLUGIN_METADATA_CACHE)
-#define ENABLE_NETSCAPE_PLUGIN_METADATA_CACHE 0
-#endif
-
 #if !defined(ENABLE_NOTIFICATION_EVENT)
 #define ENABLE_NOTIFICATION_EVENT 0
 #endif
Loading diff…

Original Bug Report

The reporter's bug is still restricted on the tracker.