CVE-2026-8517
Overview
Background
- WebShare on Windows (`share_operation.cc`)
- the browser-side implementation that fulfills
navigator.share()by streaming shared data (e.g. a blob) into a WindowsIOutputStreamfor the OS share UI. - `OutputStreamWriteOperation`
- a reference-counted helper object representing one in-progress write of blob data to the
IOutputStream, kept alive by outstandingscoped_refptrreferences across asynchronous steps. - `base::RefCounted` vs `base::RefCountedThreadSafe`
- the former increments/decrements the reference count with plain non-atomic operations valid only on a single sequence, while the latter uses atomic operations safe across threads.
- Blob reading
- reading blob contents is asynchronous and can hop between the UI/IO sequences and the blob storage context, so references to the operation may be added or dropped from more than one thread.
Root Cause Analysis
OutputStreamWriteOperation was declared as base::RefCounted<OutputStreamWriteOperation>, so every AddRef/Release used non-atomic reference-count arithmetic that is only correct when all such operations happen on a single sequence. Because the write operation drives asynchronous blob reads and IOutputStream writes whose callbacks can run on different threads, scoped_refptr copies were being created and destroyed concurrently, producing a data race on the reference counter. A lost decrement or interleaved update can drop the count to zero prematurely (freeing the object while another reference still points at it) or corrupt it, an object-lifecycle error.
The fix changes the base class to base::RefCountedThreadSafe<OutputStreamWriteOperation> (and the matching friend declaration), making all reference-count updates atomic so the object’s lifetime is managed correctly regardless of which thread adds or releases a reference.
base::RefCounted, allowing a racy refcount to free it prematurely; the fix switches it to base::RefCountedThreadSafe so all AddRef/Release operations are atomic.Attack Path
- Invoke Web Share
Web content calls
navigator.share()with data (such as a blob) on Windows, creating anOutputStreamWriteOperationto stream the payload into the OS share target. - Concurrent reference churn
The operation’s asynchronous blob reads and stream writes run their callbacks on different threads, each copying and dropping
scoped_refptr<OutputStreamWriteOperation>references. - Refcount race
Non-atomic
AddRef/Releaseinterleave, so the reference count is updated incorrectly and reaches zero while a live reference still exists, destroying the object early. - Use-after-free
A surviving reference or in-flight callback then accesses the freed
OutputStreamWriteOperation(the use-after-free and any further primitive are inferred; the diff demonstrates only the switch to a thread-safe refcount).
Impact Assessment
Changed Functions
| Function | Change | Notes |
|---|---|---|
OutputStreamWriteOperationchrome/browser/webshare/win/share_operation.cc |
modified |
Files Changed
chrome/browser/webshare/win/share_operation.cc
Audit Directions
- `base::RefCounted` on async/multi-thread objectsAudit ref-counted types whose
scoped_refptrs are passed into callbacks posted to other sequences or threads; these must usebase::RefCountedThreadSafe. - Cross-thread blob/stream pipelinesReview other platform share/upload/stream helpers that drive
IOutputStreamor blob reads, where completion callbacks hop threads, for the same non-atomic-refcount pattern. - Mismatch between threading model and refcount classLook for objects documented or implemented as single-sequence but whose work (I/O, OS callbacks, thread pool) actually spans threads, a reliable signal of a refcount thread-safety mismatch.
Patch
From 33390cb84faca1aa2deff0cc3b49d6f260e17994 Mon Sep 17 00:00:00 2001
From: Andrew Paseltiner <apaseltiner@chromium.org>
Date: Mon, 30 Mar 2026 09:17:53 -0700
Subject: [PATCH] [WebShare] Use RefCountedThreadSafe for OutputStreamWriteOperation
Fixed: 497531263
Change-Id: I668a976f66d8ffa3d8a0f4d8c06ca0dfa05f185f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7711320
Commit-Queue: Andrew Paseltiner <apaseltiner@chromium.org>
Reviewed-by: Daniel Murphy <dmurph@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1607144}
---
diff --git a/chrome/browser/webshare/win/share_operation.cc b/chrome/browser/webshare/win/share_operation.cc
index 95fa446e..1eeb3cf 100644
--- a/chrome/browser/webshare/win/share_operation.cc
+++ b/chrome/browser/webshare/win/share_operation.cc
@@ -230,7 +230,7 @@
// Represents an ongoing operation of writing to an IOutputStream.
class OutputStreamWriteOperation
- : public base::RefCounted<OutputStreamWriteOperation> {
+ : public base::RefCountedThreadSafe<OutputStreamWriteOperation> {
public:
OutputStreamWriteOperation(
content::BrowserContext::BlobContextGetter blob_context_getter,
@@ -257,7 +257,7 @@
}
private:
- friend class base::RefCounted<OutputStreamWriteOperation>;
+ friend class base::RefCountedThreadSafe<OutputStreamWriteOperation>;
~OutputStreamWriteOperation() = default;
Original Bug Report
Potential Browser Process Double-Free via Race Condition in OutputStreamWriteOperation
Project Fortify, an experimental security project, has identified the following potential security issue.
Overview: A race condition exists in the Windows Web Share API where OutputStreamWriteOperation incorrectly inherits from base::RefCounted instead of base::RefCountedThreadSafe. Concurrent releases across the Chrome IO thread and WinRT background threads can trigger a double-free in the browser process. This could potentially be leveraged for sandbox escape and Remote Code Execution.
Affected files:
chrome/browser/webshare/win/share_operation.cc
Estimated timestamp from git blame: 2020-10-28
Vulnerability Details
Initial logic and parameters for the Web Share API are validated. The IPC routing from the renderer to the browser process and the instantiation of OutputStreamWriteOperation proceed per standard Windows share mechanisms. The core architectural flaw lies in the class inheritance: OutputStreamWriteOperation (in chrome/browser/webshare/win/share_operation.cc) derives from the non-thread-safe base::RefCounted rather than base::RefCountedThreadSafe.
Standard processing applies during the cross-thread handoff between the Chrome IO thread (handling file blob writing) and the OS-managed WinRT background threads (handling the IStreamedFileDataRequestedHandler COM object).
Because base::RefCounted relies on a non-atomic uint32_t for its reference count, concurrent destruction of the scoped_refptr instances on the IO thread and the WinRT thread bypasses thread-safety. Both threads simultaneously execute the out-of-line ReleaseImpl(), non-atomically decrement the counter, and subsequently reload ref_count_ from memory. Both threads observe ref_count_ == 0 and independently execute the destructor, resulting in a double-free in the highly privileged browser process.
Because the frees occur on separate threads, PartitionAlloc routes the pointers into separate ThreadCaches, bypassing FreeList corruption detection and cleanly exposing the memory to overlapping allocations.
Potential Attacker Steps
(Note: These are suggested/potential steps, our tooling agent doesn’t yet have the ability to run code.)
- Host a malicious page that constructs a file array and invokes
navigator.share(). - Standard UI interaction processing applied (user selects a share target).
- Exploit overlapping PartitionAlloc ThreadCaches resulting from the concurrent double-free to achieve type confusion on the reallocated object.
- Hijack control flow (e.g., via
writer_delegate_virtual calls) to achieve arbitrary code execution and a full sandbox escape.
Suggested Fix
In chrome/browser/webshare/win/share_operation.cc, update the class definition to use atomic reference counting:
class OutputStreamWriteOperation
: public base::RefCountedThreadSafe<OutputStreamWriteOperation> {
...
friend class base::RefCountedThreadSafe<OutputStreamWriteOperation>;
...
Evaluated with Chrome root at commit: a9cbf6e8b275fe4147435aa905f3b7f5a656f5f0
Results from 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. And please feel free to reach out to me directly if you have concerns or feedback on the project.