Low chrome Logic Error 🔧 Commit mapped

Overview

Low
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactUI misrepresentation in Passwords
DescriptionUI misrepresentation in Passwords
ComponentPasswords
Bug ClassLogic Error
Tracker533044125
Fix commit10c3ba83d367 (chromium/src) +52/-1
CISA KEVNot listed
CreditedGoogle
Disclosed2026-09-08

Changed Functions

FunctionChangeNotes
if
chrome/browser/password_manager/chrome_password_manager_client.cc
modified

Files Changed

  • chrome/browser/password_manager/chrome_password_manager_client.cc
  • chrome/browser/password_manager/chrome_password_manager_client_unittest.cc
From 10c3ba83d3674d727b18f64e239bda152bb32e9e Mon Sep 17 00:00:00 2001
From: Friedrich Horschig <[email protected]>
Date: Thu, 30 Jul 2026 07:59:30 -0700
Subject: [PATCH] [Autofill] Check driver CanShowAutofillUi before showing TTF

This CL ensures that
ChromePasswordManagerClient::ContinueShowKeyboardReplacingSurface checks
weak_driver->CanShowAutofillUi() before proceeding to show Touch to Fill
or CredMan UI and setting the keyboard replacing surface visibility.

Fixed: 533044125
Change-Id: If69b90f8fbb48aadaefbdca4800ffd99344452ae
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8174004
Reviewed-by: Ioana Treib <[email protected]>
Commit-Queue: Friedrich Hauser <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1671066}
---

diff --git a/chrome/browser/password_manager/chrome_password_manager_client.cc b/chrome/browser/password_manager/chrome_password_manager_client.cc
index 1df9f1f..7fd808b4 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client.cc
+++ b/chrome/browser/password_manager/chrome_password_manager_client.cc
@@ -653,7 +653,7 @@
   // without being called.
   auto split_delay_callback =
       base::SplitOnceCallback(std::move(delay_callback));
-  if (!weak_driver) {
+  if (!weak_driver || !weak_driver->CanShowAutofillUi()) {
     return;
   }
   password_manager::ContentPasswordManagerDriver* driver =
diff --git a/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc b/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc
index 220675f..738ca2fb 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc
+++ b/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc
@@ -92,6 +92,7 @@
 #include "content/public/common/url_constants.h"
 #include "content/public/test/mock_navigation_handle.h"
 #include "content/public/test/navigation_simulator.h"
+#include "content/public/test/prerender_test_util.h"
 #include "content/public/test/web_contents_tester.h"
 #include "mojo/public/cpp/bindings/associated_receiver.h"
 #include "mojo/public/cpp/bindings/pending_associated_receiver.h"
@@ -2590,4 +2591,54 @@
   base::RunLoop().RunUntilIdle();
 }
 
+TEST_F(ChromePasswordManagerClientAndroidTest,
+       DoNotShowKeyboardReplacingSurfaceForInactiveFrame) {
+  webauthn::WebAuthnCredManDelegate::override_cred_man_support_for_testing(
+      webauthn::CredManSupport::DISABLED);
+  CreateManualFillingController(web_contents());
+
+  auto* ttf_controller = MakeMockTouchToFillPasswordManagerController();
+  EXPECT_CALL(*ttf_controller, InitData).Times(0);
+  EXPECT_CALL(*ttf_controller, Show).Times(0);
+
+  constexpr char kUrl[] = "https://www.foo.com/login.html";
+  NavigateAndCommit(GURL(kUrl));
+
+  content::RenderFrameHostWrapper old_rfh(main_rfh());
+  ContentAutofillDriver* autofill_driver =
+      ContentAutofillDriver::GetForRenderFrameHost(old_rfh.get());
+  ASSERT_TRUE(autofill_driver);
+
+  std::vector<FormFieldData> fields = {CreateTestFormField(
+      "Username:", "username", "", FormControlType::kInputText, "webauthn")};
+  FormData form =
+      CreateFormDataForRenderFrameHost(*old_rfh.get(), std::move(fields));
+  {
+    autofill::TestAutofillManagerWaiter waiter(
+        autofill_driver->GetAutofillManager(),
+        {autofill::AutofillManagerEvent::kFormsSeen});
+    autofill_driver->renderer_events().FormsSeen(/*updated_forms=*/{form},
+                                                 /*removed_forms=*/{});
+    ASSERT_TRUE(waiter.Wait(/*num_expected_relevant_events=*/1));
+  }
+
+  auto* old_driver =
+      ContentPasswordManagerDriver::GetForRenderFrameHost(old_rfh.get());
+
+  GetClient()->ShowKeyboardReplacingSurface(
+      old_driver, GetFocusedFieldSuggestionRequest(form));
+
+  // Navigate to another site so old_rfh becomes inactive.
+  NavigateAndCommit(GURL("https://www.bar.com/page2.html"));
+  ASSERT_FALSE(old_rfh.get()->IsActive());
+
+  // Passkeys arrive for the old driver/frame after page navigation.
+  ChromeWebAuthnCredentialsDelegateFactory::GetFactory(web_contents())
+      ->GetDelegateForFrame(old_rfh.get())
+      ->OnCredentialsReceived(
+          std::vector<password_manager::PasskeyCredential>(),
+          ChromeWebAuthnCredentialsDelegate::SecurityKeyOrHybridFlowAvailable(
+              true));
+}
+
 #endif  // BUILDFLAG(IS_ANDROID)
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc b/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc
index 220675f..738ca2fb 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc
+++ b/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc
@@ -92,6 +92,7 @@
 #include "content/public/common/url_constants.h"
 #include "content/public/test/mock_navigation_handle.h"
 #include "content/public/test/navigation_simulator.h"
+#include "content/public/test/prerender_test_util.h"
 #include "content/public/test/web_contents_tester.h"
 #include "mojo/public/cpp/bindings/associated_receiver.h"
 #include "mojo/public/cpp/bindings/pending_associated_receiver.h"
@@ -2590,4 +2591,54 @@
   base::RunLoop().RunUntilIdle();
 }
 
+TEST_F(ChromePasswordManagerClientAndroidTest,
+       DoNotShowKeyboardReplacingSurfaceForInactiveFrame) {
+  webauthn::WebAuthnCredManDelegate::override_cred_man_support_for_testing(
+      webauthn::CredManSupport::DISABLED);
+  CreateManualFillingController(web_contents());
+
+  auto* ttf_controller = MakeMockTouchToFillPasswordManagerController();
+  EXPECT_CALL(*ttf_controller, InitData).Times(0);
+  EXPECT_CALL(*ttf_controller, Show).Times(0);
+
+  constexpr char kUrl[] = "https://www.foo.com/login.html";
+  NavigateAndCommit(GURL(kUrl));
+
+  content::RenderFrameHostWrapper old_rfh(main_rfh());
+  ContentAutofillDriver* autofill_driver =
+      ContentAutofillDriver::GetForRenderFrameHost(old_rfh.get());
+  ASSERT_TRUE(autofill_driver);
+
+  std::vector<FormFieldData> fields = {CreateTestFormField(
+      "Username:", "username", "", FormControlType::kInputText, "webauthn")};
+  FormData form =
+      CreateFormDataForRenderFrameHost(*old_rfh.get(), std::move(fields));
+  {
+    autofill::TestAutofillManagerWaiter waiter(
+        autofill_driver->GetAutofillManager(),
+        {autofill::AutofillManagerEvent::kFormsSeen});
+    autofill_driver->renderer_events().FormsSeen(/*updated_forms=*/{form},
+                                                 /*removed_forms=*/{});
+    ASSERT_TRUE(waiter.Wait(/*num_expected_relevant_events=*/1));
+  }
+
+  auto* old_driver =
+      ContentPasswordManagerDriver::GetForRenderFrameHost(old_rfh.get());
+
+  GetClient()->ShowKeyboardReplacingSurface(
+      old_driver, GetFocusedFieldSuggestionRequest(form));
+
+  // Navigate to another site so old_rfh becomes inactive.
+  NavigateAndCommit(GURL("https://www.bar.com/page2.html"));
+  ASSERT_FALSE(old_rfh.get()->IsActive());
+
+  // Passkeys arrive for the old driver/frame after page navigation.
+  ChromeWebAuthnCredentialsDelegateFactory::GetFactory(web_contents())
+      ->GetDelegateForFrame(old_rfh.get())
+      ->OnCredentialsReceived(
+          std::vector<password_manager::PasskeyCredential>(),
+          ChromeWebAuthnCredentialsDelegate::SecurityKeyOrHybridFlowAvailable(
+              true));
+}
+
 #endif  // BUILDFLAG(IS_ANDROID)
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.