Overview

High
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactInappropriate implementation in Passwords
DescriptionInappropriate implementation in Passwords
ComponentPasswords
Bug ClassLogic Error
Tracker502651056
Fix commit914362a72b86 (chromium/src) +14/-6
CISA KEVNot listed
CreditedGoogle
Disclosed2026-06-02

Files Changed

  • chrome/browser/password_manager/password_change/change_password_form_filling_submission_helper.cc
  • chrome/browser/password_manager/password_change/change_password_form_finder.cc
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(
Loading diff…

Original Bug Report

reported by rj...@google.com

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.cc
  • chrome/browser/password_manager/password_change/typing_helper.cc
  • chrome/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

  1. Process-Local Identifiers: In Chromium’s multi-process architecture (Site Isolation), a DOMNodeId is only unique within its own renderer process. They are generated using a static counter last_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 identical DOMNodeId values.

  2. Cross-Frame Content Collection: The APC flow uses optimization_guide::GetAIPageContent to gather DOM information from all frames on a page. The include_same_site_only flag defaults to false, so the resulting tree includes nodes from the main frame and all cross-origin subframes, each associated with its respective process-local DOMNodeId.

  3. IPC Targeting Flaw: When the ML model identifies a node to interact with, it returns the raw DOMNodeId. Both ButtonClickHelper and TypingHelper are hardcoded to retrieve the ChromeRenderFrame interface from the PrimaryMainFrame and 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(...)
    
  4. Validation Bypass: Although the renderer includes a ValidateTimeOfUse check, it is currently bypassed. ButtonClickHelper does not provide an observed_target. When observed_target is null, the renderer returns a kOk success 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)

  1. An attacker-controlled cross-origin iframe is embedded in a target site (e.g., via malicious ad).
  2. The target site has a sensitive button in the main frame (e.g., “Delete Account”) with a specific DOMNodeId (e.g., 42).
  3. The attacker’s iframe deterministically generates DOM elements to ensure one of its nodes has a DOMNodeId of 42, styling it to look like a password submission button.
  4. The APC ML model selects the attacker’s fake button and returns DOMNodeId = 42.
  5. The browser blindly sends a ClickAction for ID 42 to the primary main frame, causing the main frame to click its own sensitive “Delete Account” button.

Scenario B: Credential Theft

  1. A legitimate site hosts its password change form in a secure cross-origin iframe.
  2. An attacker controls the parent page (e.g., a malicious site embedding the secure iframe).
  3. FormFillingHelper::FillField extracts the raw renderer_id from an autofill::FieldGlobalId, discarding the host_frame token.
  4. TypingHelper sends the new password and the DOMNodeId to the primary main frame (the attacker’s page) instead of the secure iframe.
  5. The attacker’s page intercepts the keystrokes and steals the password.

Suggested Fix

  • Update Protos: Modify the OpenFormResponseData and SubmitFormResponseData protos to include frame identifiers (e.g., a LocalFrameToken or the frame’s origin) alongside the DOMNodeId.
  • Target Correct Frames: Modify ButtonClickHelper and TypingHelper to accept a specific RenderFrameHost or frame token, and route the InvokeTool IPC to that specific frame rather than hardcoding the PrimaryMainFrame.
  • Preserve Frame Tokens: Ensure FormFillingHelper retains and utilizes the host_frame token from autofill::FieldGlobalId when delegating tasks to TypingHelper.

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.

View on issue tracker