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
Tracker567447106
Fix commitfee8baee165a (chromium/src) +37/-4
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
for
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_test.cc
  • third_party/blink/renderer/core/html/media/html_media_element.cc
From fee8baee165a2165c254585eeef25a304381bd1d Mon Sep 17 00:00:00 2001
From: Dale Curtis <[email protected]>
Date: Wed, 30 Sep 2026 21:43:49 -0700
Subject: [PATCH] Fix bugs in HTMLMediaElement::SelectNextSourceChild

In SelectNextSourceChild, src_value was held across MediaQueryMatches().
That call can trigger a style and layout update in an embedding
document, synchronizing dirty style attributes and causing the element's
attribute buffer to reallocate.

Fixed: 567447106
Change-Id: I7a5b13183f65710937d57b6298165bdd0c2f0841
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8494613
Commit-Queue: Benjamin Keen <[email protected]>
Auto-Submit: Dale Curtis <[email protected]>
Commit-Queue: Dale Curtis <[email protected]>
Reviewed-by: Benjamin Keen <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1708606}
---
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 55e715df..8c8aa2f 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
@@ -3857,13 +3857,11 @@
     // 2. If candidate does not have a src attribute, or if its src
     // attribute's value is the empty string ... jump down to the failed
     // step below
-    const AtomicString& src_value =
-        source->FastGetAttribute(html_names::kSrcAttr);
     if (should_log) {
       DVLOG(3) << "selectNextSourceChild(" << *this << ") - 'src' is "
                << UrlForLoggingMedia(media_url);
     }
-    if (src_value.empty()) {
+    if (source->FastGetAttribute(html_names::kSrcAttr).empty()) {
       goto checkAgain;
     }
 
@@ -3878,7 +3876,11 @@
     // 4. Let urlRecord be the result of encoding-parsing a URL given
     // candidate's src attribute's value, relative to candidate's node document
     // when the src attribute was last changed.
-    media_url = source->GetDocument().CompleteURL(src_value);
+    // Note: Do not cache `kSrcAttr` in a local reference across step 3, as
+    // `MediaQueryMatches()` can trigger style/layout updates that mutate
+    // attributes or reallocate the element's attribute buffer.
+    media_url = source->GetDocument().CompleteURL(
+        source->FastGetAttribute(html_names::kSrcAttr));
 
     // 5. If urlRecord is failure, then end the synchronous section, and jump
     // down to the failed with elements step below.
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 b589859..bed9553 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
@@ -28,6 +28,7 @@
 #include "third_party/blink/renderer/core/fullscreen/fullscreen.h"
 #include "third_party/blink/renderer/core/html/html_document.h"
 #include "third_party/blink/renderer/core/html/html_head_element.h"
+#include "third_party/blink/renderer/core/html/html_source_element.h"
 #include "third_party/blink/renderer/core/html/media/html_audio_element.h"
 #include "third_party/blink/renderer/core/html/media/html_video_element.h"
 #include "third_party/blink/renderer/core/html/media/media_error.h"
@@ -613,6 +614,11 @@
   }
 
  protected:
+  KURL SelectNextSourceChild(String* content_type,
+                             HTMLMediaElement::InvalidURLAction action) {
+    return Media()->SelectNextSourceChild(content_type, action);
+  }
+
   // Helpers to call MediaPlayerObserver mojo methods and check their results.
   void NotifyMediaPlaying() {
     media_->DidPlayerStartPlaying();
@@ -3648,6 +3654,31 @@
   EXPECT_TRUE(MediaShouldBeOpaque());
 }
 
+TEST_P(HTMLMediaElementTest, SelectNextSourceChildMediaQueryMatching) {
+  auto* source1 =
+      Media()->GetDocument().CreateRawElement(html_names::kSourceTag);
+  source1->setAttribute(html_names::kSrcAttr,
+                        AtomicString("http://example.com/not_matched.mp4"));
+  source1->setAttribute(html_names::kMediaAttr, AtomicString("not all"));
+  // Fill up inline attribute vector capacity to verify attribute stability.
+  for (int i = 0; i < 6; ++i) {
+    source1->setAttribute(AtomicString("data-attr" + String::Number(i)),
+                          AtomicString("val"));
+  }
+  Media()->AppendChild(source1);
+
+  auto* source2 =
+      Media()->GetDocument().CreateRawElement(html_names::kSourceTag);
+  source2->setAttribute(html_names::kSrcAttr,
+                        AtomicString("http://example.com/matched.mp4"));
+  source2->setAttribute(html_names::kMediaAttr, AtomicString("all"));
+  Media()->AppendChild(source2);
+
+  String content_type;
+  KURL url = SelectNextSourceChild(&content_type, HTMLMediaElement::kDoNothing);
+  EXPECT_EQ(url.GetString(), "http://example.com/matched.mp4");
+}
+
 TEST_P(HTMLMediaElementTest, SourceWasAddedIgnoredWithSrcObject) {
   MediaStreamComponentVector audio_components;
   MediaStreamComponentVector video_components;
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 b589859..bed9553 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
@@ -28,6 +28,7 @@
 #include "third_party/blink/renderer/core/fullscreen/fullscreen.h"
 #include "third_party/blink/renderer/core/html/html_document.h"
 #include "third_party/blink/renderer/core/html/html_head_element.h"
+#include "third_party/blink/renderer/core/html/html_source_element.h"
 #include "third_party/blink/renderer/core/html/media/html_audio_element.h"
 #include "third_party/blink/renderer/core/html/media/html_video_element.h"
 #include "third_party/blink/renderer/core/html/media/media_error.h"
@@ -613,6 +614,11 @@
   }
 
  protected:
+  KURL SelectNextSourceChild(String* content_type,
+                             HTMLMediaElement::InvalidURLAction action) {
+    return Media()->SelectNextSourceChild(content_type, action);
+  }
+
   // Helpers to call MediaPlayerObserver mojo methods and check their results.
   void NotifyMediaPlaying() {
     media_->DidPlayerStartPlaying();
@@ -3648,6 +3654,31 @@
   EXPECT_TRUE(MediaShouldBeOpaque());
 }
 
+TEST_P(HTMLMediaElementTest, SelectNextSourceChildMediaQueryMatching) {
+  auto* source1 =
+      Media()->GetDocument().CreateRawElement(html_names::kSourceTag);
+  source1->setAttribute(html_names::kSrcAttr,
+                        AtomicString("http://example.com/not_matched.mp4"));
+  source1->setAttribute(html_names::kMediaAttr, AtomicString("not all"));
+  // Fill up inline attribute vector capacity to verify attribute stability.
+  for (int i = 0; i < 6; ++i) {
+    source1->setAttribute(AtomicString("data-attr" + String::Number(i)),
+                          AtomicString("val"));
+  }
+  Media()->AppendChild(source1);
+
+  auto* source2 =
+      Media()->GetDocument().CreateRawElement(html_names::kSourceTag);
+  source2->setAttribute(html_names::kSrcAttr,
+                        AtomicString("http://example.com/matched.mp4"));
+  source2->setAttribute(html_names::kMediaAttr, AtomicString("all"));
+  Media()->AppendChild(source2);
+
+  String content_type;
+  KURL url = SelectNextSourceChild(&content_type, HTMLMediaElement::kDoNothing);
+  EXPECT_EQ(url.GetString(), "http://example.com/matched.mp4");
+}
+
 TEST_P(HTMLMediaElementTest, SourceWasAddedIgnoredWithSrcObject) {
   MediaStreamComponentVector audio_components;
   MediaStreamComponentVector video_components;
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.