CVE-2026-17851
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
TEST_Fcomponents/autofill/core/browser/filling/autofill_ai/field_filling_entity_util_unittest.cc |
modified |
Files Changed
components/autofill/core/browser/filling/autofill_ai/field_filling_entity_util.cccomponents/autofill/core/browser/filling/autofill_ai/field_filling_entity_util_unittest.cc
Patch
From 752ffe3030573be0033100a04045fdf445e790f8 Mon Sep 17 00:00:00 2001 From: Jihad Hanna <[email protected]> Date: Wed, 03 Jun 2026 00:36:23 -0700 Subject: [PATCH] Skip previewing select elements with obfuscated attributes Fixed: 519243927 Change-Id: I89714ab7e526d984ecebdff482990a7c08cf05ce Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7894642 Auto-Submit: Jihad Hanna <[email protected]> Reviewed-by: Bruno Braga <[email protected]> Commit-Queue: Bruno Braga <[email protected]> Cr-Commit-Position: refs/heads/main@{#1640752} --- diff --git a/components/autofill/core/browser/filling/autofill_ai/field_filling_entity_util.cc b/components/autofill/core/browser/filling/autofill_ai/field_filling_entity_util.cc index 6d2475bb..4e69b685 100644 --- a/components/autofill/core/browser/filling/autofill_ai/field_filling_entity_util.cc +++ b/components/autofill/core/browser/filling/autofill_ai/field_filling_entity_util.cc @@ -286,6 +286,13 @@ return FillingValueAndType(u"", field_type); } + const bool should_obfuscate = + action_persistence != mojom::ActionPersistence::kFill && + attribute->type().is_obfuscated(); + if (should_obfuscate && field.IsSelectElement()) { + return FillingValueAndType(u"", field_type); + } + if (field.IsSelectElement()) { std::optional<SelectOption> select_control_option = GetOptionForSelect(*attribute, field, app_locale, address_normalizer); @@ -298,10 +305,6 @@ } else { std::u16string fill_value = GetValueForInput(*attribute, field, app_locale); - const bool should_obfuscate = - action_persistence != mojom::ActionPersistence::kFill && - attribute->type().is_obfuscated(); - return FillingValueAndType(should_obfuscate ? GetObfuscatedValue(fill_value) : std::move(fill_value), field_type); diff --git a/components/autofill/core/browser/filling/autofill_ai/field_filling_entity_util_unittest.cc b/components/autofill/core/browser/filling/autofill_ai/field_filling_entity_util_unittest.cc index 04665f5..f81b7787 100644 --- a/components/autofill/core/browser/filling/autofill_ai/field_filling_entity_util_unittest.cc +++ b/components/autofill/core/browser/filling/autofill_ai/field_filling_entity_util_unittest.cc @@ -353,6 +353,24 @@ kNumber); } +// Tests that select element are not previewed with obfuscated attributes. +TEST_F(GetFillValueForEntityTest, ObfuscatedSelectElement) { + constexpr char16_t kNumber[] = u"12"; + auto field = std::make_unique<AutofillField>( + test::CreateTestSelectField({"11", "12", "13"})); + field->set_server_predictions({CreatePrediction(PASSPORT_NUMBER)}); + + EntityInstance passport = + test::GetPassportEntityInstance({.number = kNumber}); + + EXPECT_EQ(GetFillValueForEntity(passport, field, + mojom::ActionPersistence::kPreview), + u""); + EXPECT_EQ( + GetFillValueForEntity(passport, field, mojom::ActionPersistence::kFill), + kNumber); +} + // Tests that we can correctly fill structured name information into fields. TEST_F(GetFillValueForEntityTest, FillingStructuredNames) { EntityInstance passport = test::GetPassportEntityInstance();
Regression Test / PoC
diff --git a/components/autofill/core/browser/filling/autofill_ai/field_filling_entity_util_unittest.cc b/components/autofill/core/browser/filling/autofill_ai/field_filling_entity_util_unittest.cc
index 04665f5..f81b7787 100644
--- a/components/autofill/core/browser/filling/autofill_ai/field_filling_entity_util_unittest.cc
+++ b/components/autofill/core/browser/filling/autofill_ai/field_filling_entity_util_unittest.cc
@@ -353,6 +353,24 @@
kNumber);
}
+// Tests that select element are not previewed with obfuscated attributes.
+TEST_F(GetFillValueForEntityTest, ObfuscatedSelectElement) {
+ constexpr char16_t kNumber[] = u"12";
+ auto field = std::make_unique<AutofillField>(
+ test::CreateTestSelectField({"11", "12", "13"}));
+ field->set_server_predictions({CreatePrediction(PASSPORT_NUMBER)});
+
+ EntityInstance passport =
+ test::GetPassportEntityInstance({.number = kNumber});
+
+ EXPECT_EQ(GetFillValueForEntity(passport, field,
+ mojom::ActionPersistence::kPreview),
+ u"");
+ EXPECT_EQ(
+ GetFillValueForEntity(passport, field, mojom::ActionPersistence::kFill),
+ kNumber);
+}
+
// Tests that we can correctly fill structured name information into fields.
TEST_F(GetFillValueForEntityTest, FillingStructuredNames) {
EntityInstance passport = test::GetPassportEntityInstance();
Original Bug Report
Potential side-channel equality oracle on sensitive AutofillAI attributes via select elements
Project Fortify, an experimental security project, has identified the following potential security issue. If you’re a feature owner CC-ed on this bug, please do your best to review these reports. Please see https://chromium.googlesource.com/chromium/src/+/main/docs/security/ai-generated-security-bugs-faq.md for more information.
Overview: The AutofillAI preview path processes select elements without checking if the matched attribute requires obfuscation. A compromised renderer can leverage this by populating a drop-down with candidate options and observing which one is selected when a user hovers over an AutofillAI suggestion. This can potentially leak highly sensitive user attributes, such as passport or national ID numbers, bypassing biometric and device re-authentication.
Affected files:
components/autofill/core/browser/filling/autofill_ai/field_filling_entity_util.cccomponents/autofill/core/browser/filling/field_filling_util.cccomponents/autofill/core/browser/ui/autofill_external_delegate.cccomponents/autofill/core/browser/form_processing/autofill_ai/determine_attribute_types.cccomponents/autofill/core/common/autofill_data_validation.cc
Estimated timestamp from git blame: 2025-03-13
Description
There is a potential information disclosure vulnerability in the AutofillAI filling logic where sensitive attributes can be leaked to a compromised renderer process during form preview (hovering over suggestions).
Normally, when a user previews an AutofillAI suggestion (without clicking/accepting it), sensitive attributes like PASSPORT_NUMBER, DRIVERS_LICENSE_NUMBER, or NATIONAL_ID_CARD_NUMBER are obfuscated (e.g. replaced with masks like •••• ••••). This ensures a compromised renderer process cannot learn the cleartext credentials through the preview IPC mechanism, and must wait for the user to explicitly click/accept the suggestion (which triggers an OS-level biometric or PIN re-authentication challenge).
However, in components/autofill/core/browser/filling/autofill_ai/field_filling_entity_util.cc, the field.IsSelectElement() branch completely bypasses the obfuscation check:
if (field.IsSelectElement()) {
std::optional<SelectOption> select_control_option =
GetOptionForSelect(*attribute, field, app_locale, address_normalizer);
return FillingValueAndType(
select_control_option ? std::move(select_control_option->value) : u"",
select_control_option
? std::optional(std::move(select_control_option->text))
: std::nullopt,
field_type);
} else {
std::u16string fill_value = GetValueForInput(*attribute, field, app_locale);
const bool should_obfuscate =
action_persistence != mojom::ActionPersistence::kFill &&
attribute->type().is_obfuscated();
return FillingValueAndType(should_obfuscate ? GetObfuscatedValue(fill_value)
: std::move(fill_value),
field_type);
}
As seen above, the IsSelectElement() branch does not inspect action_persistence or attribute->type().is_obfuscated(). It invokes GetOptionForSelect() which uses case-insensitive equality matching to search for the cleartext secret among the renderer-supplied option list. If a match is found, the matched option is returned verbatim to the renderer via mojom::AutofillAgent::ApplyFieldsAction(kPreview) during suggestion selection.
Potential Attack Scenario
- A compromised renderer constructs a malicious form with
<select>fields that are crafted to trigger local/server heuristics classifying them asPASSPORT_NUMBER(or other obfuscated AutofillAI types). - The renderer populates these select elements with up to 512 candidate option values (the maximum allowed size per field).
- When the user hovers or arrow-keys over the AutofillAI suggestion, the browser process’s
AutofillExternalDelegate::DidSelectSuggestion()triggersFillOrPreviewFormwithmojom::ActionPersistence::kPreview(no biometric authentication is requested at this point). - The browser process performs the matching logic and returns the matched option to the renderer in the preview IPC (
ApplyFieldsAction(kPreview)). - The compromised renderer reads the filled option value from the preview IPC, learning which candidate matched the secret, effectively forming an equality oracle.
Note: Since our security evaluation tools do not have the capability to execute code dynamically, these steps are based on static code tracing and represent a potential exploit path.
Proposed Fix
Modify GetFillingValueAndTypeForEntity() to ensure that when action_persistence != mojom::ActionPersistence::kFill and the target attribute type is_obfuscated() is true, the select element branch is either disabled or correctly masked (e.g., returning an empty match or rejecting filling of sensitive obfuscated types into select elements during preview).
Evaluated with Chrome root at commit: 87214e6721f6c34afd9181b80769a24c0c601c50
Results so far have been promising, but there can be wrong deductions. Feel free to adjust as follows:
- If you are familiar with the severity guidelines, you may adjust the severity.
- If this is a false positive, and there’s no work to be done, please close as WAI.
- If there is work to do here but not a vulnerability, please change the issue type to Task/Bug/FR.
Data from false positives will be used to improve accuracy over time. And please feel free to reach out to me directly if you have concerns or feedback on the project.