CVE-2026-8511
Overview
Background
- SMTC / `SystemMediaControlsWin`
- the Chrome component that bridges media playback to the Windows System Media Transport Controls, including publishing the current media’s thumbnail/icon.
- `base::WeakPtr` / `weak_factory_`
- a smart pointer that becomes null once its owning object is destroyed;
weak_factory_.GetWeakPtr()hands out such a pointer so a deferred callback can check validity before dereferencing. - WinRT async operation / `IAsyncOperationCompletedHandler`
- a Windows Runtime completion handler invoked later, after an asynchronous stream write finishes; any pointer it captures must still be valid when it runs.
- `icon_stream_` / `display_updater_`
SystemMediaControlsWinmembers holding the icon’s byte stream and the WinRT updater used to push the thumbnail to the OS.
Root Cause Analysis
In system_media_controls_win.cc, the method that writes icon/image data builds a store_async_callback (a WinRT IAsyncOperationCompletedHandler<unsigned int>) that captured a raw this pointer and later dereferenced SystemMediaControlsWin members icon_stream_, icon_stream_reference_, and display_updater_. The invariant violated is that a handler captured for asynchronous invocation must not dereference an object that may have been destroyed before the async stream write completes; because the SystemMediaControlsWin is not guaranteed to outlive the operation, firing the completion handler after destruction dereferenced freed memory (use-after-free).
The fix captures auto weak_ptr = weak_factory_.GetWeakPtr() instead of this, adds an early if (!weak_ptr) { return S_OK; } guard at the top of the handler, and rewrites every member access to go through weak_ptr-> (weak_ptr->icon_stream_, weak_ptr->icon_stream_reference_, weak_ptr->display_updater_). The null check runs before any member is touched, so a destroyed controller causes the handler to return early instead of using freed memory.
this into a WinRT async completion handler that can outlive the SystemMediaControlsWin; the fix captures a base::WeakPtr and returns early (S_OK) when it is null before dereferencing any member.Attack Path
- Trigger a thumbnail update
Media playback with artwork causes
SystemMediaControlsWinto begin writing icon bytes intoicon_stream_and register thestore_async_callbackon the resulting WinRT async operation. - Destroy the controller mid-flight
Before the asynchronous stream write completes, the
SystemMediaControlsWinis destroyed (e.g. the media session ends or the controller is torn down), freeing the objectthispointed to. - Completion handler dereferences freed object
When the async operation finishes, the handler runs and, pre-patch, accesses
icon_stream_/display_updater_through the stalethis, producing a use-after-free. - Downstream corruption (inferred)
Whether the dangling access can be shaped into a controllable primitive or code execution is not shown by the diff and is
(inferred).
Impact Assessment
SystemMediaControlsWin before its async icon write completes can trigger a use-after-free in the Chrome browser process on Windows. The vendor advisory rates this critical and describes it as a use after free in UI; preconditions include Windows with the SMTC integration active, a media session that updates its thumbnail, and a timing race during controller teardown, and any escalation beyond the dangling dereference is (inferred).Changed Functions
| Function | Change | Notes |
|---|---|---|
ifcomponents/system_media_controls/win/system_media_controls_win.cc |
modified |
Files Changed
components/system_media_controls/win/system_media_controls_win.cc
Audit Directions
- Raw `this` in async/WinRT handlersGrep for
[this]captures insideMicrosoft::WRL::Callback/IAsyncOperationCompletedHandlerand other deferred callbacks and verify aWeakPtrwith a null check is used where the object may not outlive the operation. - Objects with `weak_factory_` not using itFlag classes that own a
base::WeakPtrFactorybut still capturethisraw into callbacks, indicating an available-but-unused safety mechanism. - Platform OS-integration callbacksReview other system-integration bridges (media, notifications, shell) whose completion handlers touch member state after an OS async call, ensuring controller teardown cannot race the callback.
Patch
From 411ebd37c1e01416a7db2dd2adfa5d7aad888a44 Mon Sep 17 00:00:00 2001 From: Tommy Steimel <[email protected]> Date: Tue, 24 Mar 2026 11:57:15 -0700 Subject: [PATCH] [SMTC] Use weak ptr in SystemMediaControlsWin callback We currently capture a raw `this` pointer in a SystemMediaControlsWin callback for writing image data. This could be problematic as it's possible the SystemMediaControlsWin doesn't outlive the operation. This CL updates the callback to capture and use a weak pointer instead. Bug: 495108488 Change-Id: I8698af5cf5d828ee5064793d35a6c33b6072ce53 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7694234 Commit-Queue: Tommy Steimel <[email protected]> Reviewed-by: Frank Liberato <[email protected]> Cr-Commit-Position: refs/heads/main@{#1604285} --- diff --git a/components/system_media_controls/win/system_media_controls_win.cc b/components/system_media_controls/win/system_media_controls_win.cc index 052f0397..0bbfd11a 100644 --- a/components/system_media_controls/win/system_media_controls_win.cc +++ b/components/system_media_controls/win/system_media_controls_win.cc @@ -308,10 +308,16 @@ // Make a callback that gives the icon to the SMTC once the bits make it into // |icon_stream_| + auto weak_ptr = weak_factory_.GetWeakPtr(); auto store_async_callback = Microsoft::WRL::Callback< ABI::Windows::Foundation::IAsyncOperationCompletedHandler<unsigned int>>( - [this](ABI::Windows::Foundation::IAsyncOperation<unsigned int>* async_op, - ABI::Windows::Foundation::AsyncStatus status) mutable { + [weak_ptr]( + ABI::Windows::Foundation::IAsyncOperation<unsigned int>* async_op, + ABI::Windows::Foundation::AsyncStatus status) mutable { + if (!weak_ptr) { + return S_OK; + } + // Check the async operation completed successfully. ABI::Windows::Foundation::IAsyncInfo* async_info; HRESULT hr = async_op->QueryInterface( @@ -328,15 +334,15 @@ &reference_statics); DCHECK(SUCCEEDED(result)); - result = reference_statics->CreateFromStream(icon_stream_.Get(), - &icon_stream_reference_); + result = reference_statics->CreateFromStream( + weak_ptr->icon_stream_.Get(), &weak_ptr->icon_stream_reference_); DCHECK(SUCCEEDED(result)); - result = - display_updater_->put_Thumbnail(icon_stream_reference_.Get()); + result = weak_ptr->display_updater_->put_Thumbnail( + weak_ptr->icon_stream_reference_.Get()); DCHECK(SUCCEEDED(result)); - result = display_updater_->Update(); + result = weak_ptr->display_updater_->Update(); DCHECK(SUCCEEDED(result)); } return hr;
Original Bug Report
Potential Use-After-Free in SystemMediaControlsWin::SetThumbnail via raw 'this' capture
Project Fortify, an experimental security project, has identified the following potential security issue.
Overview: A potential Use-After-Free (UAF) vulnerability exists in the browser process due to a raw this pointer capture in a WinRT asynchronous callback within SystemMediaControlsWin::SetThumbnail. If the object is destroyed while a media artwork update is pending, the callback will execute on a WinRT thread-pool thread and dereference the freed memory, potentially leading to arbitrary code execution.
Affected files:
components/system_media_controls/win/system_media_controls_win.cc
Estimated timestamp from git blame: 2021-09-08
Description
A potential Use-After-Free (UAF) vulnerability has been identified in the browser process within SystemMediaControlsWin::SetThumbnail on Windows. The issue stems from capturing a raw C++ this pointer in a Microsoft::WRL::Callback that handles the completion of an asynchronous WinRT operation.
In components/system_media_controls/win/system_media_controls_win.cc, the SetThumbnail method initiates an asynchronous write to an icon stream using icon_data_writer_->StoreAsync. A completion handler is registered via store_async_operation->put_Completed():
// components/system_media_controls/win/system_media_controls_win.cc:311
auto store_async_callback = Microsoft::WRL::Callback<
ABI::Windows::Foundation::IAsyncOperationCompletedHandler<unsigned int>>(
[this](ABI::Windows::Foundation::IAsyncOperation<unsigned int>* async_op,
ABI::Windows::Foundation::AsyncStatus status) mutable {
// ...
result = display_updater_->put_Thumbnail(icon_stream_reference_.Get());
// ...
});
The lambda captures this as a raw pointer. However, the SystemMediaControlsWin destructor does not cancel or synchronize with this pending asynchronous operation.
If the SystemMediaControlsWin object is destroyed while the write is still in flight, the WinRT runtime will eventually execute the callback, dereferencing the freed this pointer to access member variables like display_updater_ (which is a ComPtr). Because the capture is a raw pointer and no base::raw_ptr references keep the memory in MiraclePtr’s quarantine, the memory is fully freed and can be reclaimed by an attacker.
Reachability and Impact
This code path is reachable via the Media Session API. When a Progressive Web App (PWA) or an app popup window plays media, Chrome creates an instanced SystemMediaControlsWin object for that specific WebContents, managed by WebAppSystemMediaControlsManager.
If an attacker’s PWA sets media artwork (triggering SetThumbnail) and then immediately closes its own window (e.g., via window.close()), the underlying WebContents and its MediaSession are destroyed. This causes WebAppSystemMediaControlsManager to delete the SystemMediaControlsWin object while the WinRT async operation is still pending.
When the callback eventually runs, it attempts to make a virtual method call on the display_updater_ member of the freed object (display_updater_->put_Thumbnail(...)). By using standard heap spraying techniques in the browser process to control the freed memory chunk, an attacker could point display_updater_ to a forged vtable, achieving arbitrary Remote Code Execution (RCE) and a full Sandbox Escape.
Suggested Steps to Reproduce
Note: These are potential steps as we have not yet developed a working exploit.
- An attacker convinces a user to install a malicious website as a PWA, or opens an app popup window.
- The user launches the PWA, fulfilling
Browser::ShouldUseInstancedSystemMediaControls(). - The PWA’s JavaScript starts playing an audio track (e.g.,
<audio autoplay src="...">), creating aMediaSessionand requesting audio focus. - The browser creates a
WebAppSystemMediaControlsinstance, which allocates aSystemMediaControlsWinobject. - The JavaScript updates the Media Session metadata with a large artwork image to delay the WinRT processing:
navigator.mediaSession.metadata = new MediaMetadata({ artwork: [{ src: "large.png" }] }); SystemMediaControlsWin::SetThumbnailis called, initiating the asynchronousStoreAsyncoperation and registering the vulnerable callback.- Immediately after setting the metadata (allowing ~10-20ms for debounce timers to fire), the JavaScript executes
window.close(). - The window closes, destroying the
WebContentsand causing theSystemMediaControlsWinobject to be freed. - The attacker performs a heap spray in the browser process to reclaim the freed memory with a controlled payload.
- The WinRT async operation completes, the callback executes, and the dangling
thispointer is dereferenced, leading to a virtual call on the attacker’s sprayed data.
Suggested Fix
To prevent this Use-After-Free, the callback should use a base::WeakPtr instead of a raw this pointer, similar to how the ButtonPressed handler is implemented in SystemMediaControlsWin::Initialize (lines 113-125).
auto weak_ptr = weak_factory_.GetWeakPtr();
auto store_async_callback = Microsoft::WRL::Callback<
ABI::Windows::Foundation::IAsyncOperationCompletedHandler<unsigned int>>(
[weak_ptr](ABI::Windows::Foundation::IAsyncOperation<unsigned int>* async_op,
ABI::Windows::Foundation::AsyncStatus status) mutable {
if (!weak_ptr) return S_OK;
// ... safe to access weak_ptr->display_updater_ ...
});
Evaluated with Chrome root at commit: 9760e6c70cd33a320713361f17c6dcca85648c0f
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.