Chrome · Downloads
CVE-2026-87655
Logic Error in Downloads
Overview
Medium
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
forchrome/browser/ui/views/download/bubble/download_bubble_row_view.cc |
modified | |
TEST_Fchrome/browser/ui/views/download/bubble/download_bubble_row_view_unittest.cc |
modified |
Files Changed
chrome/browser/ui/views/download/bubble/download_bubble_row_view.ccchrome/browser/ui/views/download/bubble/download_bubble_row_view.hchrome/browser/ui/views/download/bubble/download_bubble_row_view_unittest.cc
Patch
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.
References
On This Page