Medium watch CVSS 6.5 chrome Info Disclosure 🔧 Commit mapped

Overview

Medium
Severity
6.5
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactInformation leak in Transactions Platform
DescriptionInformation leak in Transactions Platform
ComponentTransactions Platform
Sub-componentAutofill
Bug ClassInfo Disclosure
Action tierwatch — logic/policy bug — security-relevant, no memory-unsafety
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.
Tracker532962621
Fix commit2b02287549c6 (chromium/src) +101/-5
CWECWE-200 (Information exposure)
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N
CISA KEVNot listed
CreditedGoogle
Reported2026-07-09 (per vendor advisory)
Fix landed2026-08-26 (public git)
Disclosed2026-09-22
Patch gap27 days — fix public in source before the advisory

Background

Autocomplete history
Chrome’s local store of previously typed form-field values that are offered as suggestions on later visits, managed by AutocompleteHistoryManager.
Field rationalization
the Autofill process that assigns a semantic type to each form field, which can legitimately fall back to UNKNOWN_TYPE for some credit-card fields.
`html_type()`
the AutofillField accessor exposing the field’s parsed HTML autocomplete attribute as an HtmlFieldType (e.g. kCreditCardVerificationCode for cc-csc).
Sensitive field types
CVCs, credit-card numbers, IBANs, and promo codes, which must never be persisted to autocomplete history.

Root Cause Analysis

Before the fix, eligibility to persist a field value to autocomplete history was decided solely by IsFieldTypeSaveable, which looked at the field’s predicted (rationalized) type. Because credit-card fields can legitimately rationalize to UNKNOWN_TYPE, a field carrying autocomplete="cc-csc" (a CVC) could slip past the predicted-type check and be treated as saveable. The invariant that sensitive payment data is never written to autocomplete history was therefore violated whenever the predicted type failed to identify the field.

The fix renames the predicted-type check to IsPredictedFieldTypeSaveable and adds a parallel IsHtmlFieldTypeSaveable that rejects fields whose html_type() is kCreditCardVerificationCode, kCreditCardNumber, kIban, or kMerchantPromoCode, regardless of prediction. Both checks now gate persistence in IsValidFieldDataForAutocompleteHistory, so a CVC tagged only by its HTML attribute is caught by the second layer.

Key insight
The single mistake was trusting only the predicted field type to filter out sensitive fields, when that type can legitimately be UNKNOWN_TYPE; the fix adds a second, attribute-based gate (IsHtmlFieldTypeSaveable) so the HTML autocomplete value alone is sufficient to reject a CVC or other sensitive field.

Attack Path

  1. Craft a mislabeled CVC field An attacker page (or a site whose markup confuses the parser) presents an input with autocomplete="cc-csc" but a name that does not match the credit-card regex, so Autofill rationalizes it to UNKNOWN_TYPE.
  2. Bypass the predicted-type filter Because IsFieldTypeSaveable keys off the predicted type, the UNKNOWN_TYPE field passes the saveability check that was meant to exclude CVCs.
  3. CVC persisted to history The user’s entered CVC value is stored as an autocomplete history entry, since no HTML-attribute-based check existed to reject it.
  4. Value re-surfaced later On a subsequent visit, the stored CVC is offered as an autocomplete suggestion, exposing the sensitive value in the field’s local history where it should never appear. (inferred)

Impact Assessment

An attacker gains persistence and later re-surfacing of sensitive payment data (CVC, and by the same gap potentially card numbers, IBANs, or promo codes) in the browser’s local autocomplete history within the renderer/browser Autofill context, requiring the user to type such a value into a field whose predicted type resolves to UNKNOWN_TYPE while carrying a sensitive autocomplete attribute. The advisory classes this as an information leak in the Transactions Platform (LogicError) and states no exploited-in-the-wild status. Any broader exfiltration beyond local history exposure is not demonstrated by the patch. (inferred)

Changed Functions

FunctionChangeNotes
if
components/autofill/core/browser/single_field_fillers/autocomplete/autocomplete_history_manager.cc
modified
TEST_F
components/autofill/core/browser/single_field_fillers/autocomplete/autocomplete_history_manager_unittest.cc
modified

Files Changed

  • components/autofill/core/browser/single_field_fillers/autocomplete/autocomplete_history_manager_unittest.cc
  • components/autofill/core/browser/single_field_fillers/autocomplete/autocomplete_history_manager.cc

Audit Directions

  • Prediction-only sensitivity gates
    Look for any code that decides to store, log, or expose form values based solely on the rationalized/predicted field type, and add a fallback keyed on html_type() for cases that rationalize to UNKNOWN_TYPE.
  • Sensitive-type enumerations
    Audit every place that lists sensitive types (CVC, card number, IBAN, promo code) to ensure the HTML-attribute and predicted-type variants are kept in sync as new HtmlFieldType values are added.
  • Other single-field fillers
    Review sibling fillers under components/autofill/core/browser/single_field_fillers/ (e.g. IBAN and promo-code managers) for the same predicted-vs-HTML-type discrepancy in their persistence checks.
From 2b02287549c6fe7ec4e00ba1f4fa31487017c98c Mon Sep 17 00:00:00 2001
From: Grzegorz (Greg) Grzelachowski <ggrzelachowski@google.com>
Date: Wed, 26 Aug 2026 06:57:08 -0700
Subject: [PATCH] [Autofill] Disable autocomplete based on `autocomplete` attribute (e.g. CVC)

There are valid code paths that might result in Credit Card fields being
rationalized to `UNKNOWN_TYPE`. This has negative effect on the
autocomplete feature, where fields marked as `cc-csc` could be persisted.

Bug: 532962621
Change-Id: Ia90d63201583f7bf28e72264e90eb3906a6a6964
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8239572
Reviewed-by: Gianmarco Picarella <picarella@google.com>
Commit-Queue: Grzegorz (Greg) Grzelachowski <ggrzelachowski@google.com>
Reviewed-by: Jihad Hanna <jihadghanna@google.com>
Cr-Commit-Position: refs/heads/main@{#1686352}
---
diff --git a/components/autofill/core/browser/single_field_fillers/autocomplete/autocomplete_history_manager.cc b/components/autofill/core/browser/single_field_fillers/autocomplete/autocomplete_history_manager.cc
index 9fabb60..b3ad834 100644
--- a/components/autofill/core/browser/single_field_fillers/autocomplete/autocomplete_history_manager.cc
+++ b/components/autofill/core/browser/single_field_fillers/autocomplete/autocomplete_history_manager.cc
@@ -55,8 +55,7 @@
 namespace {
 // Returns true if the field type is eligible to be saved in the autocomplete
 // history. Some types (promo codes, IBANs, CCs, CVCs) are excluded.
-bool IsFieldTypeSaveable(const FormStructure* form, FieldGlobalId field_id) {
-  const AutofillField* field = form ? form->GetFieldById(field_id) : nullptr;
+bool IsPredictedFieldTypeSaveable(const AutofillField* field) {
   if (!field) {
     return true;
   }
@@ -204,6 +203,69 @@
   return true;
 }
 
+// An equivalent of `IsPredictedFieldTypeSaveable` that operates on the values
+// of the HTML autocomplete attribute. It serves as an additional validation
+// e.g. for cases when predicted type is `UNKNOWN_TYPE`.
+bool IsHtmlFieldTypeSaveable(const AutofillField* field) {
+  if (!field) {
+    return true;
+  }
+  switch (field->html_type()) {
+    case HtmlFieldType::kCreditCardVerificationCode:
+    case HtmlFieldType::kCreditCardNumber:
+    case HtmlFieldType::kIban:
+    case HtmlFieldType::kMerchantPromoCode:
+      return false;
+    case HtmlFieldType::kUnspecified:
+    case HtmlFieldType::kName:
+    case HtmlFieldType::kHonorificPrefix:
+    case HtmlFieldType::kGivenName:
+    case HtmlFieldType::kAdditionalName:
+    case HtmlFieldType::kFamilyName:
+    case HtmlFieldType::kOrganization:
+    case HtmlFieldType::kStreetAddress:
+    case HtmlFieldType::kAddressLine1:
+    case HtmlFieldType::kAddressLine2:
+    case HtmlFieldType::kAddressLine3:
+    case HtmlFieldType::kAddressLevel1:
+    case HtmlFieldType::kAddressLevel2:
+    case HtmlFieldType::kAddressLevel3:
+    case HtmlFieldType::kCountryCode:
+    case HtmlFieldType::kCountryName:
+    case HtmlFieldType::kPostalCode:
+    case HtmlFieldType::kCreditCardNameFull:
+    case HtmlFieldType::kCreditCardNameFirst:
+    case HtmlFieldType::kCreditCardNameLast:
+    case HtmlFieldType::kCreditCardExp:
+    case HtmlFieldType::kCreditCardExpMonth:
+    case HtmlFieldType::kCreditCardExpYear:
+    case HtmlFieldType::kCreditCardType:
+    case HtmlFieldType::kTel:
+    case HtmlFieldType::kTelCountryCode:
+    case HtmlFieldType::kTelNational:
+    case HtmlFieldType::kTelAreaCode:
+    case HtmlFieldType::kTelLocal:
+    case HtmlFieldType::kTelLocalPrefix:
+    case HtmlFieldType::kTelLocalSuffix:
+    case HtmlFieldType::kTelExtension:
+    case HtmlFieldType::kEmail:
+    case HtmlFieldType::kBirthdateDay:
+    case HtmlFieldType::kBirthdateMonth:
+    case HtmlFieldType::kBirthdateYear:
+    case HtmlFieldType::kTransactionAmount:
+    case HtmlFieldType::kTransactionCurrency:
+    case HtmlFieldType::kAdditionalNameInitial:
+    case HtmlFieldType::kCreditCardExpDate2DigitYear:
+    case HtmlFieldType::kCreditCardExpDate4DigitYear:
+    case HtmlFieldType::kCreditCardExp2DigitYear:
+    case HtmlFieldType::kCreditCardExp4DigitYear:
+    case HtmlFieldType::kOneTimeCode:
+    case HtmlFieldType::kUnrecognized:
+      return true;
+  }
+  NOTREACHED();
+}
+
 // Returns true if the given `field` in `form` and its value are valid to be
 // saved as a new or updated Autocomplete entry.
 // We put the following restriction on stored FormFields:
@@ -247,14 +309,20 @@
     return false;
   }
 
+  const AutofillField* autofill_field =
+      form ? form->GetFieldById(field.global_id()) : nullptr;
+
   // Reject fields with types that are ineligible for autocomplete such as
   // credit card numbers, CVCs, IBANs, or promo codes.
-  if (!IsFieldTypeSaveable(form, field.global_id())) {
+  if (!IsPredictedFieldTypeSaveable(autofill_field)) {
     return false;
   }
 
-  const AutofillField* autofill_field =
-      form ? form->GetFieldById(field.global_id()) : nullptr;
+  // Reject fields with HTML types that are ineligible for autocomplete.
+  if (!IsHtmlFieldTypeSaveable(autofill_field)) {
+    return false;
+  }
+
   if (autofill_field &&
       autofill_field->all_modifiers().contains(FieldModifier::kAutofill) &&
       (autofill_field->last_modifier() != FieldModifier::kUser ||
diff --git a/components/autofill/core/browser/single_field_fillers/autocomplete/autocomplete_history_manager_unittest.cc b/components/autofill/core/browser/single_field_fillers/autocomplete/autocomplete_history_manager_unittest.cc
index 460ab33..cdaa76a0 100644
--- a/components/autofill/core/browser/single_field_fillers/autocomplete/autocomplete_history_manager_unittest.cc
+++ b/components/autofill/core/browser/single_field_fillers/autocomplete/autocomplete_history_manager_unittest.cc
@@ -34,6 +34,7 @@
 #include "components/autofill/core/common/autofill_prefs.h"
 #include "components/autofill/core/common/autofill_test_utils.h"
 #include "components/autofill/core/common/form_data.h"
+#include "components/autofill/core/common/html_field_types.h"
 #include "components/optimization_guide/core/feature_registry/feature_registration.h"
 #include "components/optimization_guide/core/model_execution/model_execution_prefs.h"
 #include "components/personal_context/core/mock_personal_context_eligibility_service.h"
@@ -1053,6 +1054,33 @@
                                                     &form_structure);
 }
 
+// Tests that CVC fields tagged through autocomplete attribute are not saved in
+// history even when the type wasn't predicted.
+TEST_F(AutocompleteHistoryManagerTest,
+       AutocompleteAttributeBasedFiltering_CvcWithoutTypePrediction) {
+  FormData form =
+      test::GetFormData({.fields = {{.role = CREDIT_CARD_VERIFICATION_CODE,
+                                     .name = u"Name not matching CC regex",
+                                     .value = u"000",
+                                     .autocomplete_attribute = "cc-csc"},
+                                    {.role = CREDIT_CARD_VERIFICATION_CODE,
+                                     .name = u"Name not matching CC regex",
+                                     .value = u"111"}}});
+  FormStructure form_structure{form};
+  // Simulate rationalizing the types to UNKNOWN_TYPE.
+  form_structure.field(0)->SetTypeTo(
+      AutofillType(UNKNOWN_TYPE), AutofillPredictionSource::kRationalization);
+  form_structure.field(1)->SetTypeTo(
+      AutofillType(UNKNOWN_TYPE), AutofillPredictionSource::kRationalization);
+
+  EXPECT_CALL(*(web_data_service_.get()),
+              AddFormFields(testing::ElementsAre(
+                  testing::Property(&FormFieldData::value, u"111"))));
+
+  autocomplete_manager_->OnWillSubmitFormWithFields(form.fields(),
+                                                    &form_structure);
+}
+
 // Tests that loyalty card fields are saved in autocomplete history if they
 // were entered manually (i.e., not autofilled).
 TEST_F(AutocompleteHistoryManagerTest, LoyaltyCardManualEntryIsSaved) {
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/components/autofill/core/browser/single_field_fillers/autocomplete/autocomplete_history_manager_unittest.cc b/components/autofill/core/browser/single_field_fillers/autocomplete/autocomplete_history_manager_unittest.cc
index 460ab33..cdaa76a0 100644
--- a/components/autofill/core/browser/single_field_fillers/autocomplete/autocomplete_history_manager_unittest.cc
+++ b/components/autofill/core/browser/single_field_fillers/autocomplete/autocomplete_history_manager_unittest.cc
@@ -34,6 +34,7 @@
 #include "components/autofill/core/common/autofill_prefs.h"
 #include "components/autofill/core/common/autofill_test_utils.h"
 #include "components/autofill/core/common/form_data.h"
+#include "components/autofill/core/common/html_field_types.h"
 #include "components/optimization_guide/core/feature_registry/feature_registration.h"
 #include "components/optimization_guide/core/model_execution/model_execution_prefs.h"
 #include "components/personal_context/core/mock_personal_context_eligibility_service.h"
@@ -1053,6 +1054,33 @@
                                                     &form_structure);
 }
 
+// Tests that CVC fields tagged through autocomplete attribute are not saved in
+// history even when the type wasn't predicted.
+TEST_F(AutocompleteHistoryManagerTest,
+       AutocompleteAttributeBasedFiltering_CvcWithoutTypePrediction) {
+  FormData form =
+      test::GetFormData({.fields = {{.role = CREDIT_CARD_VERIFICATION_CODE,
+                                     .name = u"Name not matching CC regex",
+                                     .value = u"000",
+                                     .autocomplete_attribute = "cc-csc"},
+                                    {.role = CREDIT_CARD_VERIFICATION_CODE,
+                                     .name = u"Name not matching CC regex",
+                                     .value = u"111"}}});
+  FormStructure form_structure{form};
+  // Simulate rationalizing the types to UNKNOWN_TYPE.
+  form_structure.field(0)->SetTypeTo(
+      AutofillType(UNKNOWN_TYPE), AutofillPredictionSource::kRationalization);
+  form_structure.field(1)->SetTypeTo(
+      AutofillType(UNKNOWN_TYPE), AutofillPredictionSource::kRationalization);
+
+  EXPECT_CALL(*(web_data_service_.get()),
+              AddFormFields(testing::ElementsAre(
+                  testing::Property(&FormFieldData::value, u"111"))));
+
+  autocomplete_manager_->OnWillSubmitFormWithFields(form.fields(),
+                                                    &form_structure);
+}
+
 // Tests that loyalty card fields are saved in autocomplete history if they
 // were entered manually (i.e., not autofilled).
 TEST_F(AutocompleteHistoryManagerTest, LoyaltyCardManualEntryIsSaved) {
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.