CVE-2026-7954
Overview
Background
- Shared Storage
- a Privacy Sandbox web API that lets a site write to a shared, origin-scoped key/value store and read it only inside a privacy-preserving worklet.
- `SharedStorageWorkletHost`
- the browser-process object that owns a Shared Storage worklet and gates its operations through permission/allowed checks.
- Cross-origin data opt-in
- a requirement that when a worklet operates on another origin’s Shared Storage data, that other origin must have explicitly opted in; the result is tracked in
data_origin_opt_in_state_(a success flag plus a debug message) and demanded byneeds_data_origin_opt_in_. - `IsSharedStorageAllowed`
- the gate called before a Shared Storage operation proceeds, returning whether the operation is permitted and optionally a debug message.
Root Cause Analysis
Pre-patch, SharedStorageWorkletHost::IsSharedStorageAllowed did not consult needs_data_origin_opt_in_ or data_origin_opt_in_state_ at all; it went straight to the embedder’s GetContentClient()->browser()->IsSharedStorageAllowed(...) check. This meant that when a cross-origin data opt-in was required but the opt-in check had either not yet been performed (data_origin_opt_in_state_ null) or had been performed and failed (data_origin_opt_in_state_->first false), the function could still return true, allowing the operation to proceed against data the data-origin never consented to. The advisory classifies this as a race: the opt-in state is populated asynchronously, so an operation reaching the allowed-check before the opt-in completed (or despite its failure) would bypass the requirement.
The fix adds an early guard at the top of the function: if needs_data_origin_opt_in_ is set and the state is missing or its success flag is false, it populates out_debug_message (with the state’s own error string or a default) and returns false before any other check runs. This enforces the invariant “a required cross-origin opt-in must be both performed and successful before access is allowed.”
false whenever the opt-in is required but its state is missing or failed, closing the time window where the check had not yet resolved.Attack Path
- Set up a cross-origin worklet
A page creates a Shared Storage worklet that operates on another origin’s data, so
needs_data_origin_opt_in_is set for the host. - Reach the gate before opt-in resolves
Due to the asynchronous ordering,
IsSharedStorageAllowedis invoked whiledata_origin_opt_in_state_is still null (check not yet performed) or holds a failed result. - Bypass the opt-in requirement
Pre-patch, the function skips straight to the embedder allowed-check and can return
true, permitting the operation despite the unmet/failed opt-in. - Unauthorized cross-origin data access The worklet operation proceeds against data whose origin did not successfully opt in (inferred extent; the diff demonstrates the missing precondition, not a specific exfiltration primitive).
Impact Assessment
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifcontent/browser/shared_storage/shared_storage_worklet_host.cc |
modified |
Files Changed
content/browser/shared_storage/shared_storage_worklet_host.cc
Audit Directions
- Async state consulted by sync gatesAudit permission/allowed checks that run synchronously but depend on state populated by an asynchronous step; verify the gate treats “not yet populated” as deny, not allow.
- Optional/nullable consent stateLook for
std::optional/pointer consent or opt-in state that is dereferenced or assumed populated; a null value should fail closed. - Privacy Sandbox cross-origin boundariesReview other Shared Storage / FLEDGE / Attribution worklet hosts for operations that require a per-data-origin opt-in and confirm each path re-checks the opt-in result before proceeding.
Patch
From 782c8de9ff11930c48bd51c823516d0fa4703c82 Mon Sep 17 00:00:00 2001 From: Camillia Smith Barnes <[email protected]> Date: Fri, 03 Apr 2026 14:31:32 -0700 Subject: [PATCH] Shared Storage: Enforce data origin opt-in in SharedStorageWorkletHost When a SharedStorage worklet requires a cross-origin data opt-in, we must verify that the opt-in check has both been performed and succeeded before allowing the operation. This CL updates SharedStorageWorkletHost::IsSharedStorageAllowed to explicitly check these conditions. If the opt-in is required but missing or failed, the function now returns false and populates the debug message with the specific error from the opt-in state. Bug: 496380960 Change-Id: I748a4ed6ae10dcc7a62466bb8bc0a1098cace0af Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7729481 Reviewed-by: Yao Xiao <[email protected]> Commit-Queue: Cammie Smith Barnes <[email protected]> Cr-Commit-Position: refs/heads/main@{#1609953} --- diff --git a/content/browser/shared_storage/shared_storage_worklet_host.cc b/content/browser/shared_storage/shared_storage_worklet_host.cc index fc323fb..4f49dbbc 100644 --- a/content/browser/shared_storage/shared_storage_worklet_host.cc +++ b/content/browser/shared_storage/shared_storage_worklet_host.cc @@ -1804,6 +1804,17 @@ bool SharedStorageWorkletHost::IsSharedStorageAllowed( std::string* out_debug_message, bool* out_block_is_site_setting_specific) { + if (needs_data_origin_opt_in_ && + (!data_origin_opt_in_state_ || !data_origin_opt_in_state_->first)) { + if (out_debug_message) { + *out_debug_message = + data_origin_opt_in_state_ + ? data_origin_opt_in_state_->second + : "SharedStorage cross-origin data opt-in check failed."; + } + return false; + } + RenderFrameHost* rfh = document_service_ ? &(document_service_->render_frame_host()) : nullptr; return GetContentClient()->browser()->IsSharedStorageAllowed(
Original Bug Report
Race condition in SharedStorageWorkletHost bypasses cross-origin opt-in check
Project Fortify, an experimental security project, has identified the following potential security issue.
Overview: A race condition in SharedStorageWorkletHost potentially allows a compromised renderer to access victim Shared Storage data before the mandatory .well-known cross-origin opt-in check completes. This bypasses the security requirement that cross-origin data origins must explicitly opt-in to worklet access via a trusted-origins file. The attacker can indefinitely prolong this access by deliberately hanging the worklet’s script load.
Affected files:
content/browser/shared_storage/shared_storage_worklet_host.cc
Estimated timestamp from git blame: 2025-11-25
Vulnerability Description
A race condition exists in SharedStorageWorkletHost that potentially allows a compromised renderer to bypass the cross-origin opt-in requirement for Shared Storage. When a cross-origin worklet is created, the host immediately binds and dispatches the SharedStorageWorkletServiceClient remote to the renderer process before the asynchronous fetch of the mandatory /.well-known/shared-storage/trusted-origins opt-in file has completed.
Because the Mojo receiver for SharedStorageWorkletServiceClient lacks message gating and its storage-accessing handlers (such as SharedStorageGet and SharedStorageUpdate) do not verify the current opt-in state, an attacker-controlled renderer can issue Mojo calls to read or modify a victim’s cross-origin data during the fetch window.
Furthermore, an attacker can extend this window indefinitely by intentionally hanging the fetch of the worklet script (AddModule), preventing the browser from ever evaluating the failed opt-in check and shutting down the worklet.
Potential Attack Steps
(Note: These are suggested steps based on static analysis; a working proof-of-concept has not yet been executed.)
- Setup: An attacker compromises a renderer process (e.g., hosting
https://attacker.com). - Initiate Worklet Creation: The attacker crafts a
CreateWorkletMojo message over theblink.mojom.SharedStorageDocumentServiceinterface, specifyingscript_source_urlashttps://attacker.com/script.jsanddata_originashttps://victim.com. - Host Initialization: The browser processes this request in
SharedStorageDocumentServiceImpl::CreateWorklet. It creates aSharedStorageWorkletHost, which identifies that a cross-origin opt-in is required (needs_data_origin_opt_in_ = true). - Process Allocation: On platforms where strict Site Isolation is not enforced for the target origin (e.g., Android), the
SharedStorageRenderThreadWorkletDriverassigns thevictim.comworklet to run in the attacker’s compromised renderer process. - Premature Binding:
SharedStorageWorkletHost::GetAndConnectToSharedStorageWorkletService()immediately callsInitialize()on the worklet service. This binds theSharedStorageWorkletServiceClientreceiver in the browser and dispatches the remote to the compromised renderer before the.well-knownopt-in check completes. - Hang Script Load: The attacker configures their server at
https://attacker.com/script.jsto hang the network fetch indefinitely. This keeps theAddModulescript loading state pending. - Exploit Remote: The attacker intercepts the prematurely dispatched
SharedStorageWorkletServiceClientremote in their compromised renderer. - Bypass Checks: The attacker immediately sends unauthorized storage-access Mojo messages (e.g.,
SharedStorageGet). The corresponding handlers inSharedStorageWorkletHostonly check general user settings viaIsSharedStorageAllowed(), failing to verify the pending.well-knowndata_origin_opt_in_state_. - Indefinite Access: Even after the asynchronous
.well-knowncheck tovictim.comeventually fails,MaybeFinishCreateWorklet()returns early because the script load (script_loading_state_) is still pending. The worklet is never expired, granting the attacker an indefinite, unauthorized read/write channel tovictim.com’s Shared Storage data.
Impact
This vulnerability constitutes a high-severity cross-origin data leak and modification risk (S1 Site Isolation Bypass). A compromised renderer can perform unauthorized operations against a victim’s Shared Storage, completely bypassing the .well-known opt-in security mechanism.
Recommended Fix
Ensure that the SharedStorageWorkletServiceClient Mojo receiver does not process messages until the .well-known opt-in check has successfully completed. This can be achieved by:
- Deferring Binding: Wait to bind and dispatch the
SharedStorageWorkletServiceClientremote untildata_origin_opt_in_state_is successfully resolved inMaybeFinishCreateWorklet(). - Explicit Checks: Alternatively, add an explicit check for a successful
data_origin_opt_in_state_in all storage-accessing Mojo handlers withinSharedStorageWorkletHost(e.g.,SharedStorageGet,SharedStorageUpdate, etc.) whenneeds_data_origin_opt_in_is true.
Evaluated with Chrome root at commit: 0eb4855bda702feaaa8b899336664f97e3df88b8
Results so far have been promising, but there can be wrong deductions. If this proves to be a false positive, please close as WAI; data from false positives will be used to improve accuracy over time. Please feel free to reach out to me if you have concerns or feedback.