CVE-2026-13804
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifchromecast/media/cma/pipeline/av_pipeline_impl.cc |
modified |
Files Changed
chromecast/media/cma/pipeline/av_pipeline_impl.cc
Patch
From 8aef48d1116b82c5306b5bb8b669b6dd252d559c Mon Sep 17 00:00:00 2001
From: Simeon Anfinrud <sanfin@chromium.org>
Date: Thu, 14 May 2026 09:21:24 -0700
Subject: [PATCH] [chromecast] Fix Potential UAF in Cast media pipeline via missing StartPlayingFrom state guards
Introduce strict state validation in CastRenderer::StartPlayingFrom to enforce
that the pipeline must be in a Flushed state before starting playback.
Bug: 501873032
Test: Compiled and passed unit tests.
Change-Id: I93052cd6f4630a618b2d0fe0091cb960b64453bb
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7767169
Auto-Submit: Simeon Anfinrud <sanfin@chromium.org>
Reviewed-by: Shawn Quereshi <shawnq@google.com>
Commit-Queue: Shawn Quereshi <shawnq@google.com>
Cr-Commit-Position: refs/heads/main@{#1630663}
---
diff --git a/chromecast/media/cma/pipeline/av_pipeline_impl.cc b/chromecast/media/cma/pipeline/av_pipeline_impl.cc
index ae33a08..3ade6fd 100644
--- a/chromecast/media/cma/pipeline/av_pipeline_impl.cc
+++ b/chromecast/media/cma/pipeline/av_pipeline_impl.cc
@@ -76,7 +76,10 @@
LOG(INFO) << __FUNCTION__ << " called while in error state";
return false;
}
- DCHECK_EQ(state_, kFlushed);
+ if (state_ != kFlushed) {
+ LOG(ERROR) << __FUNCTION__ << " called in unexpected state " << state_;
+ return false;
+ }
// Buffering related initialization.
DCHECK(frame_provider_);
Original Bug Report
Potential UAF in Cast media pipeline via missing StartPlayingFrom state guards
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.
Overview: A potential Use-After-Free vulnerability exists in the Chromecast media pipeline due to missing state guards in the StartPlayingFrom IPC handler. A compromised renderer can bypass the expected state machine by issuing consecutive StartPlayingFrom calls without flushing, prematurely freeing media buffers still in use by the vendor backend.
Affected files:
chromecast/media/cma/pipeline/av_pipeline_impl.ccmedia/mojo/services/mojo_renderer_service.ccchromecast/media/common/video_decoder_wrapper.ccchromecast/media/common/audio_decoder_wrapper.ccchromecast/media/cma/pipeline/media_pipeline_impl.ccchromecast/media/service/cast_renderer.ccchromecast/media/common/media_pipeline_backend_wrapper.cc
Estimated timestamp from git blame: 2020-07-23
Summary
A potential Use-After-Free (UAF) vulnerability exists in the browser process for Cast-enabled devices (built with ENABLE_CAST_RENDERER). The CastRenderer implementation lacks state validation when handling the StartPlayingFrom IPC. This allows a compromised renderer process to confuse the state machine and trigger a UAF of a CastDecoderBuffer inside the vendor-specific media backend.
Technical Details
In the standard Chromium media::RendererImpl, StartPlayingFrom strictly enforces that the pipeline is in a STATE_FLUSHED state. However, chromecast::media::CastRenderer and its underlying MediaPipelineImpl lack these state guards in release builds.
When an active media buffer (Buffer A) is pushed to the pipeline, AvPipelineImpl and VideoDecoderWrapper both retain scoped_refptr references to it in their respective pushed_buffer_ members. VideoDecoderWrapper then passes a raw CastDecoderBuffer* pointer to the vendor hardware decoder. The decoder queues it asynchronously and returns kBufferPending.
If a compromised renderer sends a second StartPlayingFrom IPC without a prior Flush IPC, the state machine breaks down:
AvPipelineImpl::StartPlayingFromclears its reference viapushed_buffer_ = nullptr.- The pipeline resumes the feed loop and fetches a new buffer (Buffer B) from the attacker.
VideoDecoderWrapper::PushBufferreceives Buffer B and overwrites its reference:pushed_buffer_ = std::move(Buffer B).- Buffer A’s reference count drops to zero, and it is deallocated.
- The vendor hardware decoder still holds the raw pointer to Buffer A, leading to a UAF when it eventually accesses the memory.
Note: This bypasses MiraclePtr (BackupRefPtr) protections because the dangling raw pointer is held within an unmanaged, third-party vendor library.
Potential Reproduction Steps
Note: These are suggested steps based on static analysis; our tooling agent does not yet have the ability to run code and provide a working proof of concept.
- A compromised renderer process provisions a
CastRendererin the browser process via Mojo. - The renderer sets up the pipeline with an attacker-controlled Mojo demuxer stream.
- The renderer sends a
StartPlayingFrom(t0)IPC and feeds Buffer A to the pipeline. - The vendor decoder receives the raw pointer to Buffer A and begins asynchronous processing (
kBufferPending). - Before Buffer A completes, the renderer maliciously sends a second
StartPlayingFrom(t1)IPC without sending aFlushIPC first. - The renderer immediately feeds Buffer B.
- The browser process drops all
scoped_refptrreferences to Buffer A, freeing the memory. - The renderer performs a heap spray (e.g., sending many small
media::DecoderBuffers over Mojo) to reclaim Buffer A’s memory with controlled data. - The vendor backend dereferences the raw pointer to Buffer A, hitting the attacker’s payload and resulting in a control-flow hijack (Sandbox Escape / RCE in the Browser Process).
Suggested Fix
Introduce strict state validation in CastRenderer::StartPlayingFrom to enforce that the pipeline must be in a Flushed or Uninitialized state before starting playback. If a StartPlayingFrom IPC is received while the pipeline is already playing or has pending buffers, it should be treated as a bad message (e.g., using mojo::ReportBadMessage) and the renderer process should be terminated.
Evaluated with Chrome root at commit: 096fc8fdbfacf2546485756d03f160a3d04fcc9b
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.