Low chrome Logic Error 🔧 Commit mapped

Overview

Low
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactInappropriate implementation in Passwords
DescriptionInappropriate implementation in Passwords
ComponentPasswords
Bug ClassLogic Error
Tracker521476960
Fix commit3bed447aa3fa (chromium/src) +40/-4
CISA KEVNot listed
CreditedGoogle
Disclosed2026-07-29

Changed Functions

FunctionChangeNotes
TEST_F
components/password_manager/core/browser/password_autofill_manager_unittest.cc
modified

Files Changed

  • components/password_manager/core/browser/password_autofill_manager.cc
  • components/password_manager/core/browser/password_autofill_manager_unittest.cc
From 3bed447aa3fa78a865159d7a0719e4a723e1e30a Mon Sep 17 00:00:00 2001
From: Oleksandr Tara <[email protected]>
Date: Thu, 11 Jun 2026 04:53:16 -0700
Subject: [PATCH] Mask credentials from grouped suggestions with a fixed length string in previews.

When previewing password suggestions that come from a grouped
affiliation, use a fixed 8-character mask instead of a mask based on the
actual password length.

Fixed: b:521476960
Change-Id: I01cc15f6edc3f79b16946f3d0dfc9770c513434a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7922492
Commit-Queue: Oleksandr Tara <[email protected]>
Reviewed-by: Viktor Semeniuk <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1645278}
---

diff --git a/components/password_manager/core/browser/password_autofill_manager.cc b/components/password_manager/core/browser/password_autofill_manager.cc
index e95d609..67eca40 100644
--- a/components/password_manager/core/browser/password_autofill_manager.cc
+++ b/components/password_manager/core/browser/password_autofill_manager.cc
@@ -279,9 +279,10 @@
             ->IsBiometricAuthenticationBeforeFillingEnabled()) {
       return;
     }
+    size_t password_length =
+        payload.is_cross_domain ? 8 : payload.backup_password.value().length();
     password_manager_driver_->PreviewSuggestion(
-        payload.username,
-        std::u16string(payload.backup_password.value().length(), '*'));
+        payload.username, std::u16string(password_length, '*'));
     return;
   }
   PreviewSuggestion(GetUsernameFromSuggestion(suggestion.main_text.value),
@@ -817,9 +818,12 @@
   }
   if (const autofill::PasswordAndMetadata* password_and_metadata =
           GetPasswordAndMetadataForUsername(username, type)) {
+    size_t password_length =
+        password_and_metadata->is_grouped_affiliation
+            ? 8
+            : password_and_metadata->password_value.length();
     password_manager_driver_->PreviewSuggestion(
-        username,
-        std::u16string(password_and_metadata->password_value.length(), '*'));
+        username, std::u16string(password_length, '*'));
     return true;
   }
   return false;
diff --git a/components/password_manager/core/browser/password_autofill_manager_unittest.cc b/components/password_manager/core/browser/password_autofill_manager_unittest.cc
index c6a0485..f1fc6d36 100644
--- a/components/password_manager/core/browser/password_autofill_manager_unittest.cc
+++ b/components/password_manager/core/browser/password_autofill_manager_unittest.cc
@@ -486,6 +486,18 @@
       password_autofill_manager_->PreviewSuggestionForTest(test_username_));
 }
 
+TEST_F(PasswordAutofillManagerTest, PreviewGroupedSuggestion) {
+  fill_data().preferred_login.is_grouped_affiliation = true;
+  TestPasswordManagerClient client;
+  InitializePasswordAutofillManager(&client, nullptr);
+
+  // Grouped suggestions should be masked using an 8-character long mask.
+  EXPECT_CALL(*client.mock_driver(),
+              PreviewSuggestion(test_username_, std::u16string(8, '*')));
+  EXPECT_TRUE(
+      password_autofill_manager_->PreviewSuggestionForTest(test_username_));
+}
+
 // Test that the popup is marked as visible after receiving password
 // suggestions.
 TEST_F(PasswordAutofillManagerTest, ExternalDelegatePasswordSuggestions) {
@@ -2431,6 +2443,26 @@
             PasswordRecoveryState::kRegularFlow);
 }
 
+TEST_F(PasswordAutofillManagerTest,
+       PasswordRecoveryFlow_PreviewGroupedBackupSuggestion) {
+  TestPasswordManagerClient client;
+  InitializePasswordAutofillManager(&client, nullptr);
+  const Suggestion::PasswordSuggestionDetails payload(
+      test_username_, test_password_, backup_password_,
+      /*signon_realm=*/"", /*is_cross_domain=*/true);
+  const Suggestion suggestion = autofill::test::CreateAutofillSuggestion(
+      autofill::SuggestionType::kBackupPasswordEntry, test_username_, payload);
+
+  // Grouped backup suggestions should be masked using an 8-character long mask.
+  EXPECT_CALL(*client.mock_driver(),
+              PreviewSuggestion(test_username_, std::u16string(8, '*')));
+  password_autofill_manager_->DidSelectSuggestion(suggestion);
+  testing::Mock::VerifyAndClearExpectations(client.mock_driver());
+
+  EXPECT_EQ(client.GetUndoPasswordChangeController()->GetState(test_username_),
+            PasswordRecoveryState::kRegularFlow);
+}
+
 TEST_F(
     PasswordAutofillManagerTest,
     PasswordRecoveryFlow_AuthBeforeFillingEnabled_NoPreviewBackupSuggestion) {
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/components/password_manager/core/browser/password_autofill_manager_unittest.cc b/components/password_manager/core/browser/password_autofill_manager_unittest.cc
index c6a0485..f1fc6d36 100644
--- a/components/password_manager/core/browser/password_autofill_manager_unittest.cc
+++ b/components/password_manager/core/browser/password_autofill_manager_unittest.cc
@@ -486,6 +486,18 @@
       password_autofill_manager_->PreviewSuggestionForTest(test_username_));
 }
 
+TEST_F(PasswordAutofillManagerTest, PreviewGroupedSuggestion) {
+  fill_data().preferred_login.is_grouped_affiliation = true;
+  TestPasswordManagerClient client;
+  InitializePasswordAutofillManager(&client, nullptr);
+
+  // Grouped suggestions should be masked using an 8-character long mask.
+  EXPECT_CALL(*client.mock_driver(),
+              PreviewSuggestion(test_username_, std::u16string(8, '*')));
+  EXPECT_TRUE(
+      password_autofill_manager_->PreviewSuggestionForTest(test_username_));
+}
+
 // Test that the popup is marked as visible after receiving password
 // suggestions.
 TEST_F(PasswordAutofillManagerTest, ExternalDelegatePasswordSuggestions) {
@@ -2431,6 +2443,26 @@
             PasswordRecoveryState::kRegularFlow);
 }
 
+TEST_F(PasswordAutofillManagerTest,
+       PasswordRecoveryFlow_PreviewGroupedBackupSuggestion) {
+  TestPasswordManagerClient client;
+  InitializePasswordAutofillManager(&client, nullptr);
+  const Suggestion::PasswordSuggestionDetails payload(
+      test_username_, test_password_, backup_password_,
+      /*signon_realm=*/"", /*is_cross_domain=*/true);
+  const Suggestion suggestion = autofill::test::CreateAutofillSuggestion(
+      autofill::SuggestionType::kBackupPasswordEntry, test_username_, payload);
+
+  // Grouped backup suggestions should be masked using an 8-character long mask.
+  EXPECT_CALL(*client.mock_driver(),
+              PreviewSuggestion(test_username_, std::u16string(8, '*')));
+  password_autofill_manager_->DidSelectSuggestion(suggestion);
+  testing::Mock::VerifyAndClearExpectations(client.mock_driver());
+
+  EXPECT_EQ(client.GetUndoPasswordChangeController()->GetState(test_username_),
+            PasswordRecoveryState::kRegularFlow);
+}
+
 TEST_F(
     PasswordAutofillManagerTest,
     PasswordRecoveryFlow_AuthBeforeFillingEnabled_NoPreviewBackupSuggestion) {
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.