Chrome · Passwords
CVE-2026-14050
Logic Error in Passwords
Overview
Low
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifcomponents/password_manager/core/browser/undo_password_change_controller.cc |
modified |
Files Changed
components/password_manager/core/browser/undo_password_change_controller.cccomponents/password_manager/core/browser/undo_password_change_controller_unittest.cc
Patch
From 08456f50839dffaefdf84205548fe537eb434870 Mon Sep 17 00:00:00 2001
From: Oleksandr Tara <otara@google.com>
Date: Tue, 19 May 2026 01:50:09 -0700
Subject: [PATCH] Ignore grouped affiliations for proactive password recovery.
Suggestions from grouped affiliations need to show cross-domain
confirmation before filling but to achieve this in the proactive
password recovery, we need non-trivial amount of work. Instead, as a
quick fix, we can disable proactive recovery for passwords from grouped
affiliations.
Fixed: b:501708647
Change-Id: I36d0ecbdf03fd0afd14a6fec62f8af38a0759fed
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7854926
Reviewed-by: Viktor Semeniuk <vsemeniuk@google.com>
Commit-Queue: Ioana Treib <ioanap@chromium.org>
Reviewed-by: Ioana Treib <ioanap@chromium.org>
Auto-Submit: Oleksandr Tara <otara@google.com>
Cr-Commit-Position: refs/heads/main@{#1632709}
---
diff --git a/components/password_manager/core/browser/undo_password_change_controller.cc b/components/password_manager/core/browser/undo_password_change_controller.cc
index d18f18c0..3239365 100644
--- a/components/password_manager/core/browser/undo_password_change_controller.cc
+++ b/components/password_manager/core/browser/undo_password_change_controller.cc
@@ -30,6 +30,29 @@
constexpr char kPasswordChangeRecoveryFlowStateHistogram[] =
"PasswordManager.PasswordChangeRecoveryFlow";
+bool IsFormEligibleForProactiveRecovery(
+ const StoredCredential* form_best_match,
+ const std::u16string& failed_password_value) {
+ if (!form_best_match) {
+ return false;
+ }
+
+ if (password_manager_util::GetMatchType(*form_best_match) ==
+ password_manager_util::GetLoginMatchType::kGrouped) {
+ return false;
+ }
+
+ if (!form_best_match->GetPasswordBackup()) {
+ return false;
+ }
+
+ if (form_best_match->GetPasswordBackup() == failed_password_value) {
+ return false;
+ }
+
+ return true;
+}
+
} // namespace
UndoPasswordChangeController::UndoPasswordChangeController() = default;
@@ -168,9 +191,8 @@
const StoredCredential* form_best_match =
password_manager_util::FindCredentialByUsername(
form_manager->GetBestMatches(), failed_login_form_->username_value);
- if (!form_best_match || !form_best_match->GetPasswordBackup() ||
- form_best_match->GetPasswordBackup() ==
- failed_login_form_->password_value) {
+ if (!IsFormEligibleForProactiveRecovery(
+ form_best_match, failed_login_form_->password_value)) {
FinishObserving();
return;
}
diff --git a/components/password_manager/core/browser/undo_password_change_controller_unittest.cc b/components/password_manager/core/browser/undo_password_change_controller_unittest.cc
index cb3498d3..5b72771e 100644
--- a/components/password_manager/core/browser/undo_password_change_controller_unittest.cc
+++ b/components/password_manager/core/browser/undo_password_change_controller_unittest.cc
@@ -383,6 +383,22 @@
}
TEST_F(UndoPasswordChangeControllerTest,
+ OnLoginPotentiallyFailed_GroupedAffiliation_Ignored) {
+ best_match_form_.SetPasswordBackupNote(kBackupPassword);
+ best_match_form_.match_type =
+ password_manager::PasswordForm::MatchType::kGrouped;
+ auto form_manager = CreateFormManager(best_match_form_);
+
+ controller_.OnLoginPotentiallyFailed(&driver_, failed_login_form_);
+ EXPECT_CALL(driver_, TriggerPasswordRecoverySuggestions).Times(0);
+ static_cast<PasswordFormManagerObserver*>(&controller_)
+ ->OnPasswordFormParsed(form_manager.get());
+
+ EXPECT_EQ(controller_.GetState(kUsername),
+ PasswordRecoveryState::kRegularFlow);
+}
+
+TEST_F(UndoPasswordChangeControllerTest,
FindLoginWithProactiveRecoveryStateNoMatch) {
best_match_form_.SetPasswordBackupNote(kBackupPassword);
auto form_manager = CreateFormManager(best_match_form_);
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/components/password_manager/core/browser/undo_password_change_controller_unittest.cc b/components/password_manager/core/browser/undo_password_change_controller_unittest.cc
index cb3498d3..5b72771e 100644
--- a/components/password_manager/core/browser/undo_password_change_controller_unittest.cc
+++ b/components/password_manager/core/browser/undo_password_change_controller_unittest.cc
@@ -383,6 +383,22 @@
}
TEST_F(UndoPasswordChangeControllerTest,
+ OnLoginPotentiallyFailed_GroupedAffiliation_Ignored) {
+ best_match_form_.SetPasswordBackupNote(kBackupPassword);
+ best_match_form_.match_type =
+ password_manager::PasswordForm::MatchType::kGrouped;
+ auto form_manager = CreateFormManager(best_match_form_);
+
+ controller_.OnLoginPotentiallyFailed(&driver_, failed_login_form_);
+ EXPECT_CALL(driver_, TriggerPasswordRecoverySuggestions).Times(0);
+ static_cast<PasswordFormManagerObserver*>(&controller_)
+ ->OnPasswordFormParsed(form_manager.get());
+
+ EXPECT_EQ(controller_.GetState(kUsername),
+ PasswordRecoveryState::kRegularFlow);
+}
+
+TEST_F(UndoPasswordChangeControllerTest,
FindLoginWithProactiveRecoveryStateNoMatch) {
best_match_form_.SetPasswordBackupNote(kBackupPassword);
auto form_manager = CreateFormManager(best_match_form_);
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.
References
On This Page