CVE-2026-10937
Overview
Files Changed
chrome/browser/password_manager/password_change/change_password_form_filling_submission_helper.ccchrome/browser/password_manager/password_change/change_password_form_finder.cc
Patch
From 914362a72b86dff9b4e9199222b71d0d8115d598 Mon Sep 17 00:00:00 2001
From: Viktor Semeniuk <vsemeniuk@google.com>
Date: Thu, 16 Apr 2026 07:05:21 -0700
Subject: [PATCH] Capture page context for the same site only
Fixed: 502651056
Change-Id: Ia7ec685a568c954dc096ab87f3ea867d774ad66a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7768132
Reviewed-by: Vasilii Sukhanov <vasilii@chromium.org>
Commit-Queue: Viktor Semeniuk <vsemeniuk@google.com>
Cr-Commit-Position: refs/heads/main@{#1615814}
---
diff --git a/chrome/browser/password_manager/password_change/change_password_form_filling_submission_helper.cc b/chrome/browser/password_manager/password_change/change_password_form_filling_submission_helper.cc
index 51782f7..8d18d1f1 100644
--- a/chrome/browser/password_manager/password_change/change_password_form_filling_submission_helper.cc
+++ b/chrome/browser/password_manager/password_change/change_password_form_filling_submission_helper.cc
@@ -43,14 +43,18 @@
// WebContents where password change is happening is hidden, and renderer
// won't capture a snapshot unless it becomes visible again or
// on_critical_path is set to true.
+ blink::mojom::AIPageContentOptionsPtr options;
if (base::FeatureList::IsEnabled(
password_manager::features::
kUseActionablesForImprovedPasswordChange)) {
- return optimization_guide::ActionableAIPageContentOptions(
+ options = optimization_guide::ActionableAIPageContentOptions(
+ /*on_critical_path =*/true);
+ } else {
+ options = optimization_guide::DefaultAIPageContentOptions(
/*on_critical_path =*/true);
}
- return optimization_guide::DefaultAIPageContentOptions(
- /*on_critical_path =*/true);
+ options->include_same_site_only = true;
+ return options;
}
std::unique_ptr<Logger> GetLoggerIfAvailable(
diff --git a/chrome/browser/password_manager/password_change/change_password_form_finder.cc b/chrome/browser/password_manager/password_change/change_password_form_finder.cc
index c969e424..3dcd51b 100644
--- a/chrome/browser/password_manager/password_change/change_password_form_finder.cc
+++ b/chrome/browser/password_manager/password_change/change_password_form_finder.cc
@@ -44,14 +44,18 @@
// WebContents where password change is happening is hidden, and renderer
// won't capture a snapshot unless it becomes visible again or
// on_critical_path is set to true.
+ blink::mojom::AIPageContentOptionsPtr options;
if (base::FeatureList::IsEnabled(
password_manager::features::
kUseActionablesForImprovedPasswordChange)) {
- return optimization_guide::ActionableAIPageContentOptions(
+ options = optimization_guide::ActionableAIPageContentOptions(
+ /*on_critical_path =*/true);
+ } else {
+ options = optimization_guide::DefaultAIPageContentOptions(
/*on_critical_path =*/true);
}
- return optimization_guide::DefaultAIPageContentOptions(
- /*on_critical_path =*/true);
+ options->include_same_site_only = true;
+ return options;
}
std::unique_ptr<Logger> GetLoggerIfAvailable(
Original Bug Report
Potential Cross-Frame Confused Deputy in Automated Password Change via IPC Misdirection
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: The Automated Password Change (APC) flow incorrectly directs DOM-based actions like clicking and typing to the primary main frame, even when the intended target element belongs to a different frame. This allows a malicious cross-origin iframe to trigger actions on sensitive elements in the embedding page by spoofing DOM identifiers, or a malicious parent to steal credentials destined for a secure iframe.
Affected files:
chrome/browser/password_manager/password_change/button_click_helper.ccchrome/browser/password_manager/password_change/typing_helper.ccchrome/browser/password_manager/password_change/form_filling_helper.cc
Estimated timestamp from git blame: 2025-11-26
Summary
A potential vulnerability in the Automated Password Change (APC) flow allows a malicious cross-origin iframe to perform unauthorized actions (clicks or text entry) on the embedding page, or a malicious parent page to steal credentials intended for a secure iframe.
This occurs because ButtonClickHelper and TypingHelper unconditionally target the primary main frame when sending InvokeTool IPCs, while relying on DOMNodeId values that are process-local and can be easily collided by an attacker in a different renderer process.
Vulnerability Details
-
Process-Local Identifiers: In Chromium’s multi-process architecture (Site Isolation), a
DOMNodeIdis only unique within its own renderer process. They are generated using a static counterlast_id(third_party/blink/renderer/core/dom/dom_node_ids.cc). Different processes (e.g., a main frame and a cross-origin iframe) will predictably generate nodes with identicalDOMNodeIdvalues. -
Cross-Frame Content Collection: The APC flow uses
optimization_guide::GetAIPageContentto gather DOM information from all frames on a page. Theinclude_same_site_onlyflag defaults to false, so the resulting tree includes nodes from the main frame and all cross-origin subframes, each associated with its respective process-localDOMNodeId. -
IPC Targeting Flaw: When the ML model identifies a node to interact with, it returns the raw
DOMNodeId. BothButtonClickHelperandTypingHelperare hardcoded to retrieve theChromeRenderFrameinterface from thePrimaryMainFrameand send the action command to it, regardless of which frame the node actually belongs to:// chrome/browser/password_manager/password_change/button_click_helper.cc web_contents->GetPrimaryMainFrame() ->GetRemoteAssociatedInterfaces() ->GetInterface(&chrome_render_frame_); chrome_render_frame_->InvokeTool(...) -
Validation Bypass: Although the renderer includes a
ValidateTimeOfUsecheck, it is currently bypassed.ButtonClickHelperdoes not provide anobserved_target. Whenobserved_targetis null, the renderer returns akOksuccess result without performing identity verification (chrome/renderer/actor/tool_base.cc:376).
Suggested Exploitation Scenarios
(Note: These are potential steps as we have not executed a working proof of concept.)
Scenario A: Confused Deputy (CSRF)
- An attacker-controlled cross-origin iframe is embedded in a target site (e.g., via malicious ad).
- The target site has a sensitive button in the main frame (e.g., “Delete Account”) with a specific
DOMNodeId(e.g., 42). - The attacker’s iframe deterministically generates DOM elements to ensure one of its nodes has a
DOMNodeIdof 42, styling it to look like a password submission button. - The APC ML model selects the attacker’s fake button and returns
DOMNodeId = 42. - The browser blindly sends a
ClickActionfor ID 42 to the primary main frame, causing the main frame to click its own sensitive “Delete Account” button.
Scenario B: Credential Theft
- A legitimate site hosts its password change form in a secure cross-origin iframe.
- An attacker controls the parent page (e.g., a malicious site embedding the secure iframe).
FormFillingHelper::FillFieldextracts the rawrenderer_idfrom anautofill::FieldGlobalId, discarding thehost_frametoken.TypingHelpersends the new password and theDOMNodeIdto the primary main frame (the attacker’s page) instead of the secure iframe.- The attacker’s page intercepts the keystrokes and steals the password.
Suggested Fix
- Update Protos: Modify the
OpenFormResponseDataandSubmitFormResponseDataprotos to include frame identifiers (e.g., aLocalFrameTokenor the frame’s origin) alongside theDOMNodeId. - Target Correct Frames: Modify
ButtonClickHelperandTypingHelperto accept a specificRenderFrameHostor frame token, and route theInvokeToolIPC to that specific frame rather than hardcoding thePrimaryMainFrame. - Preserve Frame Tokens: Ensure
FormFillingHelperretains and utilizes thehost_frametoken fromautofill::FieldGlobalIdwhen delegating tasks toTypingHelper.
Evaluated with Chrome root at commit: c0eb5541aebfa4ea08806eaf6e94bcc69f87ab2f
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.