Overview

Medium
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactUI misrepresentation in Browser
DescriptionUI misrepresentation in Browser
ComponentBrowser
Sub-componentCertificateSelector
Bug ClassSpoofing
Tracker522299740
Fix commit0a8a5b85a1c9 (chromium/src) +35/-2
CISA KEVNot listed
CreditedGoogle
Disclosed2026-10-06

Changed Functions

FunctionChangeNotes
if
chrome/browser/ui/views/certificate_selector.cc
modified

Files Changed

  • chrome/browser/ui/views/certificate_selector.cc
  • chrome/browser/ui/views/certificate_selector_interactive_uitest.cc
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);
+}
Loading diff…

Regression Test / PoC

shipped with the fix
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);
+}
Loading diff…

Original Bug Report

reported by [email protected]

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.cc
  • ui/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.

  1. A victim with at least one installed TLS client certificate visits an attacker-controlled website.
  2. 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.
  3. The website triggers a subresource request to an attacker-controlled TLS server requesting client authentication.
  4. The attacker’s server paces the TLS handshake to ensure that the SSLClientCertificateSelector dialog appears on the screen immediately before the user performs the double-click.
  5. 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.

View on issue tracker