Medium watch CVSS 3.1 chrome Info Disclosure 📄 Reporter bug report 🔧 Commit mapped

Overview

Medium
Severity
3.1
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactInformation leak in Passwords
DescriptionInformation leak in Passwords
ComponentPasswords
Bug ClassInfo Disclosure
Action tierwatch — information disclosure — security-relevant, below the RCE-class bar
Computed by PatchGap's deterministic exploitability ruler from the fixing commit. patch-now = RCE-class & attacker-reachable in a default config, or exploited in the wild; watch = real security signal below that bar; noise = no security relevance.
Tracker547832510
Fix commit18195740b3c5 (chromium/src) +22/-15
CWECWE-200 (Information exposure)
CVSS vectorCVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:L/I:N/A:N
CISA KEVNot listed
CreditedGoogle
Reported2026-08-17 (per vendor advisory)
Fix landed2026-08-18 (public git)
Disclosed2026-09-22
Patch gap35 days — fix public in source before the advisory

Background

`PasswordAutofillManager`
The browser-process component that manages password autofill suggestions and drives previews and fills in the renderer.
`PreviewSuggestion`
A password_manager_driver_ call that sends a username and a masked password string to the renderer to preview a suggestion before the user confirms filling it.
Grouped affiliation
A property (is_grouped_affiliation) marking a credential that was matched via affiliation grouping rather than an exact origin match, meaning it can belong to a different (cross-domain) site.
Preview
A pre-confirmation UI hint sent to the renderer showing the candidate username and a masked password, displayed before the user has agreed to fill.

Root Cause Analysis

Both preview code paths in password_autofill_manager.cc protected the password by always sending a fixed 8-asterisk mask (std::u16string(8, '*')) for cross-domain or grouped credentials, but they still passed the real payload.username / username to PreviewSuggestion and thus to the renderer. The vulnerable path in DidSelectSuggestion (backup credentials) previewed whenever payload.is_cross_domain was true, and the path in the username-based preview helper previewed whenever password_and_metadata->is_grouped_affiliation was true, in both cases leaking the full username of a credential belonging to another domain before any user confirmation. The invariant violated is that sensitive credential data for a grouped/cross-domain match must not reach the renderer until the user explicitly confirms the fill.

The fix makes both paths return early (return; and return false;) instead of previewing, so no username or mask is sent to the renderer for cross-domain/grouped credentials.

Key insight
The code hardened the password length by masking it but overlooked that the username itself is sensitive cross-domain data, so masking alone was insufficient; the fix removes the preview entirely for cross-domain/grouped credentials rather than merely masking the password.

Attack Path

  1. Set up a grouped credential An attacker relies on the victim having a saved credential that is affiliation-grouped or backup-flagged so it surfaces as a cross-domain suggestion (is_cross_domain / is_grouped_affiliation true) on an attacker-influenced page.
  2. Trigger the preview The victim hovers or selects the autofill suggestion, invoking DidSelectSuggestion or the username preview helper, which calls PreviewSuggestion before any confirmation.
  3. Leak the username to the renderer The full username for the cross-domain credential is sent to the renderer as part of the preview, exposing it to page-controlled or compromised renderer code without the victim confirming the fill.

Impact Assessment

An attacker gains the plaintext username of a saved cross-domain/grouped credential in the renderer process before the user confirms filling, an information leak in the Passwords component. The precondition is that the victim has a relevant grouped or backup credential and interacts with the suggestion enough to trigger a preview, but no explicit fill confirmation is required.

Changed Functions

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

Files Changed

  • components/password_manager/core/browser/password_autofill_manager_unittest.cc
  • components/password_manager/core/browser/password_autofill_manager.cc

Audit Directions

  • Mask-but-not-suppress
    Look for code that masks one field (e.g., password length) of a sensitive record while still forwarding another identifying field (e.g., username) across a trust boundary.
  • Pre-confirmation renderer sends
    Audit every PreviewSuggestion and similar pre-confirmation data flow to the renderer for cross-domain or grouped credentials that should require explicit user confirmation first.
  • Cross-domain flag handling
    Review all branches keyed on is_cross_domain or is_grouped_affiliation to confirm they suppress data exposure rather than merely transforming it.
From 18195740b3c50c999f042117abf570b8bf4c68c2 Mon Sep 17 00:00:00 2001
From: dresslerd <dresslerd@google.com>
Date: Tue, 18 Aug 2026 06:11:28 -0700
Subject: [PATCH] Prevent showing a username preview for grouped credentials.

This code already used to protect the length of the password (always
using 8 asterisks), but the full username was still sent to the renderer
for preview before the user was asked to confirm this. This just gets
rid of the preview entirely for grouped credentials.

Fixed: 547832510
Change-Id: Iabcb4fee0b66b8136205ae6cb8f6eb226a6a6964
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8255316
Reviewed-by: Viktor Semeniuk <vsemeniuk@google.com>
Commit-Queue: Daniel Dressler <dresslerd@google.com>
Reviewed-by: Timofey Chudakov <tchudakov@google.com>
Cr-Commit-Position: refs/heads/main@{#1681319}
---
diff --git a/components/password_manager/core/browser/password_autofill_manager.cc b/components/password_manager/core/browser/password_autofill_manager.cc
index 47aea46..fb30c01 100644
--- a/components/password_manager/core/browser/password_autofill_manager.cc
+++ b/components/password_manager/core/browser/password_autofill_manager.cc
@@ -298,8 +298,12 @@
             ->IsBiometricAuthenticationBeforeFillingEnabled()) {
       return;
     }
-    size_t password_length =
-        payload.is_cross_domain ? 8 : payload.backup_password.value().length();
+    if (payload.is_cross_domain) {
+      // Do not preview backup credentials marked as cross-domain to avoid
+      // leaking sensitive data to the renderer without user confirmation.
+      return;
+    }
+    size_t password_length = payload.backup_password.value().length();
     password_manager_driver_->PreviewSuggestion(
         payload.username, std::u16string(password_length, '*'));
     return;
@@ -856,10 +860,13 @@
   }
   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();
+    if (password_and_metadata->is_grouped_affiliation) {
+      // Do not preview grouped credentials (which can be cross-domain)
+      // to avoid leaking sensitive data to the renderer without user
+      // confirmation.
+      return false;
+    }
+    size_t password_length = password_and_metadata->password_value.length();
     password_manager_driver_->PreviewSuggestion(
         username, std::u16string(password_length, '*'));
     return true;
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 15933d0..a2250a7 100644
--- a/components/password_manager/core/browser/password_autofill_manager_unittest.cc
+++ b/components/password_manager/core/browser/password_autofill_manager_unittest.cc
@@ -489,15 +489,15 @@
       password_autofill_manager_->PreviewSuggestionForTest(test_username_));
 }
 
-TEST_F(PasswordAutofillManagerTest, PreviewGroupedSuggestion) {
+TEST_F(PasswordAutofillManagerTest, DoNotPreviewGroupedSuggestion) {
   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(
+  // Grouped suggestions should not be previewed to avoid leaking data to the
+  // renderer without user confirmation.
+  EXPECT_CALL(*client.mock_driver(), PreviewSuggestion).Times(0);
+  EXPECT_FALSE(
       password_autofill_manager_->PreviewSuggestionForTest(test_username_));
 }
 
@@ -2507,7 +2507,7 @@
 }
 
 TEST_F(PasswordAutofillManagerTest,
-       PasswordRecoveryFlow_PreviewGroupedBackupSuggestion) {
+       PasswordRecoveryFlow_DoNotPreviewGroupedBackupSuggestion) {
   TestPasswordManagerClient client;
   InitializePasswordAutofillManager(&client, nullptr);
   const Suggestion::PasswordSuggestionDetails payload(
@@ -2516,9 +2516,9 @@
   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, '*')));
+  // Grouped backup suggestions should not be previewed to avoid leaking data
+  // without user confirmation.
+  EXPECT_CALL(*client.mock_driver(), PreviewSuggestion).Times(0);
   password_autofill_manager_->DidSelectSuggestion(suggestion);
   testing::Mock::VerifyAndClearExpectations(client.mock_driver());
 
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 15933d0..a2250a7 100644
--- a/components/password_manager/core/browser/password_autofill_manager_unittest.cc
+++ b/components/password_manager/core/browser/password_autofill_manager_unittest.cc
@@ -489,15 +489,15 @@
       password_autofill_manager_->PreviewSuggestionForTest(test_username_));
 }
 
-TEST_F(PasswordAutofillManagerTest, PreviewGroupedSuggestion) {
+TEST_F(PasswordAutofillManagerTest, DoNotPreviewGroupedSuggestion) {
   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(
+  // Grouped suggestions should not be previewed to avoid leaking data to the
+  // renderer without user confirmation.
+  EXPECT_CALL(*client.mock_driver(), PreviewSuggestion).Times(0);
+  EXPECT_FALSE(
       password_autofill_manager_->PreviewSuggestionForTest(test_username_));
 }
 
@@ -2507,7 +2507,7 @@
 }
 
 TEST_F(PasswordAutofillManagerTest,
-       PasswordRecoveryFlow_PreviewGroupedBackupSuggestion) {
+       PasswordRecoveryFlow_DoNotPreviewGroupedBackupSuggestion) {
   TestPasswordManagerClient client;
   InitializePasswordAutofillManager(&client, nullptr);
   const Suggestion::PasswordSuggestionDetails payload(
@@ -2516,9 +2516,9 @@
   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, '*')));
+  // Grouped backup suggestions should not be previewed to avoid leaking data
+  // without user confirmation.
+  EXPECT_CALL(*client.mock_driver(), PreviewSuggestion).Times(0);
   password_autofill_manager_->DidSelectSuggestion(suggestion);
   testing::Mock::VerifyAndClearExpectations(client.mock_driver());
Loading diff…

Original Bug Report

reported by dr...@google.com

Potential cross-domain username leak for weakly affiliated credentials

Security Bug

Important: Please do not change the component of this bug manually.

Please READ THIS FAQ before filing a bug: https://chromium.googlesource.com/chromium/src/+/HEAD/docs/security/faq.md

Please see the following link for instructions on filing security bugs: https://www.chromium.org/Home/chromium-security/reporting-security-bugs

Reports may be eligible for reward payments under the Chrome VRP: https://g.co/chrome/vrp

NOTE: Security bugs are normally made public once a fix has been widely deployed.


VULNERABILITY DETAILS Similar to b/522545249, the suggested password popup shows the preview of usernames for grouped/weakly affiliated credentials. These credentials can be cross-domain, and the preview sends them to the renderer.

Note: The preview of a grouped password always shows exactly 8 asterisks, so these are not leaked. That was done in b/521476960.

Code location and presumably a quick fix is in https://crrev.com/c/8255316. This just hides the cross-domain preview entirely, not just the password, similar to b/522545249.

VERSION Chrome Version: 151.0.0.0 stable, code is older, but the password suggestions based on grouped affiliations only launched recently on July 29th 2026. Operating System: Desktop

REPRODUCTION CASE Please include a demonstration of the security bug, such as an attached HTML or binary file that reproduces the bug when loaded in Chrome. PLEASE make the file as small as possible and remove any content not required to demonstrate the bug, or any personal or confidential information.

Please attach files directly, not in zip or other archive formats, and if you’ve created a demonstration site please also attach the files needed to reproduce the demonstration locally.

FOR CRASHES, PLEASE INCLUDE THE FOLLOWING ADDITIONAL INFORMATION Type of crash: [tab, browser, etc.] Crash State: [see link above: stack trace with symbols, registers, exception record] Client ID (if relevant): [see link above]

CREDIT INFORMATION Externally reported security bugs may appear in Chrome release notes. If this bug is included, how would you like to be credited? Reporter credit: [goes here]

View on issue tracker