CVE-2026-10888
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifcomponents/cast_streaming/browser/cast_streaming_session.cc |
modified |
Files Changed
components/cast_streaming/browser/cast_streaming_session.cccomponents/cast_streaming/browser/control/playback_command_dispatcher.cc
Patch
From ccc2bc32526cd2292ffb623409e70da00ea4ae16 Mon Sep 17 00:00:00 2001
From: Jordan Bayles <jophba@chromium.org>
Date: Mon, 27 Apr 2026 16:12:46 -0700
Subject: [PATCH] [cast_streaming] Fix potential UAF and re-entrancy in CastStreamingSession
This CL addresses two potential issues in CastStreamingSession:
1. A Use-After-Free (UAF) risk where deferred StartStreamingSession
callbacks could hold dangling pointers to receivers if
OnReceiversDestroying is called while a flush is pending.
2. A re-entrancy UAF during destruction if OnCastChannelClosed is
triggered while ReceiverSession is being reset.
Specifically:
- Clear start_session_cb_ in OnReceiversDestroying and EndSession.
- Call weak_factory_.InvalidateWeakPtrs() in ~ReceiverSessionClient.
- Update PlaybackCommandDispatcher to clear streaming_dispatcher_ on
session end.
Bug: 505815080
Change-Id: I9221f0b2a033778077d920805e6eed73759c4264
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7797771
Reviewed-by: Simeon Anfinrud <sanfin@chromium.org>
Commit-Queue: Jordan Bayles <jophba@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1621401}
---
diff --git a/components/cast_streaming/browser/cast_streaming_session.cc b/components/cast_streaming/browser/cast_streaming_session.cc
index c041964c..471c14a 100644
--- a/components/cast_streaming/browser/cast_streaming_session.cc
+++ b/components/cast_streaming/browser/cast_streaming_session.cc
@@ -201,6 +201,7 @@
}
CastStreamingSession::ReceiverSessionClient::~ReceiverSessionClient() {
+ weak_factory_.InvalidateWeakPtrs();
client_ = nullptr;
// Teardown of the `receiver_session_` may trigger callbacks into `this`,
// so destroy it explicitly here, so that callbacks execute while all other
@@ -428,6 +429,8 @@
playback_command_dispatcher_->OnRemotingSessionEnded();
}
+ start_session_cb_.Reset();
+
preloaded_audio_buffer_ = std::nullopt;
preloaded_video_buffer_ = std::nullopt;
@@ -517,6 +520,7 @@
}
void CastStreamingSession::ReceiverSessionClient::EndSession() {
+ start_session_cb_.Reset();
if (client_) {
CastStreamingSession::Client* client = client_;
client_ = nullptr;
diff --git a/components/cast_streaming/browser/control/playback_command_dispatcher.cc b/components/cast_streaming/browser/control/playback_command_dispatcher.cc
index 0d98647e..cac251f7 100644
--- a/components/cast_streaming/browser/control/playback_command_dispatcher.cc
+++ b/components/cast_streaming/browser/control/playback_command_dispatcher.cc
@@ -173,6 +173,7 @@
demuxer_stream_handler_.reset();
messenger_ = nullptr;
streaming_init_info_ = std::nullopt;
+ streaming_dispatcher_ = nullptr;
}
void PlaybackCommandDispatcher::SendRemotingRpcMessageToRemote(
Original Bug Report
Potential Use-After-Free in CastStreamingSession via deferred callback binding dangling Receivers
Project Fortify, an experimental security project, has identified the following potential security issue. If you’re a feature owner CC-ed on this bug, please do your best to review these reports without the Chrome Security team. Please see https://chromium.googlesource.com/chromium/src/+/main/docs/security/ai-generated-security-bugs-faq.md for more information.
Overview: A race condition during session renegotiation in CastStreamingSession can lead to a Use-After-Free in the browser process. A pending async flush defers session initialization, capturing openscreen::cast::Receiver pointers in a callback that is not cleared when those receivers are subsequently destroyed by a rapid third renegotiation. This leads to a virtual call on freed memory.
Affected files:
components/cast_streaming/browser/cast_streaming_session.cccomponents/cast_streaming/browser/cast_streaming_session.hcomponents/cast_streaming/browser/frame/stream_consumer.cccomponents/cast_streaming/browser/common/streaming_initialization_info.h
Estimated timestamp from git blame: 2023-02-02
Overview
A potential Use-After-Free (UAF) vulnerability exists in the CastStreamingSession component within the browser process. The issue stems from the deferred execution of session start logic when a renderer-side flush is pending, combined with a failure to invalidate this deferred state when session receivers are destroyed during a rapid renegotiation.
Root Cause
When a Cast Streaming remoting session is negotiated, openscreen::cast::ReceiverSession creates Receiver objects for audio and video streams.
If a session renegotiation occurs (e.g., a new OFFER message arrives), openscreen tears down the old receivers. It calls CastStreamingSession::ReceiverSessionClient::OnReceiversDestroying, which initiates an asynchronous Mojo Flush() to the renderer and sets is_flush_pending_ = true.
If initialization configuration for the new session arrives before the Flush() completes, StartStreamingSession is called. Because is_flush_pending_ is true, it defers execution by storing a StreamingInitializationInfo struct inside a callback (start_session_cb_). Crucially, this struct holds raw_ptrs to the current Receiver objects.
If the attacker initiates a third session renegotiation before the original Flush() completes, openscreen again tears down the current receivers. OnReceiversDestroying is called again, but it fails to clear or invalidate start_session_cb_. openscreen then deletes the Receiver objects.
When the asynchronous Flush() finally completes, OnFlushComplete() executes the stale start_session_cb_. This resumes StartStreamingSession, passing the dangling Receiver pointers to the StreamConsumer constructor, which immediately performs a virtual call (receiver_->SetConsumer(this)) on the freed object.
Potential Exploitation Steps
Note: These are suggested steps based on static analysis; a working proof of concept has not been executed.
An attacker on the local network can trigger this by pipelining Cast-channel messages:
- Transmit an initial remoting OFFER (#1) to establish Session 1.
- Transmit a second remoting OFFER (#2). This destroys Session 1, triggering the async
Flush(), and creates Session 2 receivers. - Immediately transmit RPC initialization calls for Session 2. This populates the configs and triggers
StartStreamingSession, which defers execution intostart_session_cb_(capturing Session 2’s receiver pointers) because the flush is pending. - Immediately transmit a third remoting OFFER (#3). This destroys Session 2’s receivers.
start_session_cb_is not cleared. - Wait for the asynchronous
Flush()to complete.OnFlushCompleterunsstart_session_cb_, resulting in the UAF and vtable hijack inStreamConsumer::StreamConsumer.
Impact
This vulnerability occurs in the highly privileged Browser process. While the affected pointers are wrapped in raw_ptr, BackupRefPtr (BRP) is currently disabled by default on CastOS (!is_castos). Therefore, the raw_ptr wrapper provides no protection via partitioning or quarantining, making the UAF potentially exploitable for arbitrary Remote Code Execution.
Suggested Fix
In CastStreamingSession::ReceiverSessionClient::OnReceiversDestroying, explicitly clear the deferred callback when the receivers are being destroyed. For example:
if (start_session_cb_) {
start_session_cb_.Reset();
}
Evaluated with Chrome root at commit: 3acbde3302da0cb19488c22c0eb007c791207b4b
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. And please feel free to reach out to me directly if you have concerns or feedback on the project.