CVE-2026-17998
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
ExtensionsMenuAllowButtonchrome/browser/ui/views/extensions/extensions_menu_main_page_view.cc |
modified | |
SectionContainerchrome/browser/ui/views/extensions/extensions_menu_main_page_view.cc |
modified |
Files Changed
chrome/browser/ui/views/extensions/extensions_menu_main_page_view.ccchrome/browser/ui/views/extensions/extensions_menu_main_page_view_unittest.cc
Patch
From 0971f338ea328c6fce6f55d273b2c43fcbe698bf Mon Sep 17 00:00:00 2001 From: Eva Su <[email protected]> Date: Thu, 11 Jun 2026 15:16:08 -0700 Subject: [PATCH] [Extensions] Add input protection to extensions menu "Allow" button According to crbug.com/521601450, an extension can call the host access request API, triggering a layout reflow that shifts the menu elements. This can potentially place the newly appeared 'Allow' button directly under the user's cursor during an active click, resulting in an unintended permission grant. This CL adds input protection to the “Allow” button in the menu. This is similar to the change we made for the ExtensionsRequestAccessButton in crrev.com/c/7876925. Fixed: 521601450 Change-Id: Iac4136c5bdf855b5b345dd710f0f8d7498536852 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7927809 Reviewed-by: Andrea Orru <[email protected]> Commit-Queue: Eva Su <[email protected]> Cr-Commit-Position: refs/heads/main@{#1645645} --- diff --git a/chrome/browser/ui/views/extensions/extensions_menu_main_page_view.cc b/chrome/browser/ui/views/extensions/extensions_menu_main_page_view.cc index 2d46c7e..e01b131d 100644 --- a/chrome/browser/ui/views/extensions/extensions_menu_main_page_view.cc +++ b/chrome/browser/ui/views/extensions/extensions_menu_main_page_view.cc @@ -48,6 +48,7 @@ #include "ui/views/controls/label.h" #include "ui/views/controls/scroll_view.h" #include "ui/views/controls/separator.h" +#include "ui/views/input_event_activation_protector.h" #include "ui/views/layout/box_layout.h" #include "ui/views/layout/flex_layout_view.h" #include "ui/views/layout/layout_types.h" @@ -94,6 +95,47 @@ DEFINE_UI_CLASS_PROPERTY_TYPE(ExtensionIdWrapper*) DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(ExtensionIdWrapper, kExtensionIdKey) +// A button in the extensions menu requesting access section that grants one +// time site access to the extension. It uses an input event activation +// protector to prevent unintended clicks. +class ExtensionsMenuAllowButton : public views::MdTextButton { + public: + ExtensionsMenuAllowButton() = default; + ExtensionsMenuAllowButton(const ExtensionsMenuAllowButton&) = delete; + ExtensionsMenuAllowButton& operator=(const ExtensionsMenuAllowButton&) = + delete; + ~ExtensionsMenuAllowButton() override = default; + + // views::View: + void VisibilityChanged(views::View* starting_from, bool is_visible) override { + views::MdTextButton::VisibilityChanged(starting_from, is_visible); + input_protector_.VisibilityChanged(is_visible); + } + + void OnBoundsChanged(const gfx::Rect& previous_bounds) override { + views::MdTextButton::OnBoundsChanged(previous_bounds); + input_protector_.MaybeUpdateViewProtectedTimeStamp(); + } + + void NotifyClick(const ui::Event& event) override { + if (input_protector_.IsPossiblyUnintendedInteraction( + event, /*allow_key_events=*/false)) { + return; + } + views::MdTextButton::NotifyClick(event); + } + + private: + views::InputEventActivationProtector input_protector_; +}; + +BEGIN_VIEW_BUILDER(/* No Export */, + ExtensionsMenuAllowButton, + views::MdTextButton) +END_VIEW_BUILDER + +DEFINE_VIEW_BUILDER(/* No Export */, ExtensionsMenuAllowButton) + // Base class for a container inside the extensions menu. class SectionContainer : public views::BoxLayoutView { public: @@ -288,7 +330,7 @@ .SetAccessibleName(l10n_util::GetStringFUTF16( IDS_EXTENSIONS_MENU_REQUESTS_ACCESS_SECTION_DISMISS_BUTTON_ACCESSIBLE_NAME, request.extension_name)), - views::Builder<views::MdTextButton>() + views::Builder<ExtensionsMenuAllowButton>() .SetCallback(base::BindRepeating( &ExtensionsMenuHandler::OnAllowExtensionClicked, base::Unretained(menu_handler_), request.extension_id)) diff --git a/chrome/browser/ui/views/extensions/extensions_menu_main_page_view_unittest.cc b/chrome/browser/ui/views/extensions/extensions_menu_main_page_view_unittest.cc index c33c5acb..ed0967c 100644 --- a/chrome/browser/ui/views/extensions/extensions_menu_main_page_view_unittest.cc +++ b/chrome/browser/ui/views/extensions/extensions_menu_main_page_view_unittest.cc @@ -44,6 +44,7 @@ #include "ui/views/controls/styled_label.h" #include "ui/views/vector_icons.h" #include "ui/views/view_utils.h" +#include "ui/views/views_switches.h" namespace { @@ -193,6 +194,8 @@ void ExtensionsMenuMainPageViewUnitTest::SetUp() { ExtensionsToolbarUnitTest::SetUp(); + base::CommandLine::ForCurrentProcess()->AppendSwitch( + views::switches::kDisableInputEventActivationProtectionForTesting); // Menu needs web contents at construction, so we need to add them to every // test. web_contents_tester_ = AddWebContentsAndGetTester();
Regression Test / PoC
diff --git a/chrome/browser/ui/views/extensions/extensions_menu_main_page_view_unittest.cc b/chrome/browser/ui/views/extensions/extensions_menu_main_page_view_unittest.cc
index c33c5acb..ed0967c 100644
--- a/chrome/browser/ui/views/extensions/extensions_menu_main_page_view_unittest.cc
+++ b/chrome/browser/ui/views/extensions/extensions_menu_main_page_view_unittest.cc
@@ -44,6 +44,7 @@
#include "ui/views/controls/styled_label.h"
#include "ui/views/vector_icons.h"
#include "ui/views/view_utils.h"
+#include "ui/views/views_switches.h"
namespace {
@@ -193,6 +194,8 @@
void ExtensionsMenuMainPageViewUnitTest::SetUp() {
ExtensionsToolbarUnitTest::SetUp();
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ views::switches::kDisableInputEventActivationProtectionForTesting);
// Menu needs web contents at construction, so we need to add them to every
// test.
web_contents_tester_ = AddWebContentsAndGetTester();
Original Bug Report
Potential clickjacking risk on Extensions Menu 'Allow' button due to missing input protection
Project Fortify, an experimental security project, has identified the following potential security issue. If you’re a feature owner CC-ed on this bug, please do your best to review these reports. Please see https://chromium.googlesource.com/chromium/src/+/main/docs/security/ai-generated-security-bugs-faq.md for more information.
Overview: The ‘Allow’ button in the Extensions Menu main page view lacks an input event activation protector. An extension can call the gesture-free host access request API, triggering a layout reflow that shifts the menu elements. This can potentially place the newly appeared ‘Allow’ button directly under the user’s cursor during an active click, resulting in an unintended permission grant.
Affected files:
chrome/browser/ui/views/extensions/extensions_menu_main_page_view.cc
Estimated timestamp from git blame: 2023-05-18
Potential Security Issue: Lack of InputEventActivationProtector on Extensions Menu ‘Allow’ Button
Root Cause Analysis
In chrome/browser/ui/views/extensions/extensions_menu_main_page_view.cc, the method AddExtensionRequestingAccess constructs the per-extension Allow button as a standard views::MdTextButton without any unintended-interaction guard:
views::Builder<views::MdTextButton>()
.SetCallback(base::BindRepeating(
&ExtensionsMenuHandler::OnAllowExtensionClicked,
base::Unretained(menu_handler_), request.extension_id))
.SetStyle(ui::ButtonStyle::kText)
...
.Build();
When a host access request is dynamically added or removed, the parent view synchronously changes the visibility of requests_section_ and triggers a layout reflow via SizeToPreferredSize():
void ExtensionsMenuMainPageView::SetOptionalSectionVisibility(
ExtensionsMenuViewModel::OptionalSection optional_section) {
...
case ExtensionsMenuViewModel::OptionalSection::kHostAccessRequests:
reload_section_->SetVisible(false);
requests_section_->SetVisible(
!requests_entries_view_->children().empty());
break;
...
SizeToPreferredSize();
}
Because the requests_section_ is inserted vertically above menu_entries_, making it visible pushes all standard menu entries downward.
While sibling surfaces (like ExtensionsRequestAccessButton in extensions_request_access_button.cc) protect against accidental clicks using a views::InputEventActivationProtector, the Allow button in the main page of the extensions menu has no such protection. As a result, click events are processed immediately upon layout shifts.
Potential Trigger Steps
Please note: The following are suggested potential steps as our tooling agent has not executed this code to verify a functional proof of concept.
- Install an extension that requests host permissions for a specific site (e.g.,
https://example.com/*), but configure the permissions to be “withheld” by default (or set to “on click”). - Open
https://example.com/in the active browser tab. - Open the Extensions Toolbar Menu (the puzzle icon).
- The extension calls
chrome.permissions.addHostAccessRequest({ tabId: activeTabId })from its service worker or content script (which does not require a user gesture). - This call dynamically inserts a new request row into the extensions menu. Because this section is located above the extension list, the list shifts down synchronously.
- If the user was moving their mouse cursor to click an element in the extension list, the newly inserted “Allow” button can shift directly under the cursor, intercepting the click.
- The click lands on the “Allow” button, immediately executing the permission grant callback and persistently writing the
kOnSitehost permission toExtensionPrefson disk without user intent.
Suggested Fix
Integrate views::InputEventActivationProtector into ExtensionsMenuMainPageView (or wrap the button callback handler to validate click events), similar to how input protection is implemented in ExtensionsRequestAccessButton.
Before executing OnAllowExtensionClicked, verify that the click event is not a potentially unintended interaction by checking that a sufficient delay has elapsed since the layout reflow occurred.
Evaluated with Chrome root at commit: 3947e01999a53d4e2382e39736cb79d79c7dffcf
Results so far have been promising, but there can be wrong deductions. Feel free to adjust as follows:
- If you are familiar with the severity guidelines, you may adjust the severity.
- If this is a false positive, and there’s no work to be done, please close as WAI.
- If there is work to do here but not a vulnerability, please change the issue type to Task/Bug/FR.
Data from false positives will be used to improve accuracy over time. And please feel free to reach out to me directly if you have concerns or feedback on the project.