CVE-2026-106232
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifchrome/browser/ui/views/certificate_selector.cc |
modified |
Files Changed
chrome/browser/ui/views/certificate_selector.ccchrome/browser/ui/views/certificate_selector_interactive_uitest.cc
Patch
From 0a8a5b85a1c9bd4141072457453e600d8787ab55 Mon Sep 17 00:00:00 2001 From: Erik Chen <[email protected]> Date: Thu, 03 Sep 2026 08:25:05 -0700 Subject: [PATCH] CertificateSelector: Gate table double-click on input protection Double-clicking a row in the certificate table calls AcceptDialog() directly and never consults the DialogClientView input protector that gates the OK button on the same dialog. Consult the protector before accepting so both accept surfaces behave consistently. TableViewObserver::OnDoubleClick() does not receive the originating ui::Event, so a mouse event stamped at the current time is used; OnDoubleClick() is dispatched synchronously from TableView::OnMousePressed(), so this is equivalent to gating on the real event. The existing DoubleClick test now resets the protector before double-clicking, and a new test covers the ignored case. TAG=agy CONV=a746e443-38b2-4cab-937a-8d4d22e2eb37 Bug: 522299740 Change-Id: I756a7926b83a3818f5db353d4d1aef6a884ee77d Agent-Generated: true Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8339532 Commit-Queue: Erik Chen <[email protected]> Reviewed-by: David Pennington <[email protected]> Cr-Commit-Position: refs/heads/main@{#1691607} --- diff --git a/chrome/browser/ui/views/certificate_selector.cc b/chrome/browser/ui/views/certificate_selector.cc index 4156704..98e63b81 100644 --- a/chrome/browser/ui/views/certificate_selector.cc +++ b/chrome/browser/ui/views/certificate_selector.cc @@ -39,11 +39,14 @@ #include "ui/base/models/table_model_observer.h" #include "ui/base/mojom/dialog_button.mojom.h" #include "ui/base/mojom/ui_base_types.mojom-shared.h" +#include "ui/events/base_event_utils.h" +#include "ui/events/event.h" #include "ui/views/controls/button/md_text_button.h" #include "ui/views/controls/scroll_view.h" #include "ui/views/controls/table/table_view.h" #include "ui/views/layout/box_layout.h" #include "ui/views/widget/widget.h" +#include "ui/views/window/dialog_client_view.h" #if BUILDFLAG(IS_CHROMEOS) #include "chrome/browser/ash/certificate_provider/certificate_provider_service.h" @@ -344,9 +347,23 @@ } void CertificateSelector::OnDoubleClick() { - if (GetSelectedCert()) { - AcceptDialog(); + if (!GetSelectedCert()) { + return; } + + views::DialogClientView* const client_view = GetDialogClientView(); + if (client_view) { + const ui::MouseEvent event(ui::EventType::kMousePressed, gfx::Point(), + gfx::Point(), ui::EventTimeForNow(), + ui::EF_LEFT_MOUSE_BUTTON, + ui::EF_LEFT_MOUSE_BUTTON); + if (client_view->IsPossiblyUnintendedInteraction( + event, ShouldAllowKeyEventsDuringInputProtection())) { + return; + } + } + + AcceptDialog(); } BEGIN_METADATA(CertificateSelector) diff --git a/chrome/browser/ui/views/certificate_selector_interactive_uitest.cc b/chrome/browser/ui/views/certificate_selector_interactive_uitest.cc index 52d5f6f..c2ff2cb 100644 --- a/chrome/browser/ui/views/certificate_selector_interactive_uitest.cc +++ b/chrome/browser/ui/views/certificate_selector_interactive_uitest.cc @@ -149,6 +149,8 @@ base::RunLoop loop; selector_->set_on_destroy(loop.QuitClosure()); + selector_->ResetViewShownTimeStampForTesting(); + // Simulate double clicking on an entry in the certificate list. selector_->OnDoubleClick(); @@ -160,3 +162,17 @@ EXPECT_TRUE(accepted); EXPECT_FALSE(canceled); } + +IN_PROC_BROWSER_TEST_F(CertificateSelectorTest, + DoubleClickSoonAfterShowIsIgnored) { + bool accepted = false; + bool canceled = false; + selector_->TrackState(&accepted, &canceled); + + // Simulate double clicking immediately after the dialog is shown. It should + // be ignored by the input protector. + selector_->OnDoubleClick(); + + EXPECT_FALSE(accepted); + EXPECT_FALSE(canceled); +}
Regression Test / PoC
diff --git a/chrome/browser/ui/views/certificate_selector_interactive_uitest.cc b/chrome/browser/ui/views/certificate_selector_interactive_uitest.cc
index 52d5f6f..c2ff2cb 100644
--- a/chrome/browser/ui/views/certificate_selector_interactive_uitest.cc
+++ b/chrome/browser/ui/views/certificate_selector_interactive_uitest.cc
@@ -149,6 +149,8 @@
base::RunLoop loop;
selector_->set_on_destroy(loop.QuitClosure());
+ selector_->ResetViewShownTimeStampForTesting();
+
// Simulate double clicking on an entry in the certificate list.
selector_->OnDoubleClick();
@@ -160,3 +162,17 @@
EXPECT_TRUE(accepted);
EXPECT_FALSE(canceled);
}
+
+IN_PROC_BROWSER_TEST_F(CertificateSelectorTest,
+ DoubleClickSoonAfterShowIsIgnored) {
+ bool accepted = false;
+ bool canceled = false;
+ selector_->TrackState(&accepted, &canceled);
+
+ // Simulate double clicking immediately after the dialog is shown. It should
+ // be ignored by the input protector.
+ selector_->OnDoubleClick();
+
+ EXPECT_FALSE(accepted);
+ EXPECT_FALSE(canceled);
+}
Original Bug Report
Input Protection Bypass via TableView Double-Click in CertificateSelector
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 client certificate selection dialog (CertificateSelector) allows acceptance via a double-click on a TableView row. This path directly calls AcceptDialog(), bypassing the InputEventActivationProtector that gates the standard OK button. Consequently, an attacker could potentially use clickjacking/double-clickjacking to silently authenticate as the victim and obtain their TLS client certificate.
Affected files:
chrome/browser/ui/views/certificate_selector.ccui/views/controls/table/table_view.cc
Estimated timestamp from git blame: 2019-07-09
Root Cause Analysis
In chrome/browser/ui/views/certificate_selector.cc, the CertificateSelector handles double-click events on its table view rows via OnDoubleClick():
// chrome/browser/ui/views/certificate_selector.cc:346-350
void CertificateSelector::OnDoubleClick() {
if (GetSelectedCert()) {
AcceptDialog();
}
}
When a row is double-clicked, TableView::OnMousePressed (in ui/views/controls/table/table_view.cc) detects event.GetClickCount() == 2 and invokes the observer’s OnDoubleClick() method without performing any safety or temporal checks.
Subsequently, CertificateSelector::OnDoubleClick() calls DialogDelegate::AcceptDialog(), which invokes Accept() directly and closes the dialog.
This execution path completely bypasses DialogClientView::ButtonPressed() (defined in ui/views/window/dialog_client_view.cc), which is the only place where the dialog’s InputEventActivationProtector is consulted to prevent clickjacking/unintended interaction. Because the protector is bypassed, the standard 500ms input-protection window (which ignores clicks made immediately after a dialog is displayed) is not enforced for table row double-clicks.
Potential Attack Scenario
Note: These are potential steps. Our analysis is based on static code review; our tooling does not have the ability to run functional exploits or code.
- A victim with at least one installed TLS client certificate visits an attacker-controlled website.
- The website positions a decoy UI element (e.g. ‘Double-click to play’) precisely where the first row of the tab-modal certificate selector dialog will render.
- The website triggers a subresource request to an attacker-controlled TLS server requesting client authentication.
- The attacker’s server paces the TLS handshake to ensure that the
SSLClientCertificateSelectordialog appears on the screen immediately before the user performs the double-click. - The user’s double-click lands on the newly shown table row, triggering
OnDoubleClick(), which accepts the dialog and completes the handshake, silently disclosing the client certificate to the attacker.
Suggested Fix
To resolve this issue, the double-click handler should respect the input activation protector.
One potential approach is to remove the accept-on-double-click behavior entirely from CertificateSelector, similar to how it was addressed in DesktopMediaPickerDialogView (see crbug.com/40052774). This forces users to explicitly click the protected OK button.
Alternatively, if double-click acceptance must be retained, the TableViewObserver::OnDoubleClick interface should be updated to accept the triggering ui::Event so that it can be passed to the InputEventActivationProtector for validation before calling AcceptDialog().
Evaluated with Chrome root at commit: b2fea2e31df308d0f04e4ae47def4c4f939ee141
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.