High chrome UAF 🔧 Commit mapped

Overview

High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactUse after free in Media
DescriptionUse after free in Media
ComponentMedia
Bug ClassUAF
Tracker566111249
Fix commit852936ed111c (chromium/src) +67/-9
CISA KEVNot listed
CreditedXinyang Ge (Anthropic), assisted by Claude
Disclosed2026-10-06

Changed Functions

FunctionChangeNotes
if
third_party/blink/renderer/core/html/media/html_media_element.cc
modified
TEST_P
third_party/blink/renderer/core/html/media/html_media_element_test.cc
modified

Files Changed

  • third_party/blink/renderer/core/html/media/html_media_element.h
  • third_party/blink/renderer/core/html/media/html_media_element_test.cc
  • third_party/blink/renderer/core/html/media/html_media_element.cc
From 852936ed111c9ec6fdfafa7d81d6eca03c7a131b Mon Sep 17 00:00:00 2001
From: Dale Curtis <dalecurtis@chromium.org>
Date: Wed, 30 Sep 2026 10:39:52 -0700
Subject: [PATCH] Ignore <source> child element insertion when srcObject is present

Per the WHATWG HTML specification, child <source> elements are only
evaluated if the media element has neither an assigned media provider
object (srcObject) nor a src attribute.

Prior to this CL, HTMLMediaElement::SourceWasAdded() only checked
FastHasAttribute(srcAttr), completely omitting the check for srcObject.

Fixed: 566111249
Change-Id: I2fcb100b7da8aef970f88cb280ef753a049bece4
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8490153
Commit-Queue: Benjamin Keen <bkeen@google.com>
Reviewed-by: Benjamin Keen <bkeen@google.com>
Auto-Submit: Dale Curtis <dalecurtis@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1708276}
---
diff --git a/third_party/blink/renderer/core/html/media/html_media_element.cc b/third_party/blink/renderer/core/html/media/html_media_element.cc
index f50a6ae..55e715df 100644
--- a/third_party/blink/renderer/core/html/media/html_media_element.cc
+++ b/third_party/blink/renderer/core/html/media/html_media_element.cc
@@ -927,8 +927,7 @@
     if (lazy_media_load_state_ == LazyMediaLoadState::kDeferred) {
       LazyMediaHelper::StartMonitoring(this);
     } else if ((!FastGetAttribute(html_names::kSrcAttr).empty() ||
-                src_object_stream_descriptor_ ||
-                src_object_media_source_handle_) &&
+                HasSrcObject()) &&
                network_state_ == kNetworkEmpty) {
       ignore_preload_none_ = false;
       InvokeLoadAlgorithm();
@@ -1327,7 +1326,7 @@
 
   // 6 - If the media element has an assigned media provider object, then let
   //     mode be object.
-  if (src_object_stream_descriptor_ || src_object_media_source_handle_) {
+  if (HasSrcObject()) {
     mode = kObject;
   } else if (FastHasAttribute(html_names::kSrcAttr)) {
     // Otherwise, if the media element has no assigned media provider object
@@ -3069,8 +3068,7 @@
 }
 
 bool HTMLMediaElement::HasMediaSources() const {
-  return FastHasAttribute(html_names::kSrcAttr) ||
-         src_object_stream_descriptor_ || src_object_media_source_handle_ ||
+  return FastHasAttribute(html_names::kSrcAttr) || HasSrcObject() ||
          Traversal<HTMLSourceElement>::FirstChild(*this);
 }
 
@@ -3936,10 +3934,11 @@
   DVLOG(3) << "sourceWasAdded(" << *this << ") - 'src' is "
            << UrlForLoggingMedia(url);
 
-  // We should only consider a <source> element when there is not src attribute
-  // at all.
-  if (FastHasAttribute(html_names::kSrcAttr))
+  // We should only consider a <source> element when there is neither a
+  // srcObject nor a src attribute at all.
+  if (FastHasAttribute(html_names::kSrcAttr) || HasSrcObject()) {
     return;
+  }
 
   // 4.8.8 - If a source element is inserted as a child of a media element that
   // has no src attribute and whose networkState has the value NETWORK_EMPTY,
@@ -3965,8 +3964,17 @@
   if (next_child_node_to_consider_)
     return;
 
-  if (load_state_ != kWaitingForSource)
+  // Step 21 ("Wait until the node after pointer is a node other than the end of
+  // the list") only applies when the resource selection algorithm is in the
+  // source elements section and waiting at the Wait step, which sets
+  // networkState to NETWORK_NO_SOURCE. If networkState is not NETWORK_NO_SOURCE
+  // (e.g. NETWORK_IDLE after a decode error where MediaEngineError() aborted
+  // resource selection but set load_state_ = kWaitingForSource), we must not
+  // resume candidate selection.
+  if (load_state_ != kWaitingForSource ||
+      network_state_ != HTMLMediaElement::kNetworkNoSource) {
     return;
+  }
 
   // 4.8.9.5, resource selection algorithm, source elements section:
   // 21. Wait until the node after pointer is a node other than the end of the
@@ -4001,6 +4009,12 @@
   DVLOG(3) << "sourceWasRemoved(" << *this << ") - 'src' is "
            << UrlForLoggingMedia(url);
 
+  // We should only consider a <source> element when there is neither a
+  // srcObject nor a src attribute at all.
+  if (FastHasAttribute(html_names::kSrcAttr) || HasSrcObject()) {
+    return;
+  }
+
   if (source != current_source_node_ && source != next_child_node_to_consider_)
     return;
 
diff --git a/third_party/blink/renderer/core/html/media/html_media_element.h b/third_party/blink/renderer/core/html/media/html_media_element.h
index 7087407..f43cbc165 100644
--- a/third_party/blink/renderer/core/html/media/html_media_element.h
+++ b/third_party/blink/renderer/core/html/media/html_media_element.h
@@ -203,6 +203,9 @@
       std::variant<MediaStreamDescriptor*, MediaSourceHandle*>;
   void SetSrcObjectVariant(SrcObjectVariant src_object_variant);
   SrcObjectVariant GetSrcObjectVariant() const;
+  bool HasSrcObject() const {
+    return src_object_stream_descriptor_ || src_object_media_source_handle_;
+  }
 
   enum NetworkState {
     kNetworkEmpty,
diff --git a/third_party/blink/renderer/core/html/media/html_media_element_test.cc b/third_party/blink/renderer/core/html/media/html_media_element_test.cc
index aa23ce3..b589859 100644
--- a/third_party/blink/renderer/core/html/media/html_media_element_test.cc
+++ b/third_party/blink/renderer/core/html/media/html_media_element_test.cc
@@ -43,6 +43,7 @@
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/heap/thread_state_scopes.h"
+#include "third_party/blink/renderer/platform/mediastream/media_stream_descriptor.h"
 #include "third_party/blink/renderer/platform/network/network_state_notifier.h"
 #include "third_party/blink/renderer/platform/testing/empty_web_media_player.h"
 #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
@@ -3647,4 +3648,44 @@
   EXPECT_TRUE(MediaShouldBeOpaque());
 }
 
+TEST_P(HTMLMediaElementTest, SourceWasAddedIgnoredWithSrcObject) {
+  MediaStreamComponentVector audio_components;
+  MediaStreamComponentVector video_components;
+  auto* descriptor = MakeGarbageCollected<MediaStreamDescriptor>(
+      audio_components, video_components);
+  Media()->SetSrcObjectVariant(descriptor);
+  EXPECT_TRUE(Media()->HasSrcObject());
+
+  // With srcObject set, appending a <source> child element must be ignored.
+  auto* source =
+      Media()->GetDocument().CreateRawElement(html_names::kSourceTag);
+  source->setAttribute(html_names::kSrcAttr,
+                       AtomicString("http://example.com/test.mp4"));
+  Media()->appendChild(source);
+
+  test::RunPendingTasks();
+
+  EXPECT_TRUE(Media()->HasSrcObject());
+}
+
+TEST_P(HTMLMediaElementTest, SourceWasAddedIgnoredWhenNetworkStateNotNoSource) {
+  Media()->SetSrc(SrcSchemeToURL(TestURLScheme::kHttp));
+  test::RunPendingTasks();
+  ASSERT_TRUE(Media()->GetWebMediaPlayer());
+
+  SetReadyState(HTMLMediaElement::kHaveMetadata);
+  SetNetworkState(WebMediaPlayer::kNetworkStateDecodeError);
+  EXPECT_EQ(Media()->getNetworkState(), HTMLMediaElement::kNetworkIdle);
+
+  auto* source =
+      Media()->GetDocument().CreateRawElement(html_names::kSourceTag);
+  source->setAttribute(html_names::kSrcAttr,
+                       AtomicString("http://example.com/test.mp4"));
+  Media()->appendChild(source);
+
+  test::RunPendingTasks();
+
+  EXPECT_EQ(Media()->getNetworkState(), HTMLMediaElement::kNetworkIdle);
+}
+
 }  // namespace blink
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/third_party/blink/renderer/core/html/media/html_media_element_test.cc b/third_party/blink/renderer/core/html/media/html_media_element_test.cc
index aa23ce3..b589859 100644
--- a/third_party/blink/renderer/core/html/media/html_media_element_test.cc
+++ b/third_party/blink/renderer/core/html/media/html_media_element_test.cc
@@ -43,6 +43,7 @@
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/heap/thread_state_scopes.h"
+#include "third_party/blink/renderer/platform/mediastream/media_stream_descriptor.h"
 #include "third_party/blink/renderer/platform/network/network_state_notifier.h"
 #include "third_party/blink/renderer/platform/testing/empty_web_media_player.h"
 #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
@@ -3647,4 +3648,44 @@
   EXPECT_TRUE(MediaShouldBeOpaque());
 }
 
+TEST_P(HTMLMediaElementTest, SourceWasAddedIgnoredWithSrcObject) {
+  MediaStreamComponentVector audio_components;
+  MediaStreamComponentVector video_components;
+  auto* descriptor = MakeGarbageCollected<MediaStreamDescriptor>(
+      audio_components, video_components);
+  Media()->SetSrcObjectVariant(descriptor);
+  EXPECT_TRUE(Media()->HasSrcObject());
+
+  // With srcObject set, appending a <source> child element must be ignored.
+  auto* source =
+      Media()->GetDocument().CreateRawElement(html_names::kSourceTag);
+  source->setAttribute(html_names::kSrcAttr,
+                       AtomicString("http://example.com/test.mp4"));
+  Media()->appendChild(source);
+
+  test::RunPendingTasks();
+
+  EXPECT_TRUE(Media()->HasSrcObject());
+}
+
+TEST_P(HTMLMediaElementTest, SourceWasAddedIgnoredWhenNetworkStateNotNoSource) {
+  Media()->SetSrc(SrcSchemeToURL(TestURLScheme::kHttp));
+  test::RunPendingTasks();
+  ASSERT_TRUE(Media()->GetWebMediaPlayer());
+
+  SetReadyState(HTMLMediaElement::kHaveMetadata);
+  SetNetworkState(WebMediaPlayer::kNetworkStateDecodeError);
+  EXPECT_EQ(Media()->getNetworkState(), HTMLMediaElement::kNetworkIdle);
+
+  auto* source =
+      Media()->GetDocument().CreateRawElement(html_names::kSourceTag);
+  source->setAttribute(html_names::kSrcAttr,
+                       AtomicString("http://example.com/test.mp4"));
+  Media()->appendChild(source);
+
+  test::RunPendingTasks();
+
+  EXPECT_EQ(Media()->getNetworkState(), HTMLMediaElement::kNetworkIdle);
+}
+
 }  // namespace blink
Loading diff…

Original Bug Report

The reporter's bug is still restricted on the tracker. Chrome de-restricts security bugs ~30–90 days after the fix ships; a later run will backfill it here.