Low CVSS 4.3 chrome Spoofing 🔧 Commit mapped

Overview

Low
Severity
4.3
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactIncorrect security UI in Global Media Controls
DescriptionIncorrect security UI in Global Media Controls
ComponentGlobal Media Controls
Sub-componentMediaRouter
Bug ClassSpoofing
Tracker519744561
Fix commita019509362c6 (chromium/src) +106/-6
CWECWE-451
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:N
CISA KEVNot listed
CreditedGoogle
Reported2026-06-04 (per vendor advisory)
Fix landed2026-06-10 (public git)
Disclosed2026-07-29
Patch gap49 days — fix public in source before the advisory

Changed Functions

FunctionChangeNotes
if
chrome/browser/ui/global_media_controls/presentation_request_notification_item.cc
modified

Files Changed

  • chrome/browser/ui/global_media_controls/presentation_request_notification_item.cc
  • chrome/browser/ui/global_media_controls/presentation_request_notification_item.h
  • chrome/browser/ui/global_media_controls/presentation_request_notification_item_unittest.cc
From a019509362c68d8ab8669fe28013822301cb73a5 Mon Sep 17 00:00:00 2001
From: Muyao Xu <[email protected]>
Date: Wed, 10 Jun 2026 16:07:33 -0700
Subject: [PATCH] [MediaRouter] Only use Mediasession metadata for same-origin requests

Onl use the tab's MediaSession metadata for the
PresentationRequestNotificationItem when they are from the same
origin.

Bug: 519744561
Change-Id: Ia95f35f2226597e6f81bfe825be53f67ac78d6f9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7916088
Reviewed-by: Jordan Bayles <[email protected]>
Commit-Queue: Muyao Xu <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1644954}
---

diff --git a/chrome/browser/ui/global_media_controls/presentation_request_notification_item.cc b/chrome/browser/ui/global_media_controls/presentation_request_notification_item.cc
index d88b9ed..79aa20f0 100644
--- a/chrome/browser/ui/global_media_controls/presentation_request_notification_item.cc
+++ b/chrome/browser/ui/global_media_controls/presentation_request_notification_item.cc
@@ -11,6 +11,7 @@
 #include "components/global_media_controls/public/media_item_manager.h"
 #include "components/media_message_center/media_notification_util.h"
 #include "content/public/browser/media_session.h"
+#include "content/public/browser/render_frame_host.h"
 #include "services/media_session/public/cpp/media_image_manager.h"
 #include "services/media_session/public/cpp/media_metadata.h"
 #include "ui/gfx/image/image_skia.h"
@@ -155,9 +156,10 @@
   if (!provider_->is_bound()) {
     return;
   }
-  // If we have metadata from the media session, use that.
-  media_session::MediaMetadata data =
-      metadata_.value_or(media_session::MediaMetadata{});
+  media_session::MediaMetadata data;
+  if (metadata_.has_value() && ShouldShowMediaSessionMetadata()) {
+    data = *metadata_;
+  }
 
   if (media_message_center::IsOriginGoodForDisplay(request_.frame_origin)) {
     // `request_` has more accurate origin info than `metadata_` e.g. when the
@@ -179,12 +181,17 @@
   if (!provider_->is_bound()) {
     return;
   }
-  (*provider_)->OnArtworkImageChanged(artwork_image_);
-  if (!favicon_image_.isNull()) {
+
+  const bool should_show_metadata = ShouldShowMediaSessionMetadata();
+  (*provider_)
+      ->OnArtworkImageChanged(should_show_metadata ? artwork_image_
+                                                   : gfx::ImageSkia());
+
+  if (should_show_metadata && !favicon_image_.isNull()) {
     (*provider_)->OnFaviconImageChanged(favicon_image_);
     return;
   }
-  // Otherwise, get one ourselves.
+
   auto* web_contents = GetWebContentsFromPresentationRequest(request_);
   if (web_contents) {
     favicon::FaviconDriver* favicon_driver =
@@ -209,3 +216,21 @@
   favicon_image_ = GetCorrectColorTypeImage(bitmap).value_or(gfx::ImageSkia());
   UpdatePickerWithImages();
 }
+
+bool PresentationRequestNotificationItem::ShouldShowMediaSessionMetadata()
+    const {
+  auto* web_contents = GetWebContentsFromPresentationRequest(request_);
+  if (!web_contents) {
+    return false;
+  }
+  auto* media_session = GetMediaSession(web_contents);
+  if (!media_session) {
+    return false;
+  }
+  content::RenderFrameHost* routed_frame = media_session->GetRoutedFrame();
+  if (!routed_frame) {
+    return true;
+  }
+  return routed_frame->GetLastCommittedOrigin().IsSameOriginWith(
+      request_.frame_origin);
+}
diff --git a/chrome/browser/ui/global_media_controls/presentation_request_notification_item.h b/chrome/browser/ui/global_media_controls/presentation_request_notification_item.h
index e32f83a2..7210879 100644
--- a/chrome/browser/ui/global_media_controls/presentation_request_notification_item.h
+++ b/chrome/browser/ui/global_media_controls/presentation_request_notification_item.h
@@ -86,6 +86,10 @@
   void OnArtworkBitmap(const SkBitmap& bitmap);
   void OnFaviconBitmap(const SkBitmap& bitmap);
 
+  // Returns true if the origin of the active MediaSession's routed frame is the
+  // same as the origin of the frame that initiated the presentation request.
+  bool ShouldShowMediaSessionMetadata() const;
+
   // True if the item is created from a default PresentationRequest, which means
   // |context_| is set to nullptr in the constructor.
   const bool is_default_presentation_request_;
diff --git a/chrome/browser/ui/global_media_controls/presentation_request_notification_item_unittest.cc b/chrome/browser/ui/global_media_controls/presentation_request_notification_item_unittest.cc
index 8d532a2..027e83d 100644
--- a/chrome/browser/ui/global_media_controls/presentation_request_notification_item_unittest.cc
+++ b/chrome/browser/ui/global_media_controls/presentation_request_notification_item_unittest.cc
@@ -8,7 +8,10 @@
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "components/global_media_controls/public/test/mock_device_service.h"
 #include "components/media_router/common/mojom/media_router.mojom.h"
+#include "content/public/browser/web_contents.h"
 #include "content/public/test/mock_media_session.h"
+#include "content/public/test/navigation_simulator.h"
+#include "content/public/test/test_renderer_host.h"
 #include "services/media_session/public/cpp/media_image.h"
 #include "services/media_session/public/mojom/media_session.mojom.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -21,6 +24,7 @@
  protected:
   void SetUp() override {
     ChromeRenderViewHostTestHarness::SetUp();
+    NavigateAndCommit(GURL("https://example.com"));
     PresentationRequestNotificationItem::SetMediaSessionForTest(
         &media_session_);
 
@@ -79,3 +83,70 @@
   item_->MediaSessionImagesChanged(
       {{media_session::mojom::MediaSessionImageType::kArtwork, {image}}});
 }
+
+TEST_F(PresentationRequestNotificationItemTest,
+       MediaSessionMetadataChanged_RoutedFrameOriginMatch) {
+  EXPECT_CALL(media_session_, GetRoutedFrame())
+      .WillRepeatedly(testing::Return(main_rfh()));
+
+  media_session::MediaMetadata metadata;
+  metadata.source_title = u"some-other-domain.com";
+  metadata.artist = u"My title";
+
+  EXPECT_CALL(*provider_, OnMetadataChanged)
+      .WillOnce([metadata](const media_session::MediaMetadata& metadata_arg) {
+        EXPECT_EQ(u"example.com", metadata_arg.source_title);
+        EXPECT_EQ(metadata.artist, metadata_arg.artist);
+      });
+  item_->MediaSessionMetadataChanged(metadata);
+}
+
+TEST_F(PresentationRequestNotificationItemTest,
+       MediaSessionMetadataChanged_RoutedFrameOriginMismatch) {
+  content::RenderFrameHost* child_rfh =
+      content::RenderFrameHostTester::For(main_rfh())
+          ->AppendChild("child_frame");
+  child_rfh = content::NavigationSimulator::NavigateAndCommitFromDocument(
+      GURL("https://other.com"), child_rfh);
+
+  EXPECT_CALL(media_session_, GetRoutedFrame())
+      .WillRepeatedly(testing::Return(child_rfh));
+
+  media_session::MediaMetadata metadata;
+  metadata.source_title = u"some-other-domain.com";
+  metadata.artist = u"My title";
+
+  EXPECT_CALL(*provider_, OnMetadataChanged)
+      .WillOnce([this](const media_session::MediaMetadata& metadata_arg) {
+        EXPECT_EQ(u"example.com", metadata_arg.source_title);
+        EXPECT_TRUE(metadata_arg.title.empty());
+        EXPECT_EQ(web_contents()->GetTitle(), metadata_arg.artist);
+      });
+  item_->MediaSessionMetadataChanged(metadata);
+}
+
+TEST_F(PresentationRequestNotificationItemTest,
+       MediaSessionImagesChanged_RoutedFrameOriginMismatch) {
+  content::RenderFrameHost* child_rfh =
+      content::RenderFrameHostTester::For(main_rfh())
+          ->AppendChild("child_frame");
+  child_rfh = content::NavigationSimulator::NavigateAndCommitFromDocument(
+      GURL("https://other.com"), child_rfh);
+
+  EXPECT_CALL(media_session_, GetRoutedFrame())
+      .WillRepeatedly(testing::Return(child_rfh));
+
+  media_session::MediaImage image;
+  image.src = GURL{"https://example.com"};
+  image.sizes = {{100, 100}};
+
+  EXPECT_CALL(*provider_, OnArtworkImageChanged)
+      .WillOnce(
+          [](const gfx::ImageSkia& image) { EXPECT_TRUE(image.isNull()); });
+  EXPECT_CALL(*provider_, OnFaviconImageChanged)
+      .WillOnce(
+          [](const gfx::ImageSkia& image) { EXPECT_TRUE(image.isNull()); });
+
+  item_->MediaSessionImagesChanged(
+      {{media_session::mojom::MediaSessionImageType::kArtwork, {image}}});
+}
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/chrome/browser/ui/global_media_controls/presentation_request_notification_item_unittest.cc b/chrome/browser/ui/global_media_controls/presentation_request_notification_item_unittest.cc
index 8d532a2..027e83d 100644
--- a/chrome/browser/ui/global_media_controls/presentation_request_notification_item_unittest.cc
+++ b/chrome/browser/ui/global_media_controls/presentation_request_notification_item_unittest.cc
@@ -8,7 +8,10 @@
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "components/global_media_controls/public/test/mock_device_service.h"
 #include "components/media_router/common/mojom/media_router.mojom.h"
+#include "content/public/browser/web_contents.h"
 #include "content/public/test/mock_media_session.h"
+#include "content/public/test/navigation_simulator.h"
+#include "content/public/test/test_renderer_host.h"
 #include "services/media_session/public/cpp/media_image.h"
 #include "services/media_session/public/mojom/media_session.mojom.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -21,6 +24,7 @@
  protected:
   void SetUp() override {
     ChromeRenderViewHostTestHarness::SetUp();
+    NavigateAndCommit(GURL("https://example.com"));
     PresentationRequestNotificationItem::SetMediaSessionForTest(
         &media_session_);
 
@@ -79,3 +83,70 @@
   item_->MediaSessionImagesChanged(
       {{media_session::mojom::MediaSessionImageType::kArtwork, {image}}});
 }
+
+TEST_F(PresentationRequestNotificationItemTest,
+       MediaSessionMetadataChanged_RoutedFrameOriginMatch) {
+  EXPECT_CALL(media_session_, GetRoutedFrame())
+      .WillRepeatedly(testing::Return(main_rfh()));
+
+  media_session::MediaMetadata metadata;
+  metadata.source_title = u"some-other-domain.com";
+  metadata.artist = u"My title";
+
+  EXPECT_CALL(*provider_, OnMetadataChanged)
+      .WillOnce([metadata](const media_session::MediaMetadata& metadata_arg) {
+        EXPECT_EQ(u"example.com", metadata_arg.source_title);
+        EXPECT_EQ(metadata.artist, metadata_arg.artist);
+      });
+  item_->MediaSessionMetadataChanged(metadata);
+}
+
+TEST_F(PresentationRequestNotificationItemTest,
+       MediaSessionMetadataChanged_RoutedFrameOriginMismatch) {
+  content::RenderFrameHost* child_rfh =
+      content::RenderFrameHostTester::For(main_rfh())
+          ->AppendChild("child_frame");
+  child_rfh = content::NavigationSimulator::NavigateAndCommitFromDocument(
+      GURL("https://other.com"), child_rfh);
+
+  EXPECT_CALL(media_session_, GetRoutedFrame())
+      .WillRepeatedly(testing::Return(child_rfh));
+
+  media_session::MediaMetadata metadata;
+  metadata.source_title = u"some-other-domain.com";
+  metadata.artist = u"My title";
+
+  EXPECT_CALL(*provider_, OnMetadataChanged)
+      .WillOnce([this](const media_session::MediaMetadata& metadata_arg) {
+        EXPECT_EQ(u"example.com", metadata_arg.source_title);
+        EXPECT_TRUE(metadata_arg.title.empty());
+        EXPECT_EQ(web_contents()->GetTitle(), metadata_arg.artist);
+      });
+  item_->MediaSessionMetadataChanged(metadata);
+}
+
+TEST_F(PresentationRequestNotificationItemTest,
+       MediaSessionImagesChanged_RoutedFrameOriginMismatch) {
+  content::RenderFrameHost* child_rfh =
+      content::RenderFrameHostTester::For(main_rfh())
+          ->AppendChild("child_frame");
+  child_rfh = content::NavigationSimulator::NavigateAndCommitFromDocument(
+      GURL("https://other.com"), child_rfh);
+
+  EXPECT_CALL(media_session_, GetRoutedFrame())
+      .WillRepeatedly(testing::Return(child_rfh));
+
+  media_session::MediaImage image;
+  image.src = GURL{"https://example.com"};
+  image.sizes = {{100, 100}};
+
+  EXPECT_CALL(*provider_, OnArtworkImageChanged)
+      .WillOnce(
+          [](const gfx::ImageSkia& image) { EXPECT_TRUE(image.isNull()); });
+  EXPECT_CALL(*provider_, OnFaviconImageChanged)
+      .WillOnce(
+          [](const gfx::ImageSkia& image) { EXPECT_TRUE(image.isNull()); });
+
+  item_->MediaSessionImagesChanged(
+      {{media_session::mojom::MediaSessionImageType::kArtwork, {image}}});
+}
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.