Chrome · Global Media Controls
CVE-2026-17983
Logic Error in Global Media Controls
Overview
Low
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifchrome/browser/ui/global_media_controls/presentation_request_notification_item.cc |
modified |
Files Changed
chrome/browser/ui/global_media_controls/presentation_request_notification_item.ccchrome/browser/ui/global_media_controls/presentation_request_notification_item.hchrome/browser/ui/global_media_controls/presentation_request_notification_item_unittest.cc
Patch
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.
References
On This Page