CVE-2026-17871
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifchrome/browser/ui/views/passwords/account_chooser_dialog_view.cc |
modified |
Files Changed
chrome/browser/ui/views/passwords/account_chooser_dialog_view.ccchrome/browser/ui/views/passwords/account_chooser_dialog_view.h
Patch
From 86978059c4639cae0af8227e3140fc13e14770ef Mon Sep 17 00:00:00 2001
From: Mohamed Amir Yosef <mamir@chromium.org>
Date: Wed, 10 Jun 2026 03:13:45 -0700
Subject: [PATCH] Fix InputEventActivationProtector bypass in AccountChooserDialogView
While standard OK/Cancel dialog buttons are automatically protected
through DialogClientView, the `AccountChooserDialogView` displays
credential rows using `CredentialsItemView`. Previously, interactions
with these row buttons were wired directly to `CredentialsItemPressed`
without checking the `InputEventActivationProtector` mechanism, which
could allow unintended credential selection or clickjacking.
This CL updates the `CredentialsItemPressed` callback to receive the
underlying `ui::Event` and passes it through the
`DialogClientView::IsPossiblyUnintendedInteraction()` check. This
ensures the credential rows respect the exact same input protections and
minimum-display delays as the standard dialog buttons.
Fixed: 521938924
Change-Id: Ie2ffb3f6174d493c2c7bfa728deddaa407af1c92
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7913835
Reviewed-by: Rafał Godlewski <rgod@google.com>
Commit-Queue: Mohamed Amir Yosef <mamir@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1644542}
---
diff --git a/chrome/browser/ui/views/passwords/account_chooser_dialog_view.cc b/chrome/browser/ui/views/passwords/account_chooser_dialog_view.cc
index ac0f3e9..19aabcce 100644
--- a/chrome/browser/ui/views/passwords/account_chooser_dialog_view.cc
+++ b/chrome/browser/ui/views/passwords/account_chooser_dialog_view.cc
@@ -28,6 +28,7 @@
#include "ui/base/mojom/dialog_button.mojom.h"
#include "ui/base/mojom/ui_base_types.mojom-shared.h"
#include "ui/base/resource/resource_bundle.h"
+#include "ui/events/event.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/strings/grit/ui_strings.h"
#include "ui/views/border.h"
@@ -39,6 +40,7 @@
#include "ui/views/layout/layout_provider.h"
#include "ui/views/style/typography.h"
#include "ui/views/widget/widget.h"
+#include "ui/views/window/dialog_client_view.h"
AccountChooserDialogView::AccountChooserDialogView(
CredentialManagerDialogController* controller,
@@ -156,7 +158,14 @@
}
void AccountChooserDialogView::CredentialsItemPressed(
- const password_manager::PasswordForm* form) {
+ const password_manager::PasswordForm* form,
+ const ui::Event& event) {
+ if (GetDialogClientView() &&
+ GetDialogClientView()->IsPossiblyUnintendedInteraction(
+ event, /*allow_key_events=*/
+ ShouldAllowKeyEventsDuringInputProtection())) {
+ return;
+ }
// On Mac the button click event may be dispatched after the dialog was
// hidden. Thus, the controller can be null.
if (controller_) {
diff --git a/chrome/browser/ui/views/passwords/account_chooser_dialog_view.h b/chrome/browser/ui/views/passwords/account_chooser_dialog_view.h
index 8201511..ea443a0 100644
--- a/chrome/browser/ui/views/passwords/account_chooser_dialog_view.h
+++ b/chrome/browser/ui/views/passwords/account_chooser_dialog_view.h
@@ -45,7 +45,8 @@
// Sets up the child views.
void InitWindow();
- void CredentialsItemPressed(const password_manager::PasswordForm* form);
+ void CredentialsItemPressed(const password_manager::PasswordForm* form,
+ const ui::Event& event);
// A weak pointer to the controller.
raw_ptr<CredentialManagerDialogController, AcrossTasksDanglingUntriaged>
Original Bug Report
Potential bypass of InputEventActivationProtector in AccountChooserDialogView
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: A potential vulnerability in AccountChooserDialogView allows credential row buttons to bypass the InputEventActivationProtector safety mechanism. An attacker hosting a PSL-matched or affiliated origin can programmatically trigger the credential chooser and harvest an unintended user click. This can result in the unauthorized disclosure of the user’s cleartext credentials to the calling website.
Affected files:
chrome/browser/ui/views/passwords/account_chooser_dialog_view.ccchrome/browser/ui/views/passwords/credentials_item_view.cc
Estimated timestamp from git blame: 2019-07-09
Description / Root Cause
The AccountChooserDialogView is used by the Credential Management API to allow users to select saved credentials when multiple matches exist and the kCredentialManagementUnifiedUi feature is disabled (which is the code default).
To prevent clickjacking and accidental interactions immediately after a dialog is shown, Chromium utilizes InputEventActivationProtector. However, this protector is currently only enforced for standard dialog buttons (like OK and Cancel) handled by DialogClientView::ButtonPressed:
// ui/views/window/dialog_client_view.cc
void DialogClientView::ButtonPressed(ui::mojom::DialogButton type,
const ui::Event& event) {
DialogDelegate* const delegate = GetDialogDelegate();
if (!delegate ||
input_protector_->IsPossiblyUnintendedInteraction(
event, /*allow_key_events=*/delegate
->ShouldAllowKeyEventsDuringInputProtection())) {
return;
}
...
}
In AccountChooserDialogView, each credential row is rendered as a custom CredentialsItemView (which inherits from views::Button). These item views are wired directly to AccountChooserDialogView::CredentialsItemPressed:
// chrome/browser/ui/views/passwords/account_chooser_dialog_view.cc
for (const auto& form : controller_->GetLocalForms()) {
...
auto* credential_view =
list_view->AddChildView(std::make_unique<CredentialsItemView>(
base::BindRepeating(
&AccountChooserDialogView::CredentialsItemPressed,
base::Unretained(this), base::Unretained(form.get())),
...));
}
Because interactions with these rows skip the DialogClientView button path, they completely bypass the input event protection check. A user’s click or tap that occurs immediately upon the dialog’s appearance is accepted with zero minimum-display delay.
Potential Trigger Path / Attack Scenario
Note: The following scenario represents potential steps an attacker might follow. Our analysis is based on static code review, and we have not run dynamic proof-of-concept exploits.
- The attacker controls or compromises a subdomain or affiliated origin (e.g.,
https://attacker.example.comwhich PSL-matches the victim’s saved credential originhttps://login.example.com). - The attacker’s page prompts the user to click at a precise UI location (e.g., a fake CAPTCHA or decoy button) corresponding to where the dialog’s first credential row will appear.
- Upon user interaction (e.g., a
mousedownevent), the page callsnavigator.credentials.get({password: true, mediation: 'required'})to trigger the credential chooser. - Due to the lack of an input protector on the row button, the subsequent mouse-up or rapid second click immediately registers on the
CredentialsItemViewrow. - The browser processes the select click, resolves the API promise, and returns the cleartext password of the affiliated/PSL match back to the attacker’s page.
Impact
An attacker can obtain the user’s cleartext credential for an affiliated/PSL-matched origin through a single clickjacking or interaction-harvesting attempt, bypassing the intended minimum-display-time protections meant to safeguard credential release.
Suggested Fix
Instantiate an InputEventActivationProtector within AccountChooserDialogView itself and update its visibility state appropriately. Modify the CredentialsItemView pressed callback to accept and pass the underlying ui::Event so the protector can validate the interaction timing before executing the credential selection:
void AccountChooserDialogView::CredentialsItemPressed(
const password_manager::PasswordForm* form,
const ui::Event& event) {
if (input_protector_ && input_protector_->IsPossiblyUnintendedInteraction(event)) {
return;
}
if (controller_) {
controller_->OnChooseCredentials(
*form, password_manager::CredentialType::CREDENTIAL_TYPE_PASSWORD);
}
}
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.