Overview

High
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactInappropriate implementation in Autofill
DescriptionInappropriate implementation in Autofill
ComponentAutofill
Bug ClassLogic Error
Tracker516734537
Fix commit6e1a3c5dbaa5 (chromium/src) +9/-6
CISA KEVNot listed
CreditedGoogle
Disclosed2026-06-23

Files Changed

  • components/autofill/core/browser/foundations/browser_autofill_manager.cc
From 6e1a3c5dbaa5c8bc19a9d0ff07e7d416a70d7441 Mon Sep 17 00:00:00 2001
From: Przemek Perkowski <perkowski@google.com>
Date: Wed, 03 Jun 2026 05:11:24 -0700
Subject: [PATCH] Fix the state desynchronization bug in autofill manager.

As explained in the attached bug, the current implementation leads to
the popup not being hidden correctly.

Bug: 516734537
Change-Id: If0370f3370240ef3904cbf7fbdc868766a6a6964
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7894738
Reviewed-by: Christoph Schwering <schwering@google.com>
Reviewed-by: Atalyk Akash <atalyk@google.com>
Commit-Queue: Przemek Perkowski <perkowski@google.com>
Cr-Commit-Position: refs/heads/main@{#1640851}
---

diff --git a/components/autofill/core/browser/foundations/browser_autofill_manager.cc b/components/autofill/core/browser/foundations/browser_autofill_manager.cc
index 5ac3ba3d..76b064c 100644
--- a/components/autofill/core/browser/foundations/browser_autofill_manager.cc
+++ b/components/autofill/core/browser/foundations/browser_autofill_manager.cc
@@ -1188,17 +1188,20 @@
     return;
   }
 
+  // TODO(crbug.com/519061643): Rely on central atMemory eligibility logic
+  // instead.
+  if (IsAtMemoryTriggerSource(trigger_source) &&
+      client().GetPersonalContextEnablementState() ==
+          personal_context::PersonalContextEnablementState::
+              kDisabledNotEligible) {
+    return;
+  }
+
   const FormFieldData& field = CHECK_DEREF(form.FindFieldByGlobalId(field_id));
   external_delegate_->OnQuery(form, field, caret_bounds, trigger_source,
                               /*update_datalist=*/true);
 
   if (IsAtMemoryTriggerSource(trigger_source)) {
-    // Do not show the pop up at all for non eligible profiles.
-    if (client().GetPersonalContextEnablementState() ==
-        personal_context::PersonalContextEnablementState::
-            kDisabledNotEligible) {
-      return;
-    }
     std::vector<Suggestion> suggestions;
     GetAtMemoryManager().MaybeAppendPersonalContextNotice(suggestions);
 
Loading diff…

Original Bug Report

reported by vm...@google.com

Autofill Origin Bypass via State Desynchronization in BrowserAutofillManager

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 potential state desynchronization vulnerability in BrowserAutofillManager allows a compromised renderer in a cross-origin frame to overwrite active query state while an Autofill popup remains visible. Due to an early-return path that fails to hide the popup or restore state, a subsequent user acceptance can redirect sensitive credit card or address data to the attacker’s origin.

Affected files:

  • components/autofill/core/browser/foundations/browser_autofill_manager.cc
  • components/autofill/core/browser/ui/autofill_external_delegate.cc

Estimated timestamp from git blame: 2026-04-28

Root Cause Analysis

In BrowserAutofillManager::OnAskForValuesToFillImpl (located in components/autofill/core/browser/foundations/browser_autofill_manager.cc), the method updates the active query state on the external delegate before evaluating the eligibility gate for memory-related trigger sources:

const FormFieldData& field = CHECK_DEREF(form.FindFieldByGlobalId(field_id));
external_delegate_->OnQuery(form, field, caret_bounds, trigger_source,
                            /*update_datalist=*/true);

if (IsAtMemoryTriggerSource(trigger_source)) {
  // Do not show the pop up at all for non eligible profiles.
  if (client().GetPersonalContextEnablementState() ==
      personal_context::PersonalContextEnablementState::
          kDisabledNotEligible) {
    return; // Early return leaves popup visible and query_field_ mutated
  }
  external_delegate_->OnSuggestionsReturned(field_id, {});
  return;
}

When client().GetPersonalContextEnablementState() == kDisabledNotEligible (which is the default in stock Chrome, as the kPersonalContext feature is disabled by default), the code performs an early return without closing any currently visible popup or restoring the previously active query_field_ state.


Potential Exploitation Mechanism

A compromised renderer could potentially exploit this behavior via the following sequence of events:

  1. Popup Initiation: A user clicks on an autofill-eligible field in a legitimate payment frame (Frame M on Origin M), causing the mainframe manager’s AutofillExternalDelegate to display a credit card autofill popup.
  2. State Overwrite: A compromised renderer inside a subframe (Frame A on Origin A) directly calls the Mojo interface AskForValuesToFill with trigger_source = AutofillSuggestionTriggerSource::kAtMemory and field_id = field_A_id.
  3. Bypassing Renderer-to-Browser Checks: The trigger source kAtMemory successfully passes browser-side validation in bad_message::CheckSingleValidTriggerSource (defined in components/autofill/content/browser/bad_message.cc), as the validation only blocks kPlusAddressUpdatedInBrowserProcess.
  4. Desynchronization Trigger: Because both frames are inside the same FormForest, the router routes the request to the mainframe’s BrowserAutofillManager. This manager updates its shared AutofillExternalDelegate’s state variables (query_form_ and query_field_) to point to the attacker’s Frame A.
  5. Popup Remains Visible: The manager evaluates IsAtMemoryTriggerSource and hits the kDisabledNotEligible early return. Because it returns immediately, suggestions are never generated, and AutofillSuggestionController::GetOrCreate is never invoked for the second request. Consequently, the original popup (showing suggestions for Frame M) remains open and active.
  6. Data Exfiltration: The user clicks on a suggestion in the still-visible popup. The delegate processes the acceptance via AutofillExternalDelegate::DidAcceptSuggestion, which resolves the cached form using the mutated query_form_ and query_field_. In FormForest::IsSafeToFill, the security check compares the destination fields (Origin A) to the triggered_origin (mutated to Origin A) and permits cross-frame autofill, sending the sensitive data directly to the compromised renderer.

Suggested Remediation

To prevent this state desynchronization, the early-return path should explicitly dismiss any active popups and reset the query state.

We recommend moving the eligibility gate check before modifying the delegate state, or ensuring that any early return explicitly closes the popup:

if (IsAtMemoryTriggerSource(trigger_source)) {
  if (client().GetPersonalContextEnablementState() ==
      personal_context::PersonalContextEnablementState::
          kDisabledNotEligible) {
    client().HideAutofillSuggestions(SuggestionHidingReason::kUserGesture);
    return;
  }
}

const FormFieldData& field = CHECK_DEREF(form.FindFieldByGlobalId(field_id));
external_delegate_->OnQuery(form, field, caret_bounds, trigger_source,
                            /*update_datalist=*/true);

Evaluated with Chrome root at commit: a2bea94528f4bd6cc57739c43fa3bb890b8367d3


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