Overview

High
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactInsufficient validation of untrusted input in Chromecast
DescriptionInsufficient validation of untrusted input in Chromecast
ComponentChromecast
Bug ClassLogic Error
Tracker513375270
Fix commit2e6d61a00f58 (chromium/src) +6/-4
CISA KEVNot listed
CreditedGoogle
Disclosed2026-07-29

Changed Functions

FunctionChangeNotes
if
chromecast/media/cma/pipeline/media_pipeline_impl.cc
modified

Files Changed

  • chromecast/media/cma/pipeline/media_pipeline_impl.cc
From 2e6d61a00f581ce2c39b278ad5f08b654cf03f3f Mon Sep 17 00:00:00 2001
From: Simeon Anfinrud <sanfin@chromium.org>
Date: Mon, 22 Jun 2026 12:59:53 -0700
Subject: [PATCH] [chromecast] Fix Flush bypass in MediaPipelineImpl

This CL addresses a state machine vulnerability where a Flush() operation
could unconditionally transition the backend_state_ to INITIALIZED,
bypassing the lazy initialization of the MediaPipelineBackend in
StartPlayingFrom().

If a compromised renderer sent a Flush() immediately after Initialize(),
the subsequent StartPlayingFrom() would skip initializing the backend
and directly call Start(), violating the backend ABI contract and
potentially causing memory corruption in the OEM implementation.

Bug: 513375270
Test: CQ
Change-Id: I3a9701676348cdd2ab9cd78e390f4dae579073f4
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7854259
Auto-Submit: Simeon Anfinrud <sanfin@chromium.org>
Reviewed-by: Sandeep Vijayasekar <sandv@google.com>
Commit-Queue: Simeon Anfinrud <sanfin@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1650515}
---

diff --git a/chromecast/media/cma/pipeline/media_pipeline_impl.cc b/chromecast/media/cma/pipeline/media_pipeline_impl.cc
index 39a48df9..999afb6 100644
--- a/chromecast/media/cma/pipeline/media_pipeline_impl.cc
+++ b/chromecast/media/cma/pipeline/media_pipeline_impl.cc
@@ -364,10 +364,12 @@
 
   if (pending_flush_task_->audio_flushed &&
       pending_flush_task_->video_flushed) {
-    // Stop the backend, so that the backend won't push their pending buffer,
-    // which may be invalidated later, to hardware. (b/25342604)
-    media_pipeline_backend_->Stop();
-    backend_state_ = BACKEND_STATE_INITIALIZED;
+    if (backend_state_ != BACKEND_STATE_UNINITIALIZED) {
+      // Stop the backend, so that the backend won't push their pending buffer,
+      // which may be invalidated later, to hardware. (b/25342604)
+      media_pipeline_backend_->Stop();
+      backend_state_ = BACKEND_STATE_INITIALIZED;
+    }
     metrics::CastMetricsHelper::GetInstance()->RecordApplicationEvent(
         "Cast.Platform.Ended");
 
Loading diff…

Original Bug Report

reported by vm...@google.com

Potential MediaPipelineBackend initialization bypass via early Flush in Chromecast CMA

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. Please see https://chromium.googlesource.com/chromium/src/+/main/docs/security/ai-generated-security-bugs-faq.md for more information.

Overview: A state machine flaw in MediaPipelineImpl allows a Flush() operation to incorrectly transition the internal backend state to INITIALIZED prematurely. This can cause subsequent playback operations to skip mandatory backend initialization, potentially leading to memory corruption in privileged vendor-specific implementations.

Affected files:

  • chromecast/media/cma/pipeline/media_pipeline_impl.cc
  • media/mojo/services/mojo_renderer_service.cc
  • chromecast/media/service/cast_renderer.cc

Estimated timestamp from git blame: 2016-02-18

Summary

A potential state machine vulnerability has been identified in the Chromecast CMA (Cast Multimedia Stack) pipeline. In MediaPipelineImpl, a Flush() operation can transition the backend state to BACKEND_STATE_INITIALIZED without ensuring that the underlying MediaPipelineBackend::Initialize() method has been called. This violates the mandatory initialization contract of the media backend ABI.

Technical Details

The MediaPipelineImpl class (in chromecast/media/cma/pipeline/media_pipeline_impl.cc) uses a lazy initialization pattern in StartPlayingFrom:

if (backend_state_ == BACKEND_STATE_UNINITIALIZED) {
  if (!media_pipeline_backend_->Initialize()) { ... }
  backend_state_ = BACKEND_STATE_INITIALIZED;
}
// Start the backend.
if (!media_pipeline_backend_->Start(time.InMicroseconds())) { ... }

However, the OnFlushDone method, which is called after a flush operation completes, unconditionally transitions the state to INITIALIZED (Reference: chromecast/media/cma/pipeline/media_pipeline_impl.cc:375):

if (pending_flush_task_->audio_flushed && pending_flush_task_->video_flushed) {
  media_pipeline_backend_->Stop();
  backend_state_ = BACKEND_STATE_INITIALIZED; 
  ...
}

While there are DCHECK guards in MediaPipelineImpl::Flush and MojoRendererService::Flush intended to ensure the pipeline is in a valid state (PLAYING or PAUSED) before flushing, these checks are removed in release builds. A compromised renderer can therefore trigger a Flush() immediately after Initialize(), but before StartPlayingFrom(). This sequence causes OnFlushDone to set the state to INITIALIZED while bypassing the actual call to media_pipeline_backend_->Initialize().

Impact

The MediaPipelineBackend (defined in chromecast/public/media/media_pipeline_backend.h) is typically implemented as an OEM shared library running within the unsandboxed browser process (specifically on the privileged CastMediaThread).

Calling Stop() or Start() on an uninitialized backend violates the ABI contract and may cause the vendor implementation to dereference uninitialized handles or access unallocated memory pools. This could lead to memory corruption and potential arbitrary code execution within the privileged browser process, effectively allowing a renderer-to-browser sandbox escape.

Potential Steps to Reproduce

An attacker with control over a renderer process could potentially follow these steps:

  1. Acquire a handle to the media.mojom.Renderer interface.
  2. Call Initialize(client, streams) to set up the media service and MediaPipelineImpl.
  3. Immediately call Flush(). In a release build, this bypasses the state checks and triggers OnFlushDone once the (empty) pipelines are flushed.
  4. OnFlushDone sets the internal backend_state_ to INITIALIZED.
  5. Call StartPlayingFrom(time). MediaPipelineImpl sees the state as INITIALIZED, skips the call to the backend’s Initialize(), and invokes media_pipeline_backend_->Start().

Suggested Fix

The OnFlushDone method should not unconditionally set the state to INITIALIZED. It should verify that the backend was previously initialized or ensure that the transition only occurs if the current state is PLAYING or PAUSED. Additionally, more robust state validation that persists in release builds should be added to the public Mojo interface boundaries.

Evaluated with Chrome root at commit: b3153093eb3c78c3e88ccf562bcbc20437a04b0e


Results so far have been promising, but there can be wrong deductions. Feel free to adjust as follows:

  • If you are familiar with the severity guidelines, you may adjust the severity.
  • If this is a false positive, and there’s no work to be done, please close as WAI.
  • If there is work to do here but not a vulnerability, please change the issue type to Task/Bug/FR.

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.

View on issue tracker