558f682dc597948ea4f47cc270de47e93370fcc5 Add default value for is_cross_origin_isolated
Triage note: Uninitialized read (UB) of a security-relevant capability flag on the service-worker start path, so a wrong value could over- or under-grant cross-origin-isolated APIs. Not a proven exploit from the diff; effect depends on stack contents.
The bug at a glance
This is a defense-in-depth initialization fix, not a demonstrated exploitable bug, so it is rated low and its CVSS left null. The field WebEmbeddedWorkerStartData::is_cross_origin_isolated was a plain bool with no default initializer; MSAN caught a read of it before assignment. The security-relevant part is what the field controls — whether a service/embedded worker is granted access to cross-origin-isolated APIs (SharedArrayBuffer, high-resolution timers, and the broader COOP/COEP-gated surface that underpins Spectre-class isolation). A garbage value could in principle flip that decision in either direction: falsely granting isolated capabilities to a worker that should not have them, or denying them to one that should. That is a genuine security-relevant field, which is why this is watch-tier rather than pure noise. However, the diff shows the uninitialized read was hit on a TEST path (CreateStartData() in the unit test did not set the field; the fix re-enables the previously MSAN-DISABLED TerminateSoonAfterStart test). Production callers that build WebEmbeddedWorkerStartData most likely assign is_cross_origin_isolated explicitly from the browser-side worker start parameters, so real-world impact is unproven from this diff alone. Because exploitability depends on whether any production path can leave it unset — which the diff does not establish — inflating above low would be speculative.
A single missing ‘= false’ on a security-decision boolean. The interesting question an auditor asks is not ‘is this bool uninitialized in the struct’ (it plainly was) but ‘can any production construction site reach the worker-start flow without assigning it?’ The struct is a POD-style transfer object at the Blink public boundary (public/web), meaning it is populated field-by-field by embedders/browser glue rather than through a constructor that enforces all fields. Field-by-field population is exactly where a newly added or conditionally-set field silently stays garbage. The value then feeds into whether the worker’s execution context is treated as cross-origin isolated, i.e. whether Spectre-gated APIs unlock. The angle is: default-false makes the safe outcome (no isolation) the fallback, which is the correct fail-closed posture for a capability gate.
Root cause
WebEmbeddedWorkerStartData is the parameter bundle passed from the browser/embedder into Blink to start an embedded (service) worker. The member ‘bool is_cross_origin_isolated;’ had no in-class initializer. When a construction site failed to assign it (observed in the unit test’s CreateStartData()), the bool held indeterminate stack/heap bytes. Downstream, this value is consumed when configuring the worker global scope’s cross-origin-isolation state, which governs eligibility for cross-origin-isolated APIs. An indeterminate read is undefined behavior and, more concretely, a non-deterministic capability decision. The fix adds an in-class default initializer ‘bool is_cross_origin_isolated = false;’, making every construction that omits the field fall back to not-isolated (fail-closed). The accompanying test change removes the MSAN/Linux/ChromeOS DISABLED_ guard on TerminateSoonAfterStart, which had been suppressed precisely because it tripped the uninitialized-read report.
Key code
Add fail-closed default initializer to the cross-origin-isolation capability field.
// third_party/blink/public/web/web_embedded_worker_start_data.h
WebFetchClientSettingsObject outside_fetch_client_settings_object;
// Whether the worker has access to cross-origin isolated APIs.
- bool is_cross_origin_isolated;
+ bool is_cross_origin_isolated = false; // fail-closed default
// Unique token that identifies this worker ...
// web_embedded_worker_impl_test.cc: the MSAN/Linux/ChromeOS DISABLED_
// guard on TerminateSoonAfterStart is removed, re-enabling the test
// that previously read the uninitialized value via CreateStartData().
Patch walkthrough
third_party/blink/public/web/web_embedded_worker_start_data.h— Adds ‘= false’ to is_cross_origin_isolated. Because this struct is populated field-by-field across the Blink public boundary, an in-class initializer is the robust place to guarantee a defined, fail-closed value for any caller that forgets the field. Choosing false (not isolated) means the fallback denies rather than grants Spectre-gated capabilities.third_party/blink/renderer/modules/service_worker/web_embedded_worker_impl_test.cc— Removes the platform-conditional MAYBE_/DISABLED_TerminateSoonAfterStart machinery and runs TerminateSoonAfterStart unconditionally. The test had been disabled on Linux/ChromeOS (the MSAN bots) because its CreateStartData() left is_cross_origin_isolated unset, tripping the uninitialized-read report; with the default in place the test is safe to re-enable, which also serves as the regression guard.
Background
Cross-origin isolation — A security state (enabled by COOP: same-origin + COEP: require-corp) that isolates a document/worker so it can safely use powerful APIs like SharedArrayBuffer and unclamped performance.now(). It is a Spectre mitigation gate: capabilities are granted only when the origin has opted into strong isolation.
WebEmbeddedWorkerStartData — A public/web transfer struct carrying the parameters Blink needs to start an embedded (service) worker, including script URL, fetch client settings, and this isolation flag. As a boundary struct it is filled member-by-member by the browser/embedder rather than via an all-args constructor.
MSAN (MemorySanitizer) — A compiler instrumentation that detects reads of uninitialized memory. It flagged the read of is_cross_origin_isolated, which is why the affected test was previously DISABLED on MSAN-covered platforms.
In-class member initializer — A C++11 feature (‘bool x = false;’) that gives a member a default value used by any constructor that does not otherwise set it. For POD-like boundary structs it is the standard way to avoid indeterminate fields.
Fail-closed default — A safety principle: when a capability-gating value is unspecified, default to denying the capability. Defaulting is_cross_origin_isolated to false denies isolated APIs on the unset path rather than granting them.
Vulnerability window
- latent — The is_cross_origin_isolated field was added without an initializer; some construction paths (at least the unit test’s CreateStartData) did not assign it.
- detected — MSAN reported an uninitialized-value read; the affected test TerminateSoonAfterStart was DISABLED on Linux/ChromeOS to keep bots green (Bug 478209534).
- fix — 2026-01-30 (Jiacheng Guo, r1577655): add ‘= false’ default and re-enable the test unconditionally.
Proof of concept
No proof-of-concept is warranted or possible from this diff. The evidence is an MSAN report on a unit-test construction path, not a demonstrated production path that leaves the field unset. To claim exploitation one would need to show a real worker-start flow where is_cross_origin_isolated is read while indeterminate AND that the resulting isolation decision crosses a security boundary — neither is established here. Fabricating a PoC would misrepresent a defense-in-depth initialization fix as a live vulnerability.
Exploitation
- precondition (unproven) — A production construction site of WebEmbeddedWorkerStartData would have to leave is_cross_origin_isolated unassigned. The diff only shows this on a test path; no such production path is demonstrated.
- hypothetical impact — If such a path existed, the worker’s cross-origin-isolation state would be decided by garbage bytes, potentially granting SharedArrayBuffer / precise timers to a worker that did not meet COOP/COEP requirements (weakening a Spectre gate) or denying them spuriously. The default-false fix makes the unset outcome fail-closed.
Detection & hunting
For defenders and detection engineers:
- MSAN uninitialized-read reports —
- Unexpected worker isolation state —
Audit directions
- All WebEmbeddedWorkerStartData construction sites —
- Sibling capability booleans in public/web transfer structs —
- Isolation flag propagation —