CVE-2026-10950
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifcomponents/autofill/ios/browser/autofill_driver_ios.mm |
modified | |
TEST_Fcomponents/autofill/ios/browser/autofill_driver_ios_unittest.mm |
modified |
Files Changed
components/autofill/ios/browser/autofill_driver_ios.mmcomponents/autofill/ios/browser/autofill_driver_ios_unittest.mm
Patch
From 6946fc91170fbc9347406cf75202bcaf8202d6b3 Mon Sep 17 00:00:00 2001
From: Matt Reichhoff <mreichhoff@chromium.org>
Date: Wed, 29 Apr 2026 12:17:38 -0700
Subject: [PATCH] [iOS] Fix potential iOS Autofill isolation bypass
Should be a simple unregister change. CL entirely AI generated.
Bug: 505123022
Change-Id: Ieda1bb5893cf7989cb8757f9680c7c532b345cfc
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7802397
Reviewed-by: Tommy Martino <tmartino@chromium.org>
Commit-Queue: Matt Reichhoff <mreichhoff@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1622636}
---
diff --git a/components/autofill/ios/browser/autofill_driver_ios.mm b/components/autofill/ios/browser/autofill_driver_ios.mm
index b9c22f0..a04e740 100644
--- a/components/autofill/ios/browser/autofill_driver_ios.mm
+++ b/components/autofill/ios/browser/autofill_driver_ios.mm
@@ -670,6 +670,10 @@
void AutofillDriverIOS::SetSelfAsParent(const autofill::FormData& form,
LocalFrameToken token) {
+ if (unregistered_) {
+ return;
+ }
+
AutofillDriverIOS* child_driver =
FromWebStateAndLocalFrameToken(web_state_, token);
if (child_driver) {
@@ -813,6 +817,8 @@
void AutofillDriverIOS::Unregister() {
router_->UnregisterDriver(*this, /*driver_is_dying=*/true);
unregistered_ = true;
+ parent_ = nullptr;
+ weak_ptr_factory_.InvalidateWeakPtrs();
}
void AutofillDriverIOS::OnDidTriggerFormFetch() {
diff --git a/components/autofill/ios/browser/autofill_driver_ios_unittest.mm b/components/autofill/ios/browser/autofill_driver_ios_unittest.mm
index d54ef877..3dfe5fe 100644
--- a/components/autofill/ios/browser/autofill_driver_ios_unittest.mm
+++ b/components/autofill/ios/browser/autofill_driver_ios_unittest.mm
@@ -303,6 +303,13 @@
EXPECT_EQ(1, fetch_calls);
}
+TEST_F(AutofillDriverIOSTest, Unregister_InvalidatesWeakPtrs) {
+ auto weak_ptr = main_frame_driver()->GetWeakPtr();
+ ASSERT_TRUE(weak_ptr);
+ main_frame_driver()->Unregister();
+ EXPECT_FALSE(weak_ptr);
+}
+
} // namespace
} // namespace autofill
Regression Test / PoC
diff --git a/components/autofill/ios/browser/autofill_driver_ios_unittest.mm b/components/autofill/ios/browser/autofill_driver_ios_unittest.mm
index d54ef877..3dfe5fe 100644
--- a/components/autofill/ios/browser/autofill_driver_ios_unittest.mm
+++ b/components/autofill/ios/browser/autofill_driver_ios_unittest.mm
@@ -303,6 +303,13 @@
EXPECT_EQ(1, fetch_calls);
}
+TEST_F(AutofillDriverIOSTest, Unregister_InvalidatesWeakPtrs) {
+ auto weak_ptr = main_frame_driver()->GetWeakPtr();
+ ASSERT_TRUE(weak_ptr);
+ main_frame_driver()->Unregister();
+ EXPECT_FALSE(weak_ptr);
+}
+
} // namespace
} // namespace autofill
Original Bug Report
Potential iOS Autofill isolation bypass via async callback resurrection
Flapjack, 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 Chrome Security team. Please see go/chrome-ai-generated-security-bugs-faq for more information.
Overview: A logic flaw in iOS Autofill allows an isolated malicious iframe to resurrect itself and bypass anti-spoofing mitigations. Because AutofillDriverIOS::Unregister() fails to invalidate its WeakPtrFactory or check the unregistered_ flag in subsequent async callbacks, a compromised frame can re-insert itself into the global Autofill tree. This potentially allows the malicious frame to intercept sensitive cross-origin autofill data.
Affected files:
components/autofill/ios/browser/autofill_driver_ios.mmcomponents/autofill/ios/browser/autofill_driver_ios.hios/chrome/browser/autofill/model/autofill_tab_helper.mm
Estimated timestamp from git blame: 2024-07-25
Background
In iOS Autofill, cross-iframe filling (kAutofillAcrossIframesIos) relies on a security isolation mechanism to combat frame spoofing. If AutofillTabHelper::OnDidDoubleRegistration detects multiple frames claiming the same remote token, it assumes a spoofing attack and calls AutofillDriverIOS::Unregister() on the suspicious driver. This removes the driver’s FrameData node from the FormForest tree, preventing it from participating in cross-frame filling.
Vulnerability
There is a potential bypass of this isolation mechanism due to inadequate cleanup in AutofillDriverIOS::Unregister().
When a frame reports forms containing nested child frames, AutofillDriverIOS::FormsSeen registers an asynchronous callback with the ChildFrameRegistrar. This callback is bound to AutofillDriverIOS::SetSelfAsParent and securely captures the driver using a base::WeakPtr.
When AutofillTabHelper isolates a driver via Unregister(), it sets an internal unregistered_ = true flag and removes the driver from the router. However, it does not invalidate the driver’s weak_ptr_factory_ nor does it clear its parent_ pointer.
Because the weak pointers remain valid, any pending child frame registration callbacks belonging to the isolated driver can still execute. When SetSelfAsParent executes, it fails to check the unregistered_ flag and proceeds to call router_->FormsSeen(...), passing the isolated driver back into the system.
FormForest::UpdateTreeOfRendererForm actively recreates the previously erased FrameData node. Because the driver’s parent_ pointer was never cleared, FormForest successfully asks the top-level parent document to re-extract forms, seamlessly linking the isolated malicious frame back into the cross-origin form tree.
Potential Exploitation Steps
An attacker controlling a top-level page and an iframe (Frame A) could potentially trigger this bypass:
- Callback Creation: Frame A embeds its own child iframe (Frame C). Frame A extracts its forms and sends them to the browser, which creates a pending registration callback for Frame C’s token bound to Frame A’s driver.
- Spoofing Attack: The attacker reads the
__gCrChildFrameRemoteTokenof a legitimate cross-origin iframe (Frame B) from the parent DOM and uses Frame A to register mapping to Frame B’s token. - Isolation: Frame B registers its legitimate mapping.
ChildFrameRegistrardetects double registration for Frame B’s token, invalidates the token, and isolates Frame A by callingUnregister()on its driver. - Zombie Execution: Frame C finally loads and registers its token mapping.
ChildFrameRegistrarexecutes the pending callback from step 1. - Tree Re-insertion: The callback invokes
SetSelfAsParenton the isolated Frame A driver. Without anunregistered_check, the driver callsrouter_->FormsSeen, which recreates Frame A’s node inFormForest. - Relinking:
FormForestcallsGetParent()on Frame A’s driver, triggering a re-extraction in the top-level document that fully wires the resurrected Frame A back into the Autofill tree.
Once resurrected, Frame A can participate in cross-frame filling and potentially intercept sensitive user data (like credit cards) filled into the legitimate parent frame.
Suggested Fix
- In
AutofillDriverIOS::Unregister(), explicitly invalidate the weak pointers to prevent asynchronous callbacks from executing on isolated drivers:weak_ptr_factory_.InvalidateWeakPtrs(); - As a defense-in-depth measure, add an explicit check at the beginning of
AutofillDriverIOS::SetSelfAsParentto return early ifunregistered_is true. - Consider explicitly clearing
parent_inUnregister()to sever ties with the form tree hierarchy.
Evaluated with Chrome root at commit: 4a3e9db74111a3c6c4b3acfd70050a05077cf27a
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.