Medium watch CVSS 3.1 chrome Race 📄 Reporter bug report 🔧 Commit mapped

Overview

Medium
Severity
3.1
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactRace in Shared Storage
DescriptionRace in Shared Storage
ComponentShared Storage
Bug ClassRace
Action tierwatch — logic/policy bug — security-relevant, no memory-unsafety
Computed by PatchGap's deterministic exploitability ruler from the fixing commit. patch-now = RCE-class & attacker-reachable in a default config, or exploited in the wild; watch = real security signal below that bar; noise = no security relevance.
Tracker496380960
Fix commit782c8de9ff11 (chromium/src) +11/-0
CWECWE-362 (Race condition)
CVSS vectorCVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:L/I:N/A:N
CISA KEVNot listed
CreditedGoogle
Reported2026-03-26 (per vendor advisory)
Fix landed2026-04-03 (public git)
Disclosed2026-05-05
Patch gap32 days — fix public in source before the advisory

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 by needs_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.”

Key insight
The allowed-check omitted any verification that a required cross-origin data opt-in had actually completed and succeeded; the fix adds an explicit precondition returning 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

  1. 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.
  2. Reach the gate before opt-in resolves Due to the asynchronous ordering, IsSharedStorageAllowed is invoked while data_origin_opt_in_state_ is still null (check not yet performed) or holds a failed result.
  3. 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.
  4. 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

An attacker-controlled page could, under a timing/ordering race, cause a Shared Storage worklet to operate on cross-origin data without the required and successful opt-in, undermining the Privacy Sandbox cross-origin consent boundary in the browser process. The precondition is a worklet configured to need a cross-origin data opt-in whose state can be observed before resolution or after failure. The vendor advisory rates this medium and does not report exploitation in the wild; any broader privacy-boundary consequence beyond the missing check is (inferred).

Changed Functions

FunctionChangeNotes
if
content/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 gates
    Audit 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 state
    Look 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 boundaries
    Review 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.
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(
Loading diff…

Original Bug Report

reported by [email protected]

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.)

  1. Setup: An attacker compromises a renderer process (e.g., hosting https://attacker.com).
  2. Initiate Worklet Creation: The attacker crafts a CreateWorklet Mojo message over the blink.mojom.SharedStorageDocumentService interface, specifying script_source_url as https://attacker.com/script.js and data_origin as https://victim.com.
  3. Host Initialization: The browser processes this request in SharedStorageDocumentServiceImpl::CreateWorklet. It creates a SharedStorageWorkletHost, which identifies that a cross-origin opt-in is required (needs_data_origin_opt_in_ = true).
  4. Process Allocation: On platforms where strict Site Isolation is not enforced for the target origin (e.g., Android), the SharedStorageRenderThreadWorkletDriver assigns the victim.com worklet to run in the attacker’s compromised renderer process.
  5. Premature Binding: SharedStorageWorkletHost::GetAndConnectToSharedStorageWorkletService() immediately calls Initialize() on the worklet service. This binds the SharedStorageWorkletServiceClient receiver in the browser and dispatches the remote to the compromised renderer before the .well-known opt-in check completes.
  6. Hang Script Load: The attacker configures their server at https://attacker.com/script.js to hang the network fetch indefinitely. This keeps the AddModule script loading state pending.
  7. Exploit Remote: The attacker intercepts the prematurely dispatched SharedStorageWorkletServiceClient remote in their compromised renderer.
  8. Bypass Checks: The attacker immediately sends unauthorized storage-access Mojo messages (e.g., SharedStorageGet). The corresponding handlers in SharedStorageWorkletHost only check general user settings via IsSharedStorageAllowed(), failing to verify the pending .well-known data_origin_opt_in_state_.
  9. Indefinite Access: Even after the asynchronous .well-known check to victim.com eventually 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 to victim.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.

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:

  1. Deferring Binding: Wait to bind and dispatch the SharedStorageWorkletServiceClient remote until data_origin_opt_in_state_ is successfully resolved in MaybeFinishCreateWorklet().
  2. Explicit Checks: Alternatively, add an explicit check for a successful data_origin_opt_in_state_ in all storage-accessing Mojo handlers within SharedStorageWorkletHost (e.g., SharedStorageGet, SharedStorageUpdate, etc.) when needs_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.

View on issue tracker