Overview

Low
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactInsufficient data validation in Autofill
DescriptionInsufficient data validation in Autofill
ComponentAutofill
Bug ClassLogic Error
Tracker500262869
Fix commit6839541cdd55 (chromium/src) +18/-11
CISA KEVNot listed
CreditedGoogle
Disclosed2026-06-02

Changed Functions

FunctionChangeNotes
BindRepeating
components/autofill/content/browser/email_verifier_delegate.cc
modified
if
components/autofill/content/browser/email_verifier_delegate.cc
modified
EmailVerifierDelegate
components/autofill/content/browser/email_verifier_delegate.h
modified

Files Changed

  • components/autofill/content/browser/email_verifier_delegate.cc
  • components/autofill/content/browser/email_verifier_delegate.h
  • components/autofill/content/browser/email_verifier_delegate_unittest.cc
From 6839541cdd55f102e18d81f73f23d0aefbc6db57 Mon Sep 17 00:00:00 2001
From: Christoph Schwering <schwering@google.com>
Date: Tue, 28 Apr 2026 02:50:14 -0700
Subject: [PATCH] [Autofill] Retrieve EmailVerifierDelegate for field's frame

This CL retrieves the content::webid::EmailVerifier for the
email field's frame rather than the form's frame.

The form's frame and the field's frame are not necessarily identical
due to frame-transcending forms.

Bug: 500262869
Change-Id: Ib52bf819181db9f409f7b523568e46353f266beb
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7735890
Reviewed-by: Dominic Battré <battre@chromium.org>
Reviewed-by: Sam Goto <goto@chromium.org>
Commit-Queue: Christoph Schwering <schwering@google.com>
Cr-Commit-Position: refs/heads/main@{#1621631}
---

diff --git a/components/autofill/content/browser/email_verifier_delegate.cc b/components/autofill/content/browser/email_verifier_delegate.cc
index 001b0e3..75997ee9 100644
--- a/components/autofill/content/browser/email_verifier_delegate.cc
+++ b/components/autofill/content/browser/email_verifier_delegate.cc
@@ -8,6 +8,7 @@
 #include "base/functional/bind.h"
 #include "base/strings/utf_string_conversions.h"
 #include "components/autofill/content/browser/content_autofill_driver.h"
+#include "components/autofill/content/browser/renderer_forms_from_browser_form.h"
 #include "components/autofill/core/browser/autofill_field.h"
 #include "components/autofill/core/browser/data_model/addresses/autofill_profile.h"
 #include "components/autofill/core/browser/form_structure.h"
@@ -22,11 +23,13 @@
 EmailVerifierDelegate::EmailVerifierDelegate(AutofillClient* client)
     : EmailVerifierDelegate(
           client,
-          base::BindRepeating([](AutofillManager& manager) {
-            ContentAutofillDriver& content_driver =
-                static_cast<ContentAutofillDriver&>(manager.driver());
-            content::RenderFrameHost* rfh = content_driver.render_frame_host();
-            return content::webid::EmailVerifier::GetOrCreateForFrame(rfh);
+          base::BindRepeating([](AutofillClient& client,
+                                 const LocalFrameToken& frame_token) {
+            content::RenderFrameHost* rfh = FindRenderFrameHostByToken(
+                *static_cast<ContentAutofillClient&>(client).web_contents(),
+                frame_token);
+            return rfh ? content::webid::EmailVerifier::GetOrCreateForFrame(rfh)
+                       : nullptr;
           })) {}
 
 EmailVerifierDelegate::EmailVerifierDelegate(AutofillClient* client,
@@ -82,7 +85,10 @@
   std::u16string email = (*profile)->GetRawInfo(EMAIL_ADDRESS);
 
   content::webid::EmailVerifier* verifier =
-      email_verifier_builder_.Run(manager);
+      email_verifier_builder_.Run(manager.client(), email_field.host_frame());
+  if (!verifier) {
+    return;
+  }
   verifier->Verify(
       base::UTF16ToUTF8(email), base::UTF16ToUTF8(email_field.nonce()),
       base::BindOnce(
diff --git a/components/autofill/content/browser/email_verifier_delegate.h b/components/autofill/content/browser/email_verifier_delegate.h
index 52c2899..f39c6ed1 100644
--- a/components/autofill/content/browser/email_verifier_delegate.h
+++ b/components/autofill/content/browser/email_verifier_delegate.h
@@ -27,8 +27,8 @@
 // https://github.com/dickhardt/email-verification-protocol
 class EmailVerifierDelegate : public AutofillManager::Observer {
  public:
-  using EmailVerifierBuilder =
-      base::RepeatingCallback<content::webid::EmailVerifier*(AutofillManager&)>;
+  using EmailVerifierBuilder = base::RepeatingCallback<
+      content::webid::EmailVerifier*(AutofillClient&, const LocalFrameToken&)>;
 
   explicit EmailVerifierDelegate(AutofillClient* client);
   EmailVerifierDelegate(AutofillClient* client, EmailVerifierBuilder builder);
diff --git a/components/autofill/content/browser/email_verifier_delegate_unittest.cc b/components/autofill/content/browser/email_verifier_delegate_unittest.cc
index 357ebf8..deee7d36 100644
--- a/components/autofill/content/browser/email_verifier_delegate_unittest.cc
+++ b/components/autofill/content/browser/email_verifier_delegate_unittest.cc
@@ -76,9 +76,10 @@
     email_verifier_ = std::make_unique<NiceMock<MockEmailVerifier>>();
     delegate_ = std::make_unique<EmailVerifierDelegate>(
         &client_,
-        base::BindRepeating([](content::webid::EmailVerifier* verifier,
-                               AutofillManager&) { return verifier; },
-                            email_verifier_.get()));
+        base::BindRepeating(
+            [](content::webid::EmailVerifier* verifier, AutofillClient&,
+               const LocalFrameToken&) { return verifier; },
+            email_verifier_.get()));
   }
 
   void TearDown() override {
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/components/autofill/content/browser/email_verifier_delegate_unittest.cc b/components/autofill/content/browser/email_verifier_delegate_unittest.cc
index 357ebf8..deee7d36 100644
--- a/components/autofill/content/browser/email_verifier_delegate_unittest.cc
+++ b/components/autofill/content/browser/email_verifier_delegate_unittest.cc
@@ -76,9 +76,10 @@
     email_verifier_ = std::make_unique<NiceMock<MockEmailVerifier>>();
     delegate_ = std::make_unique<EmailVerifierDelegate>(
         &client_,
-        base::BindRepeating([](content::webid::EmailVerifier* verifier,
-                               AutofillManager&) { return verifier; },
-                            email_verifier_.get()));
+        base::BindRepeating(
+            [](content::webid::EmailVerifier* verifier, AutofillClient&,
+               const LocalFrameToken&) { return verifier; },
+            email_verifier_.get()));
   }
 
   void TearDown() override {
Loading diff…

Original Bug Report

reported by vm...@google.com

EVP Cross-Frame Origin Confusion allows SD-JWT+KB Assertion Theft

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 without the security team.

Overview: A potential vulnerability in the Email Verification Protocol (EVP) allows a cross-origin iframe to steal a browser-signed identity assertion bound to its parent frame’s origin. Due to missing origin checks during Autofill form merging, the browser signs the parent’s origin into the token’s audience claim but delivers it to the attacker’s subframe. This could enable cross-origin identity assertion theft and account takeover.

Affected files:

  • components/autofill/content/browser/email_verifier_delegate.cc
  • content/browser/webid/delegation/email_verification_request.cc
  • components/autofill/core/browser/foundations/autofill_driver_router.cc
  • components/autofill/core/browser/foundations/form_forest.cc
  • components/autofill/core/browser/filling/form_filler.cc
  • components/autofill/content/renderer/form_autofill_util.cc

Estimated timestamp from git blame: 2025-09-25

The Email Verification Protocol (EVP) implementation within Autofill contains a logic flaw allowing an attacker-controlled subframe to obtain a signed SD-JWT+KB identity assertion scoped to its parent frame’s origin (aud claim).

Vulnerability Details

Standard Autofill processing successfully merges cross-origin subframe fields into a single logical form handled by the root frame’s BrowserAutofillManager. When a user autofills an EVP-enabled field within this merged context, EmailVerifierDelegate::OnFillOrPreviewForm is invoked.

Rather than validating the specific field’s origin, the delegate directly constructs the EmailVerificationRequest using the root manager’s RenderFrameHost. This incorrectly binds the resulting JWT’s audience (aud) claim to the parent (victim) origin. The system then routes the DispatchEmailVerifiedEvent containing the signed presentation token back to the attacker-controlled subframe that originally hosted the input field.

Potential Reproduction Steps

Note: These are suggested/potential steps to trigger the vulnerability, as our tooling agent does not yet have the ability to run code.

  1. Setup: An attacker embeds a cross-origin iframe (https://attacker.com) on a target victim site (https://victim.com).
  2. Payload: The attacker iframe contains <input type="email" autocomplete="email" nonce="ATTACKER_NONCE"> and a JavaScript listener for the emailverified DOM event.
  3. Interaction: The user autofills the email field within the attacker’s iframe.
  4. Exploitation: The browser signs the ATTACKER_NONCE into an SD-JWT+KB assertion with aud=https://victim.com and fires the emailverified event in the attacker’s iframe. The attacker captures the token and replays it to the victim’s backend.

Suggested Fix

Update EmailVerifierDelegate::OnFillOrPreviewForm to either:

  1. Verify that the LocalFrameToken of the field possessing the nonce matches the frame token of the AutofillManager processing the form.
  2. Pass the specific RenderFrameHost corresponding to the field’s frame_token to the EmailVerifierBuilder, ensuring the aud claim accurately reflects the subframe’s origin.

Evaluated with Chrome root at commit: f200f57a19490707ff8bc7aa5de3cbc443a3afad


Results so far have been promising, but there can be wrong deductions. If this proves to be a false positive, please close as WAI; 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