Overview

High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactUse after free in Transactions Platform
DescriptionUse after free in Transactions Platform
ComponentTransactions Platform
Sub-componentAutofill
Bug ClassUAF
Tracker553117374
Fix commit43939844e1bb (chromium/src) +61/-5
CISA KEVNot listed
CreditedGoogle
Disclosed2026-10-20

Files Changed

  • testing/variations/fieldtrial_testing_config.json
  • components/autofill/core/common/autofill_features.cc
  • chrome/browser/ui/autofill/autofill_popup_controller_impl.cc
  • tools/metrics/histograms/metadata/autofill/histograms.xml
  • chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl.cc
  • components/autofill/core/common/autofill_features.h
  • chrome/browser/autofill/autofill_captured_sites_interactive_uitest.cc
From 43939844e1bb97e0a7101e675f47741263a8a80d Mon Sep 17 00:00:00 2001
From: Christoph Schwering <[email protected]>
Date: Wed, 16 Sep 2026 05:41:45 -0700
Subject: [PATCH] [Autofill] Require focus in the suggestions' anchor frame

This CL requires that the anchor frame has the focus before Autofill
shows suggestions. This unfocused renderers from displaying
suggestions. That could otherwise happen due to race conditions
(e.g., because AskForValuesToFill() is delayed or because of
asynchronous parsing or suggestion generation) or because of a
malicious renderer.

The change is behind a Finch experiment.

Bug: 536607604, 553117374
Change-Id: Ibcc6821f5b3e06119e813ee9d9f9ee9e22463055
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8413948
Reviewed-by: Jan Keitel <[email protected]>
Commit-Queue: Christoph Schwering <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1698861}
---
diff --git a/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl.cc b/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl.cc
index 6412bd9..3d41357c 100644
--- a/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl.cc
+++ b/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl.cc
@@ -731,6 +731,14 @@
     Hide(SuggestionHidingReason::kNoFrameHasFocus);
     return;
   }
+  if (rfh != web_contents_->GetFocusedFrame() &&
+      base::FeatureList::IsEnabled(
+          features::kAutofillRequireFocusInFrameForSuggestions)) {
+    base::UmaHistogramEnumeration("Autofill.SuggestionSuppressionDueToNoFocus",
+                                  trigger_source);
+    Hide(SuggestionHidingReason::kNoFrameHasFocus);
+    return;
+  }
 
   if (IsPointerLocked(web_contents_.get())) {
     Hide(SuggestionHidingReason::kMouseLocked);
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc b/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc
index 00ca37b..98d1afe 100644
--- a/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc
+++ b/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc
@@ -336,6 +336,14 @@
     Hide(SuggestionHidingReason::kNoFrameHasFocus);
     return;
   }
+  if (rfh != web_contents_->GetFocusedFrame() && !should_ignore_focus_loss &&
+      base::FeatureList::IsEnabled(
+          features::kAutofillRequireFocusInFrameForSuggestions)) {
+    base::UmaHistogramEnumeration("Autofill.SuggestionSuppressionDueToNoFocus",
+                                  trigger_source);
+    Hide(SuggestionHidingReason::kNoFrameHasFocus);
+    return;
+  }
 
   if (IsPointerLocked(web_contents_.get())) {
     Hide(SuggestionHidingReason::kMouseLocked);
diff --git a/components/autofill/core/common/autofill_features.cc b/components/autofill/core/common/autofill_features.cc
index 479dfd28..d1f8370 100644
--- a/components/autofill/core/common/autofill_features.cc
+++ b/components/autofill/core/common/autofill_features.cc
@@ -996,6 +996,13 @@
 BASE_FEATURE(kAutofillReplaceFormElementObserver,
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+// If enabled, AutofillPopupControllerImpl and
+// AutofillKeyboardAccessoryControllerImpl require that the frame to which the
+// suggestions are anchored has focus.
+// TODO(crbug.com/536607604): Clean up when launched.
+BASE_FEATURE(kAutofillRequireFocusInFrameForSuggestions,
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 // Restricts OTP fields detection and fetching to forms that are in a frame
 // with the same TLD+1 as the main frame.
 BASE_FEATURE(kAutofillRestrictOtpToSameTldPlusOne,
diff --git a/components/autofill/core/common/autofill_features.h b/components/autofill/core/common/autofill_features.h
index 32c1c99..d528f189 100644
--- a/components/autofill/core/common/autofill_features.h
+++ b/components/autofill/core/common/autofill_features.h
@@ -372,6 +372,8 @@
 COMPONENT_EXPORT(AUTOFILL)
 BASE_DECLARE_FEATURE(kAutofillReplaceFormElementObserver);
 COMPONENT_EXPORT(AUTOFILL)
+BASE_DECLARE_FEATURE(kAutofillRequireFocusInFrameForSuggestions);
+COMPONENT_EXPORT(AUTOFILL)
 BASE_DECLARE_FEATURE(kAutofillRestrictOtpToSameTldPlusOne);
 COMPONENT_EXPORT(AUTOFILL)
 BASE_DECLARE_FEATURE(kAutofillServerExperimentalSignatures);
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 80d5125..d91e892a 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -2677,6 +2677,25 @@
             ]
         }
     ],
+    "AutofillRequireFocusInFrameForSuggestions": [
+        {
+            "platforms": [
+                "android",
+                "chromeos",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "AutofillRequireFocusInFrameForSuggestions"
+                    ]
+                }
+            ]
+        }
+    ],
     "AutofillRestrictOtpToSameTldPlusOne": [
         {
             "platforms": [
diff --git a/tools/metrics/histograms/metadata/autofill/histograms.xml b/tools/metrics/histograms/metadata/autofill/histograms.xml
index bc002858..d2324b84 100644
--- a/tools/metrics/histograms/metadata/autofill/histograms.xml
+++ b/tools/metrics/histograms/metadata/autofill/histograms.xml
@@ -9635,6 +9635,16 @@
   </summary>
 </histogram>
 
+<histogram name="Autofill.SuggestionSuppressionDueToNoFocus"
+    enum="AutofillSuggestionTriggerSource" expires_after="2027-03-01">
+  <owner>[email protected]</owner>
+  <owner>[email protected]</owner>
+  <summary>
+    Records the trigger source when Autofill suggestions are suppressed because
+    the suggestions' anchor frame does not have focus.
+  </summary>
+</histogram>
+
 <histogram name="Autofill.TestAddressesEvent"
     enum="AutofillInDevtoolsTestAddressesEvents" expires_after="2027-03-07">
   <owner>[email protected]</owner>
diff --git a/chrome/browser/autofill/autofill_captured_sites_interactive_uitest.cc b/chrome/browser/autofill/autofill_captured_sites_interactive_uitest.cc
index 2246855c..f8d16dc 100644
--- a/chrome/browser/autofill/autofill_captured_sites_interactive_uitest.cc
+++ b/chrome/browser/autofill/autofill_captured_sites_interactive_uitest.cc
@@ -408,15 +408,17 @@
     // elements in a form to determine if the form is ready for interaction.
     feature_list_.InitWithFeaturesAndParameters(
         /*enabled_features=*/
-        {{features::debug::kAutofillServerCommunication, {}},
+        {{features::kAutofillRequireFocusInFrameForSuggestions, {}},
+         {features::debug::kAutofillCapturedSiteTestsUseAutofillFlow, {}},
+         {features::debug::kAutofillServerCommunication, {}},
          {features::debug::kAutofillShowTypePredictions,
           {
-              // TODO(crbug.com/410879924): Investigate why the test fails when
-              // kAutofillShowTypePredictions is enabled without parameters.
+              // TODO(crbug.com/410879924): Investigate why the test fails
+              // when kAutofillShowTypePredictions is enabled without
+              // parameters.
               {features::debug::kAutofillShowTypePredictionsAsTitleParam.name,
                "true"},
-          }},
-         {features::debug::kAutofillCapturedSiteTestsUseAutofillFlow, {}}},
+          }}},
         /*disabled_features=*/{});
     command_line->AppendSwitchASCII(
         variations::switches::kVariationsOverrideCountry, "us");
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/chrome/browser/autofill/autofill_captured_sites_interactive_uitest.cc b/chrome/browser/autofill/autofill_captured_sites_interactive_uitest.cc
index 2246855c..f8d16dc 100644
--- a/chrome/browser/autofill/autofill_captured_sites_interactive_uitest.cc
+++ b/chrome/browser/autofill/autofill_captured_sites_interactive_uitest.cc
@@ -408,15 +408,17 @@
     // elements in a form to determine if the form is ready for interaction.
     feature_list_.InitWithFeaturesAndParameters(
         /*enabled_features=*/
-        {{features::debug::kAutofillServerCommunication, {}},
+        {{features::kAutofillRequireFocusInFrameForSuggestions, {}},
+         {features::debug::kAutofillCapturedSiteTestsUseAutofillFlow, {}},
+         {features::debug::kAutofillServerCommunication, {}},
          {features::debug::kAutofillShowTypePredictions,
           {
-              // TODO(crbug.com/410879924): Investigate why the test fails when
-              // kAutofillShowTypePredictions is enabled without parameters.
+              // TODO(crbug.com/410879924): Investigate why the test fails
+              // when kAutofillShowTypePredictions is enabled without
+              // parameters.
               {features::debug::kAutofillShowTypePredictionsAsTitleParam.name,
                "true"},
-          }},
-         {features::debug::kAutofillCapturedSiteTestsUseAutofillFlow, {}}},
+          }}},
         /*disabled_features=*/{});
     command_line->AppendSwitchASCII(
         variations::switches::kVariationsOverrideCountry, "us");
Loading diff…

Original Bug Report

reported by [email protected]

Autofill Popup Recycling Hijack Leading to Cross-Origin Payment Data Exfiltration

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: A compromised root frame renderer can potentially hijack an active Autofill credit card suggestion popup opened for an embedded cross-origin payment iframe. Due to missing frame token and field bounds validation during popup recycling in AutofillPopupControllerImpl::MayRecycle and unconstrained root-frame field bounds in ContentAutofillDriver::Lift, the popup can be silently retargeted to an attacker-controlled field at the same screen coordinates. When the victim accepts the suggestion, sensitive payment information is filled directly into the attacker’s origin.

Affected files:

  • chrome/browser/ui/autofill/autofill_popup_controller_impl.cc
  • components/autofill/content/browser/content_autofill_driver.cc
  • chrome/browser/ui/autofill/chrome_autofill_client.cc
  • chrome/browser/ui/autofill/autofill_suggestion_controller.cc
  • components/autofill/core/browser/ui/autofill_external_delegate.cc
  • components/autofill/core/browser/foundations/autofill_driver_router.cc

Estimated timestamp from git blame: 2026-06-09

Summary

A security weakness in Chromium’s Autofill subsystem allows a compromised root frame renderer to deterministically retarget an active credit card Autofill popup originally opened for an embedded cross-origin payment iframe (PSP). When the user clicks the suggestion to fill payment details, the sensitive data (full PAN, expiry, cardholder name, and CVC) is delivered to the attacker’s origin rather than the intended payment iframe.

Root Cause Analysis

The issue arises from the combination of three mechanisms in the browser-side Autofill architecture:

  1. Unvalidated Root-Frame Field Bounds (content_autofill_driver.cc:89-95): When ContentAutofillDriver::Lift converts renderer-provided FormFieldData::bounds to root coordinates, TransformPointToRootCoordSpaceF acts as an identity function for the root frame. A compromised root renderer can supply arbitrary bounds for its own fields that overlap an embedded subframe’s screen rect.

  2. FormForest Shared Delegate Routing (autofill_driver_router.cc:343-372): When a cross-origin payment iframe is enclosed inside a top-level <form>, FormForest flattens the frame hierarchy and identifies the top-level frame as browser_form.host_frame(). Consequently, autofill queries from both the subframe and the root frame are dispatched to the root frame’s BrowserAutofillManager and share the same AutofillExternalDelegate instance.

  3. Popup Recycling Without Origin/Field Validation (autofill_popup_controller_impl.cc:259-277): AutofillPopupControllerImpl::MayRecycle checks only that delegate_.get() == delegate.get(), container_view() == web_contents->GetNativeView(), and GetSuggestionTriggerSource() == trigger_source. Because both the legitimate query and the subsequent attacker query route to the same delegate, MayRecycle returns true. Recycle() silently replaces controller_common_ with the attacker field’s token and claimed bounds, and Show() reuses the active view via OnSuggestionsChanged(), updating internal last_query_ state to the attacker’s field.

  4. Same-Origin Sensitive Field Fill Safety (autofill_driver_router.cc:87-124): When the user clicks the suggestion, AutofillExternalDelegate::DidAcceptSuggestion calls payments::FillOrPreviewCard with last_query_.field_id (the attacker’s field). In AutofillDriverRouter::IsSafeToFill, field.origin() == trigger_origin evaluates to true because both target and trigger belong to the attacker origin. As a result, sensitive credit card values are dispatched directly to the attacker’s renderer process.

Suggested / Potential Reproduction Steps

(Note: These are potential steps deduced from code analysis; our analysis tooling has not executed this exploit dynamically.)

  1. From a compromised root renderer (https://attacker.com), embed a cross-origin payment form (https://payment-provider.com) inside a top-level <form> tag, and include hidden credit card inputs (<input autocomplete="cc-number">, etc.).
  2. User clicks the credit card input inside the payment iframe, triggering mojom::AutofillDriver::AskForValuesToFill and opening popup P1 showing saved cards over the iframe.
  3. While P1 is visible, the attacker renderer sends a forged mojom::AutofillDriver::AskForValuesToFill for its own field A_cc_field, setting bounds to the on-screen rect of the payment iframe field.
  4. BrowserAutofillManager generates identical saved-card suggestions, MayRecycle evaluates to true, and AutofillPopupControllerImpl updates in place without closing the view.
  5. The user clicks a card suggestion row believing it targets the payment iframe.
  6. Browser fills the credit card PAN, expiration date, and name into A_cc_field and sends the data via Mojo to the attacker renderer.

Suggested Fix

  1. Strengthen MayRecycle Conditions: In AutofillPopupControllerImpl::MayRecycle, enforce that the frame token and triggering field ID match the existing controller’s target before permitting in-place recycling, or dismiss the popup if the triggering frame origin changes.
  2. Validate Element Bounds Against Frame Geometry: In ContentAutofillDriver::Lift and associated validation layers, verify that a field’s claimed bounds lie strictly within the visible layout rect of the source frame and do not overlap unrelated or cross-origin subframes without authorization.

Evaluated with Chrome root at commit: c6718ebbf2c677c6f63691e28c7801c563f6b19c


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.

View on issue tracker