Low chrome Logic Error 🔧 Commit mapped

Overview

Low
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactInformation leak in Passwords
DescriptionInformation leak in Passwords
ComponentPasswords
Bug ClassLogic Error
Tracker532968511
Fix commita7991af9d476 (chromium/src) +78/-5
CISA KEVNot listed
CreditedGoogle
Disclosed2026-09-08

Changed Functions

FunctionChangeNotes
TEST_F
components/autofill/core/browser/foundations/browser_autofill_manager_unittest.cc
modified
OtpSuggestionGeneratorTest
components/autofill/core/browser/suggestions/one_time_passwords/otp_suggestion_generator_unittest.cc
modified
TEST_F
components/autofill/core/browser/suggestions/one_time_passwords/otp_suggestion_generator_unittest.cc
modified

Files Changed

  • components/autofill/core/browser/foundations/browser_autofill_manager.cc
  • components/autofill/core/browser/foundations/browser_autofill_manager_unittest.cc
  • components/autofill/core/browser/suggestions/one_time_passwords/otp_suggestion_generator.cc
  • components/autofill/core/browser/suggestions/one_time_passwords/otp_suggestion_generator_unittest.cc
From a7991af9d476b4ca205454aead73a71f6a1d08e5 Mon Sep 17 00:00:00 2001
From: Matthias Koerber <koerber@google.com>
Date: Tue, 04 Aug 2026 04:01:13 -0700
Subject: [PATCH] [OTP] Restrict SMS OTP Autofill to secure contexts

This CL ensures that SMS OTP suggestions are only offered on secure
(HTTPS) contexts. To achieve this, we silently suppress OTP suggestions
when the context is insecure:

1. In the legacy path (BrowserAutofillManager), we skip fetching OTPs
from OtpManager in Phase 1 if the context is insecure, and ensure we
don't build suggestions in Phase 2.

2. In the new suggestion pipeline (OtpSuggestionGenerator), we early
return with empty suggestions if the context is insecure.

Silent suppression was chosen over showing a warning message (similar to
Payments) to avoid UI noise on HTTP pages when no OTP is actually
available.

Fixed: 532968511
Change-Id: Iaec97661cb16f38c761473fc8dc462ce02b29000
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8177172
Auto-Submit: Matthias Körber <koerber@google.com>
Commit-Queue: Matthias Körber <koerber@google.com>
Reviewed-by: Jihad Hanna <jihadghanna@google.com>
Cr-Commit-Position: refs/heads/main@{#1673232}
---

diff --git a/components/autofill/core/browser/foundations/browser_autofill_manager.cc b/components/autofill/core/browser/foundations/browser_autofill_manager.cc
index f09f106c..57c06fc 100644
--- a/components/autofill/core/browser/foundations/browser_autofill_manager.cc
+++ b/components/autofill/core/browser/foundations/browser_autofill_manager.cc
@@ -1502,6 +1502,10 @@
   // autocomplete.
   if (otp_manager_ && autofill_field &&
       autofill_field->Type().GetTypes().contains(ONE_TIME_CODE)) {
+    if (!client().IsContextSecure()) {
+      std::move(generate_suggestions_and_maybe_show_ui_phase2).Run({});
+      return;
+    }
     otp_manager_->GetOtpSuggestions(
         std::move(generate_suggestions_and_maybe_show_ui_phase2));
     return;
@@ -3291,7 +3295,9 @@
       }
       break;
     case FillingProduct::kOneTimePassword:
-      suggestions = BuildOtpSuggestions(one_time_passwords);
+      if (client().IsContextSecure()) {
+        suggestions = BuildOtpSuggestions(one_time_passwords);
+      }
       break;
     case FillingProduct::kAtMemory:
       return {};
diff --git a/components/autofill/core/browser/foundations/browser_autofill_manager_unittest.cc b/components/autofill/core/browser/foundations/browser_autofill_manager_unittest.cc
index 65976418..19de7d41 100644
--- a/components/autofill/core/browser/foundations/browser_autofill_manager_unittest.cc
+++ b/components/autofill/core/browser/foundations/browser_autofill_manager_unittest.cc
@@ -7125,6 +7125,44 @@
   EXPECT_EQ(otp_value, filled_fields[0].value());
 }
 
+// Test that OTP suggestions are silently suppressed on insecure contexts.
+TEST_F(BrowserAutofillManagerOtpSuggestionsTest,
+       OtpSuggestions_InsecureContext) {
+  autofill_client().set_last_committed_primary_main_frame_url(
+      GURL("http://example.com"));
+
+  FormData form =
+      test::GetFormData({.fields = {
+                             {.label = u"Enter one time code",
+                              .form_control_type = FormControlType::kInputText},
+                         }});
+
+  // Simulate form parsing results.
+  auto form_structure = std::make_unique<FormStructure>(form);
+  form_structure->field(0)->set_heuristic_type(
+      HeuristicSource::kPasswordManagerMachineLearning,
+      FieldType::ONE_TIME_CODE);
+  test_api(autofill_manager()).AddSeenFormStructure(std::move(form_structure));
+
+  // We should NOT call GetOtpSuggestions on the manager.
+  EXPECT_CALL(otp_manager(), GetOtpSuggestions).Times(0);
+
+  ON_CALL(autocomplete_history_manager(), OnGetSingleFieldSuggestions)
+      .WillByDefault(
+          [](const FormData& form, const FormStructure* form_structure,
+             const FormFieldData& field, const AutofillField* autofill_field,
+             const AutofillClient& client,
+             SingleFieldFillRouter::OnSuggestionsReturnedCallback
+                 on_suggestions_returned) {
+            std::move(on_suggestions_returned).Run(field.global_id(), {});
+          });
+
+  OnAskForValuesToFill(form, form.fields()[0]);
+
+  // We expect no suggestions.
+  external_delegate()->CheckNoSuggestions(form.fields()[0].global_id());
+}
+
 // Tests that FillOrPreviewForm correctly passes the blocked_fields to the
 // FormFiller.
 TEST_F(BrowserAutofillManagerTest, FillOrPreviewForm_BlockedFields) {
diff --git a/components/autofill/core/browser/suggestions/one_time_passwords/otp_suggestion_generator.cc b/components/autofill/core/browser/suggestions/one_time_passwords/otp_suggestion_generator.cc
index a006afd..8fd0e5d 100644
--- a/components/autofill/core/browser/suggestions/one_time_passwords/otp_suggestion_generator.cc
+++ b/components/autofill/core/browser/suggestions/one_time_passwords/otp_suggestion_generator.cc
@@ -15,9 +15,6 @@
 #include "components/autofill/core/browser/data_quality/addresses/profile_token_quality.h"
 #include "components/autofill/core/browser/field_types.h"
 #include "components/autofill/core/browser/foundations/autofill_client.h"
-#if BUILDFLAG(IS_ANDROID)
-#include "components/strings/grit/components_strings.h"
-#endif
 #include "components/autofill/core/browser/integrators/one_time_tokens/otp_manager.h"
 #include "components/autofill/core/browser/suggestions/suggestion.h"
 #include "components/autofill/core/browser/suggestions/suggestion_generator.h"
@@ -83,6 +80,11 @@
     return;
   }
 
+  if (!client.IsContextSecure()) {
+    std::move(callback).Run({SuggestionDataSource::kOneTimePassword, {}});
+    return;
+  }
+
   otp_manager_->GetOtpSuggestions(
       base::BindOnce(&OtpSuggestionGenerator::OnOtpReturned,
                      weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
diff --git a/components/autofill/core/browser/suggestions/one_time_passwords/otp_suggestion_generator_unittest.cc b/components/autofill/core/browser/suggestions/one_time_passwords/otp_suggestion_generator_unittest.cc
index 370a1d7c..66eaee6 100644
--- a/components/autofill/core/browser/suggestions/one_time_passwords/otp_suggestion_generator_unittest.cc
+++ b/components/autofill/core/browser/suggestions/one_time_passwords/otp_suggestion_generator_unittest.cc
@@ -19,16 +19,19 @@
 #include "components/autofill/core/common/autofill_test_utils.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 namespace autofill {
 
 using ::testing::Field;
+using ::testing::IsEmpty;
+using ::testing::Pair;
 
 class OtpSuggestionGeneratorTest : public testing::Test {
  protected:
   OtpSuggestionGeneratorTest() = default;
 
-  AutofillClient& client() { return autofill_client_; }
+  TestAutofillClient& client() { return autofill_client_; }
   OtpSuggestionGenerator& generator() { return generator_; }
   MockOtpManager& otp_manager() { return otp_manager_; }
 
@@ -94,4 +97,28 @@
 #endif
 }
 
+// Test that OTP suggestions are silently suppressed on insecure contexts.
+TEST_F(OtpSuggestionGeneratorTest, GenerateOtpSuggestions_InsecureContext) {
+  client().set_last_committed_primary_main_frame_url(
+      GURL("http://example.com"));
+  FormData form = test::GetFormData({.fields = {{.role = ONE_TIME_CODE}}});
+  FormStructure form_structure(form);
+  form_structure.field(0)->SetTypeTo(AutofillType(ONE_TIME_CODE), std::nullopt);
+
+  EXPECT_CALL(otp_manager(), GetOtpSuggestions).Times(0);
+
+  base::MockCallback<
+      base::OnceCallback<void(SuggestionGenerator::ReturnedSuggestions)>>
+      suggestions_generated_callback;
+
+  EXPECT_CALL(
+      suggestions_generated_callback,
+      Run(Pair(SuggestionGenerator::SuggestionDataSource::kOneTimePassword,
+               IsEmpty())));
+
+  generator().GenerateSuggestions(form, form.fields()[0], &form_structure,
+                                  form_structure.field(0), client(),
+                                  suggestions_generated_callback.Get());
+}
+
 }  // namespace autofill
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/components/autofill/core/browser/foundations/browser_autofill_manager_unittest.cc b/components/autofill/core/browser/foundations/browser_autofill_manager_unittest.cc
index 65976418..19de7d41 100644
--- a/components/autofill/core/browser/foundations/browser_autofill_manager_unittest.cc
+++ b/components/autofill/core/browser/foundations/browser_autofill_manager_unittest.cc
@@ -7125,6 +7125,44 @@
   EXPECT_EQ(otp_value, filled_fields[0].value());
 }
 
+// Test that OTP suggestions are silently suppressed on insecure contexts.
+TEST_F(BrowserAutofillManagerOtpSuggestionsTest,
+       OtpSuggestions_InsecureContext) {
+  autofill_client().set_last_committed_primary_main_frame_url(
+      GURL("http://example.com"));
+
+  FormData form =
+      test::GetFormData({.fields = {
+                             {.label = u"Enter one time code",
+                              .form_control_type = FormControlType::kInputText},
+                         }});
+
+  // Simulate form parsing results.
+  auto form_structure = std::make_unique<FormStructure>(form);
+  form_structure->field(0)->set_heuristic_type(
+      HeuristicSource::kPasswordManagerMachineLearning,
+      FieldType::ONE_TIME_CODE);
+  test_api(autofill_manager()).AddSeenFormStructure(std::move(form_structure));
+
+  // We should NOT call GetOtpSuggestions on the manager.
+  EXPECT_CALL(otp_manager(), GetOtpSuggestions).Times(0);
+
+  ON_CALL(autocomplete_history_manager(), OnGetSingleFieldSuggestions)
+      .WillByDefault(
+          [](const FormData& form, const FormStructure* form_structure,
+             const FormFieldData& field, const AutofillField* autofill_field,
+             const AutofillClient& client,
+             SingleFieldFillRouter::OnSuggestionsReturnedCallback
+                 on_suggestions_returned) {
+            std::move(on_suggestions_returned).Run(field.global_id(), {});
+          });
+
+  OnAskForValuesToFill(form, form.fields()[0]);
+
+  // We expect no suggestions.
+  external_delegate()->CheckNoSuggestions(form.fields()[0].global_id());
+}
+
 // Tests that FillOrPreviewForm correctly passes the blocked_fields to the
 // FormFiller.
 TEST_F(BrowserAutofillManagerTest, FillOrPreviewForm_BlockedFields) {
diff --git a/components/autofill/core/browser/suggestions/one_time_passwords/otp_suggestion_generator_unittest.cc b/components/autofill/core/browser/suggestions/one_time_passwords/otp_suggestion_generator_unittest.cc
index 370a1d7c..66eaee6 100644
--- a/components/autofill/core/browser/suggestions/one_time_passwords/otp_suggestion_generator_unittest.cc
+++ b/components/autofill/core/browser/suggestions/one_time_passwords/otp_suggestion_generator_unittest.cc
@@ -19,16 +19,19 @@
 #include "components/autofill/core/common/autofill_test_utils.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 namespace autofill {
 
 using ::testing::Field;
+using ::testing::IsEmpty;
+using ::testing::Pair;
 
 class OtpSuggestionGeneratorTest : public testing::Test {
  protected:
   OtpSuggestionGeneratorTest() = default;
 
-  AutofillClient& client() { return autofill_client_; }
+  TestAutofillClient& client() { return autofill_client_; }
   OtpSuggestionGenerator& generator() { return generator_; }
   MockOtpManager& otp_manager() { return otp_manager_; }
 
@@ -94,4 +97,28 @@
 #endif
 }
 
+// Test that OTP suggestions are silently suppressed on insecure contexts.
+TEST_F(OtpSuggestionGeneratorTest, GenerateOtpSuggestions_InsecureContext) {
+  client().set_last_committed_primary_main_frame_url(
+      GURL("http://example.com"));
+  FormData form = test::GetFormData({.fields = {{.role = ONE_TIME_CODE}}});
+  FormStructure form_structure(form);
+  form_structure.field(0)->SetTypeTo(AutofillType(ONE_TIME_CODE), std::nullopt);
+
+  EXPECT_CALL(otp_manager(), GetOtpSuggestions).Times(0);
+
+  base::MockCallback<
+      base::OnceCallback<void(SuggestionGenerator::ReturnedSuggestions)>>
+      suggestions_generated_callback;
+
+  EXPECT_CALL(
+      suggestions_generated_callback,
+      Run(Pair(SuggestionGenerator::SuggestionDataSource::kOneTimePassword,
+               IsEmpty())));
+
+  generator().GenerateSuggestions(form, form.fields()[0], &form_structure,
+                                  form_structure.field(0), client(),
+                                  suggestions_generated_callback.Get());
+}
+
 }  // namespace autofill
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.