Medium chrome Logic Error 🔧 Commit mapped

Overview

Medium
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactClickjacking in Downloads
DescriptionClickjacking in Downloads
ComponentDownloads
Bug ClassLogic Error
Tracker514023309
Fix commit3cfe51aa2838 (chromium/src) +37/-0
CISA KEVNot listed
CreditedGoogle
Disclosed2026-09-08

Changed Functions

FunctionChangeNotes
for
chrome/browser/ui/views/download/bubble/download_bubble_row_view.cc
modified
TEST_F
chrome/browser/ui/views/download/bubble/download_bubble_row_view_unittest.cc
modified

Files Changed

  • chrome/browser/ui/views/download/bubble/download_bubble_row_view.cc
  • chrome/browser/ui/views/download/bubble/download_bubble_row_view.h
  • chrome/browser/ui/views/download/bubble/download_bubble_row_view_unittest.cc
From 3cfe51aa2838e8a95f78dbc9e82327de5db20870 Mon Sep 17 00:00:00 2001
From: Yaw Frempong <yawfrempong@google.com>
Date: Thu, 30 Jul 2026 07:25:30 -0700
Subject: [PATCH] [Download Bubble] Disable download bubble main page buttons on PiP occlusion

DownloadBubbleRowView::OnOcclusionStateChanged() already disables the
row's transparent button and quick-action buttons while the bubble is
occluded by a picture-in-picture window. Apply the same treatment to the
main page buttons so that they behave consistently with the other
controls on the row, and add a unit test covering all three button
kinds.

Reviewed in https://crrev.com/i/9601875

Bug: 514023309
Change-Id: I3d27699cca9f8dc7010d18cdd09431927eb09753
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8169860
Commit-Queue: Yaw Frempong <yawfrempong@google.com>
Reviewed-by: Lily Chen <chlily@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1671046}
---

diff --git a/chrome/browser/ui/views/download/bubble/download_bubble_row_view.cc b/chrome/browser/ui/views/download/bubble/download_bubble_row_view.cc
index a68d3391..f9b8c9c 100644
--- a/chrome/browser/ui/views/download/bubble/download_bubble_row_view.cc
+++ b/chrome/browser/ui/views/download/bubble/download_bubble_row_view.cc
@@ -978,6 +978,9 @@
   for (auto& [command, action_button] : quick_actions_) {
     action_button->SetEnabled(!occluded);
   }
+  for (auto& [command, main_page_button] : main_page_buttons_) {
+    main_page_button->SetEnabled(!occluded);
+  }
 }
 
 std::u16string_view DownloadBubbleRowView::GetSecondaryLabelTextForTesting() {
@@ -1053,6 +1056,13 @@
   return it->second;
 }
 
+views::MdTextButton* DownloadBubbleRowView::GetMainPageButtonForTesting(
+    DownloadCommands::Command command) {
+  auto it = main_page_buttons_.find(command);
+  CHECK(it != main_page_buttons_.end());
+  return it->second;
+}
+
 void DownloadBubbleRowView::SetInputProtectorForTesting(
     std::unique_ptr<views::InputEventActivationProtector> input_protector) {
   input_protector_ = std::move(input_protector);
diff --git a/chrome/browser/ui/views/download/bubble/download_bubble_row_view.h b/chrome/browser/ui/views/download/bubble/download_bubble_row_view.h
index 6ca1a625..141a7fe 100644
--- a/chrome/browser/ui/views/download/bubble/download_bubble_row_view.h
+++ b/chrome/browser/ui/views/download/bubble/download_bubble_row_view.h
@@ -112,6 +112,8 @@
   bool IsQuickActionButtonVisibleForTesting(DownloadCommands::Command command);
   views::ImageButton* GetQuickActionButtonForTesting(
       DownloadCommands::Command command);
+  views::MdTextButton* GetMainPageButtonForTesting(
+      DownloadCommands::Command command);
   void SetInputProtectorForTesting(
       std::unique_ptr<views::InputEventActivationProtector> input_protector);
 
diff --git a/chrome/browser/ui/views/download/bubble/download_bubble_row_view_unittest.cc b/chrome/browser/ui/views/download/bubble/download_bubble_row_view_unittest.cc
index 9fb3b9a..9b191dfd 100644
--- a/chrome/browser/ui/views/download/bubble/download_bubble_row_view_unittest.cc
+++ b/chrome/browser/ui/views/download/bubble/download_bubble_row_view_unittest.cc
@@ -26,6 +26,7 @@
 #include "ui/events/test/test_event.h"
 #include "ui/events/types/event_type.h"
 #include "ui/views/controls/button/image_button.h"
+#include "ui/views/controls/button/md_text_button.h"
 #include "ui/views/test/mock_input_event_activation_protector.h"
 
 namespace {
@@ -241,4 +242,28 @@
       ->OnMousePressed(event);
 }
 
+// Test that all button controls on the row are disabled while the row is
+// occluded by a picture-in-picture window, and re-enabled when it is not.
+TEST_F(DownloadBubbleRowViewTest, OcclusionDisablesButtons) {
+  views::Button* transparent_button = row_view()->transparent_button();
+  views::ImageButton* quick_action =
+      row_view()->GetQuickActionButtonForTesting(DownloadCommands::CANCEL);
+  views::MdTextButton* main_page_button =
+      row_view()->GetMainPageButtonForTesting(DownloadCommands::KEEP);
+
+  ASSERT_TRUE(transparent_button->GetEnabled());
+  ASSERT_TRUE(quick_action->GetEnabled());
+  ASSERT_TRUE(main_page_button->GetEnabled());
+
+  row_view()->OnOcclusionStateChanged(/*occluded=*/true);
+  EXPECT_FALSE(transparent_button->GetEnabled());
+  EXPECT_FALSE(quick_action->GetEnabled());
+  EXPECT_FALSE(main_page_button->GetEnabled());
+
+  row_view()->OnOcclusionStateChanged(/*occluded=*/false);
+  EXPECT_TRUE(transparent_button->GetEnabled());
+  EXPECT_TRUE(quick_action->GetEnabled());
+  EXPECT_TRUE(main_page_button->GetEnabled());
+}
+
 }  // namespace
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/chrome/browser/ui/views/download/bubble/download_bubble_row_view_unittest.cc b/chrome/browser/ui/views/download/bubble/download_bubble_row_view_unittest.cc
index 9fb3b9a..9b191dfd 100644
--- a/chrome/browser/ui/views/download/bubble/download_bubble_row_view_unittest.cc
+++ b/chrome/browser/ui/views/download/bubble/download_bubble_row_view_unittest.cc
@@ -26,6 +26,7 @@
 #include "ui/events/test/test_event.h"
 #include "ui/events/types/event_type.h"
 #include "ui/views/controls/button/image_button.h"
+#include "ui/views/controls/button/md_text_button.h"
 #include "ui/views/test/mock_input_event_activation_protector.h"
 
 namespace {
@@ -241,4 +242,28 @@
       ->OnMousePressed(event);
 }
 
+// Test that all button controls on the row are disabled while the row is
+// occluded by a picture-in-picture window, and re-enabled when it is not.
+TEST_F(DownloadBubbleRowViewTest, OcclusionDisablesButtons) {
+  views::Button* transparent_button = row_view()->transparent_button();
+  views::ImageButton* quick_action =
+      row_view()->GetQuickActionButtonForTesting(DownloadCommands::CANCEL);
+  views::MdTextButton* main_page_button =
+      row_view()->GetMainPageButtonForTesting(DownloadCommands::KEEP);
+
+  ASSERT_TRUE(transparent_button->GetEnabled());
+  ASSERT_TRUE(quick_action->GetEnabled());
+  ASSERT_TRUE(main_page_button->GetEnabled());
+
+  row_view()->OnOcclusionStateChanged(/*occluded=*/true);
+  EXPECT_FALSE(transparent_button->GetEnabled());
+  EXPECT_FALSE(quick_action->GetEnabled());
+  EXPECT_FALSE(main_page_button->GetEnabled());
+
+  row_view()->OnOcclusionStateChanged(/*occluded=*/false);
+  EXPECT_TRUE(transparent_button->GetEnabled());
+  EXPECT_TRUE(quick_action->GetEnabled());
+  EXPECT_TRUE(main_page_button->GetEnabled());
+}
+
 }  // namespace
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.