Low chrome Memory Corruption 📄 Reporter bug report 🔧 Commit mapped

Overview

Low
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactMemory corruption in Autofill
DescriptionMemory corruption in Autofill
ComponentAutofill
Sub-componentMac
Bug ClassMemory Corruption
Tracker439873332
Fix commit54157e0d7a49 (chromium/src) +71/-11
CISA KEVNot listed
CreditedManojkumar Jaganathan ( https://www.linkedin.com/in/manojkumar-j-7ba35b202/ ) Aka TheWhiteEvil ( https://hackerone.com/the-white-evil ) with HackerBro Technologies
Disclosed2026-10-20

Changed Functions

FunctionChangeNotes
if
chrome/browser/media/webrtc/media_stream_focus_delegate.cc
modified
if
chrome/browser/permissions/BUILD.gn
modified

Files Changed

  • chrome/browser/permissions/permissions_security_model_interactive_uitest.cc
  • content/browser/renderer_host/render_widget_host_view_mac.mm
  • chrome/browser/media/webrtc/media_stream_focus_delegate.cc
  • chrome/browser/media/webrtc/media_stream_focus_delegate.h
  • chrome/test/base/interactive_test_utils_aura.cc
  • chrome/browser/permissions/BUILD.gn
From 54157e0d7a49f477f16d6bbbe703f691e9d056ac Mon Sep 17 00:00:00 2001
From: Keren Zhu <[email protected]>
Date: Tue, 22 Sep 2026 08:50:51 -0700
Subject: [PATCH] mac: return false from RWHVMac::HasFocus() when the window is not key

This CL changes HasFocus() to return false if the window is non-key.
This aligns the behavior with Aura & Blink (that being focused implies
being in the active window).

This fixes a security issue in autofill that the autofill popup in an
inactive window sometimes occludes the active window
(crbug.com/439873332). Previously, the autofill popup closes itself iff
RWHV::HasFocus() is false, but HasFocus() does not check checks window
key status. This means the popup won't be close if the window goes
inactive but NSView does not resign first responder.

A few tests are updated to show and activate the browser window before
running the rest of the test. They were depending on HasFocus()
returning true when the window is inactive. Some tests are excluded on
Wayland because Wayland has poor support for activating background
window (https://crbug.com/40863331) and the test times out.

The change is under a kill switch,
kRWHVMacHasFocusReturnsFalseForNonKeyWindow.

Bug: 441089142, 439873332
Include-Ci-Only-Tests: chromium.mac:mac26-arm64-rel-tests|browser_tests
Change-Id: I9683d3a328d58f6a5cf76d10f53a7e170898d052
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7085807
Reviewed-by: Avi Drissman <[email protected]>
Commit-Queue: Keren Zhu <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1702667}
---
diff --git a/chrome/browser/media/webrtc/media_stream_focus_delegate.cc b/chrome/browser/media/webrtc/media_stream_focus_delegate.cc
index 04d4a8df..c7cf97a 100644
--- a/chrome/browser/media/webrtc/media_stream_focus_delegate.cc
+++ b/chrome/browser/media/webrtc/media_stream_focus_delegate.cc
@@ -85,8 +85,8 @@
     return;  // Window of opportunity to change focus now closed - we're done.
   }
 
-  if (!IsWidgetFocused()) {
-    // Capturing window not focused - likely the user has alt-tabbed away.
+  if (!IsBrowserActive()) {
+    // Capturing window not active - likely the user has alt-tabbed away.
     return;
   }
 
@@ -105,17 +105,20 @@
   focus_window_of_opportunity_open_ = false;
 }
 
-bool MediaStreamFocusDelegate::IsWidgetFocused() const {
+bool MediaStreamFocusDelegate::IsBrowserActive() const {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   DCHECK(capturing_web_contents_);  // Tested by caller.
 
-  content::RenderWidgetHostView* const rwhv =
-      capturing_web_contents_->GetRenderWidgetHostView();
-  if (!rwhv) {
-    return false;
-  }
-
-  return rwhv->HasFocus();
+  // Use BrowserWindowInterface::IsActive() rather than
+  // RenderWidgetHostView::HasFocus(). When the screen picker dialog is accepted
+  // and closing (e.g. during the asynchronous modal close animation on macOS),
+  // the child modal dialog window may still be the OS key window when
+  // SetFocus() runs, causing RenderWidgetHostView::HasFocus() to return false
+  // even though the browser window is still logically active.
+  BrowserWindowInterface* const browser =
+      GlobalBrowserCollection::GetInstance()->FindBrowserWithTab(
+          capturing_web_contents_.get());
+  return browser && browser->IsActive();
 }
 
 void MediaStreamFocusDelegate::FocusTab(
diff --git a/chrome/browser/media/webrtc/media_stream_focus_delegate.h b/chrome/browser/media/webrtc/media_stream_focus_delegate.h
index b6b79d0..024d1c8 100644
--- a/chrome/browser/media/webrtc/media_stream_focus_delegate.h
+++ b/chrome/browser/media/webrtc/media_stream_focus_delegate.h
@@ -53,7 +53,7 @@
   void ResetExplicitDecisionForTesting() { explicit_decision_ = false; }
 
  private:
-  bool IsWidgetFocused() const;
+  bool IsBrowserActive() const;
   void FocusTab(const content::DesktopMediaID& media_id);
   void FocusWindow(const content::DesktopMediaID& media_id);
 
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.mm b/content/browser/renderer_host/render_widget_host_view_mac.mm
index 31561fd..3086ae7 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac.mm
+++ b/content/browser/renderer_host/render_widget_host_view_mac.mm
@@ -115,6 +115,11 @@
 // resize.
 BASE_FEATURE(kThrottleResizeIpc, base::FEATURE_ENABLED_BY_DEFAULT);
 
+// If enabled, RenderWidgetHostViewMac::HasFocus() returns false if it is in
+// a non-key NSWindow. This aligns with Aura behavior. crbug.com/441089142.
+BASE_FEATURE(kRWHVMacHasFocusReturnsFalseForNonKeyWindow,
+             base::FEATURE_ENABLED_BY_DEFAULT);
+
 // Extract any events in `visible_time_request` that should go to the
 // DelegatedFrameHost and sends them to `delegated_frame_host`. Modifies
 // `visible_time_request` in place.
@@ -683,6 +688,12 @@
 }
 
 bool RenderWidgetHostViewMac::HasFocus() {
+  if (base::FeatureList::IsEnabled(
+          kRWHVMacHasFocusReturnsFalseForNonKeyWindow)) {
+    // In headless mode the NSView is not in a NSWindow.
+    return is_first_responder_ && (IsHeadless() || is_window_key_);
+  }
+
   return is_first_responder_;
 }
 
diff --git a/chrome/browser/permissions/permissions_security_model_interactive_uitest.cc b/chrome/browser/permissions/permissions_security_model_interactive_uitest.cc
index 15b55ed7..53f5410 100644
--- a/chrome/browser/permissions/permissions_security_model_interactive_uitest.cc
+++ b/chrome/browser/permissions/permissions_security_model_interactive_uitest.cc
@@ -22,6 +22,7 @@
 #include "chrome/test/base/chrome_test_path_utils.h"
 #include "chrome/test/base/chrome_test_utils.h"
 #include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/interactive_test_utils.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "chrome/test/interaction/interactive_browser_test.h"
 #include "chrome/test/permissions/permission_request_manager_test_api.h"
@@ -60,6 +61,10 @@
 #include "third_party/blink/public/mojom/permissions/permission_status.mojom-shared.h"
 #include "url/gurl.h"
 
+#if BUILDFLAG(IS_OZONE)
+#include "ui/ozone/public/ozone_platform.h"
+#endif
+
 namespace {
 
 // Helper for CreateBlobURL() and CreateFilesystemURL().
@@ -173,6 +178,7 @@
       contents, content::JsReplace("window.open($1, '', '[]');", url));
   BrowserWindowInterface* popup = ui_test_utils::WaitForBrowserToOpen();
   EXPECT_NE(popup, browser);
+  EXPECT_TRUE(ui_test_utils::BringBrowserWindowToFront(popup));
   content::WebContents* popup_contents =
       popup->GetTabStripModel()->GetActiveWebContents();
   EXPECT_TRUE(WaitForRenderFrameReady(popup_contents->GetPrimaryMainFrame()));
@@ -307,6 +313,10 @@
       permissions::PermissionRequestManager::AutoResponseType::ACCEPT_ALL);
 
   // Move the web contents to the foreground.
+  BrowserWindowInterface* opener_browser =
+      GlobalBrowserCollection::GetInstance()->FindBrowserWithTab(
+          opener_or_embedder_contents);
+  ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(opener_browser));
   opener_rfh->GetView()->Focus();
   ASSERT_TRUE(opener_rfh->GetView()->HasFocus());
   // Request permission on the opener or embedder contents.
@@ -323,6 +333,10 @@
   EXPECT_EQ(true, content::EvalJs(test_rfh, check_permission_script));
 
   // Request permission on the test RFH.
+  BrowserWindowInterface* test_browser =
+      GlobalBrowserCollection::GetInstance()->FindBrowserWithTab(
+          content::WebContents::FromRenderFrameHost(test_rfh));
+  ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(test_browser));
   test_rfh->GetView()->Focus();
   ASSERT_TRUE(test_rfh->GetView()->HasFocus());
   EXPECT_EQ("granted", content::EvalJs(test_rfh, request_permission_script));
@@ -350,6 +364,10 @@
       permissions::PermissionRequestManager::AutoResponseType::ACCEPT_ALL);
 
   // Move the web contents to the foreground.
+  BrowserWindowInterface* popup_browser =
+      GlobalBrowserCollection::GetInstance()->FindBrowserWithTab(
+          popup_contents);
+  ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(popup_browser));
   popup_rfh->GetView()->Focus();
   ASSERT_TRUE(popup_rfh->GetView()->HasFocus());
   // Request permission on the popup RenderFrameHost.
@@ -482,6 +500,11 @@
 
 IN_PROC_BROWSER_TEST_F(PermissionsSecurityModelInteractiveUITest,
                        WindowOpenAboutBlank) {
+#if BUILDFLAG(IS_OZONE)
+  if (ui::OzonePlatform::RunningOnWaylandForTest()) {
+    GTEST_SKIP() << "Wayland does not support programmatic window activation.";
+  }
+#endif
   ASSERT_TRUE(embedded_test_server()->Start());
   const GURL url(embedded_test_server()->GetURL("/empty.html"));
   EXPECT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
@@ -500,6 +523,11 @@
 
 IN_PROC_BROWSER_TEST_F(PermissionsSecurityModelInteractiveUITest,
                        WindowOpenAboutBlankToUseQuiet) {
+#if BUILDFLAG(IS_OZONE)
+  if (ui::OzonePlatform::RunningOnWaylandForTest()) {
+    GTEST_SKIP() << "Wayland does not support programmatic window activation.";
+  }
+#endif
   browser()->GetProfile()->GetPrefs()->SetBoolean(
       prefs::kEnableQuietNotificationPermissionUi, true);
   ASSERT_TRUE(embedded_test_server()->Start());
@@ -562,6 +590,11 @@
 
 IN_PROC_BROWSER_TEST_F(PermissionsSecurityModelInteractiveUITest,
                        WindowOpenBlob) {
+#if BUILDFLAG(IS_OZONE)
+  if (ui::OzonePlatform::RunningOnWaylandForTest()) {
+    GTEST_SKIP() << "Wayland does not support programmatic window activation.";
+  }
+#endif
   ASSERT_TRUE(embedded_test_server()->Start());
   const GURL url(embedded_test_server()->GetURL("/empty.html"));
   content::RenderFrameHost* main_rfh =
@@ -605,6 +638,11 @@
 
 IN_PROC_BROWSER_TEST_F(PermissionsSecurityModelInteractiveUITest,
                        WindowOpenFileSystemBrowserNavigation) {
+#if BUILDFLAG(IS_OZONE)
+  if (ui::OzonePlatform::RunningOnWaylandForTest()) {
+    GTEST_SKIP() << "Wayland does not support programmatic window activation.";
+  }
+#endif
   ASSERT_TRUE(embedded_test_server()->Start());
   const GURL url(embedded_test_server()->GetURL("/empty.html"));
   content::RenderFrameHost* main_rfh =
diff --git a/chrome/test/base/interactive_test_utils_aura.cc b/chrome/test/base/interactive_test_utils_aura.cc
index 624a7a2..fb5f7ee 100644
--- a/chrome/test/base/interactive_test_utils_aura.cc
+++ b/chrome/test/base/interactive_test_utils_aura.cc
@@ -7,6 +7,7 @@
 #include "build/build_config.h"
 #include "chrome/test/base/interactive_test_utils.h"
 #include "ui/aura/window.h"
+#include "ui/views/widget/widget.h"
 
 namespace ui_test_utils {
 
@@ -26,6 +27,9 @@
 
 bool ShowAndFocusNativeWindowAura(gfx::NativeWindow window) {
   window->Show();
+  if (views::Widget* widget = views::Widget::GetWidgetForNativeWindow(window)) {
+    widget->Activate();
+  }
   window->Focus();
   return true;
 }
diff --git a/chrome/browser/permissions/BUILD.gn b/chrome/browser/permissions/BUILD.gn
index b49f7df..9152679 100644
--- a/chrome/browser/permissions/BUILD.gn
+++ b/chrome/browser/permissions/BUILD.gn
@@ -445,5 +445,9 @@
       deps += [ "//chrome/browser/ui:browser_window_header" ]
       sources += [ "system/system_permission_settings_interactive_uitest.cc" ]
     }
+
+    if (use_ozone) {
+      deps += [ "//ui/ozone" ]
+    }
   }
 }
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/chrome/browser/permissions/permissions_security_model_interactive_uitest.cc b/chrome/browser/permissions/permissions_security_model_interactive_uitest.cc
index 15b55ed7..53f5410 100644
--- a/chrome/browser/permissions/permissions_security_model_interactive_uitest.cc
+++ b/chrome/browser/permissions/permissions_security_model_interactive_uitest.cc
@@ -22,6 +22,7 @@
 #include "chrome/test/base/chrome_test_path_utils.h"
 #include "chrome/test/base/chrome_test_utils.h"
 #include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/interactive_test_utils.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "chrome/test/interaction/interactive_browser_test.h"
 #include "chrome/test/permissions/permission_request_manager_test_api.h"
@@ -60,6 +61,10 @@
 #include "third_party/blink/public/mojom/permissions/permission_status.mojom-shared.h"
 #include "url/gurl.h"
 
+#if BUILDFLAG(IS_OZONE)
+#include "ui/ozone/public/ozone_platform.h"
+#endif
+
 namespace {
 
 // Helper for CreateBlobURL() and CreateFilesystemURL().
@@ -173,6 +178,7 @@
       contents, content::JsReplace("window.open($1, '', '[]');", url));
   BrowserWindowInterface* popup = ui_test_utils::WaitForBrowserToOpen();
   EXPECT_NE(popup, browser);
+  EXPECT_TRUE(ui_test_utils::BringBrowserWindowToFront(popup));
   content::WebContents* popup_contents =
       popup->GetTabStripModel()->GetActiveWebContents();
   EXPECT_TRUE(WaitForRenderFrameReady(popup_contents->GetPrimaryMainFrame()));
@@ -307,6 +313,10 @@
       permissions::PermissionRequestManager::AutoResponseType::ACCEPT_ALL);
 
   // Move the web contents to the foreground.
+  BrowserWindowInterface* opener_browser =
+      GlobalBrowserCollection::GetInstance()->FindBrowserWithTab(
+          opener_or_embedder_contents);
+  ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(opener_browser));
   opener_rfh->GetView()->Focus();
   ASSERT_TRUE(opener_rfh->GetView()->HasFocus());
   // Request permission on the opener or embedder contents.
@@ -323,6 +333,10 @@
   EXPECT_EQ(true, content::EvalJs(test_rfh, check_permission_script));
 
   // Request permission on the test RFH.
+  BrowserWindowInterface* test_browser =
+      GlobalBrowserCollection::GetInstance()->FindBrowserWithTab(
+          content::WebContents::FromRenderFrameHost(test_rfh));
+  ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(test_browser));
   test_rfh->GetView()->Focus();
   ASSERT_TRUE(test_rfh->GetView()->HasFocus());
   EXPECT_EQ("granted", content::EvalJs(test_rfh, request_permission_script));
@@ -350,6 +364,10 @@
       permissions::PermissionRequestManager::AutoResponseType::ACCEPT_ALL);
 
   // Move the web contents to the foreground.
+  BrowserWindowInterface* popup_browser =
+      GlobalBrowserCollection::GetInstance()->FindBrowserWithTab(
+          popup_contents);
+  ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(popup_browser));
   popup_rfh->GetView()->Focus();
   ASSERT_TRUE(popup_rfh->GetView()->HasFocus());
   // Request permission on the popup RenderFrameHost.
@@ -482,6 +500,11 @@
 
 IN_PROC_BROWSER_TEST_F(PermissionsSecurityModelInteractiveUITest,
                        WindowOpenAboutBlank) {
+#if BUILDFLAG(IS_OZONE)
+  if (ui::OzonePlatform::RunningOnWaylandForTest()) {
+    GTEST_SKIP() << "Wayland does not support programmatic window activation.";
+  }
+#endif
   ASSERT_TRUE(embedded_test_server()->Start());
   const GURL url(embedded_test_server()->GetURL("/empty.html"));
   EXPECT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
@@ -500,6 +523,11 @@
 
 IN_PROC_BROWSER_TEST_F(PermissionsSecurityModelInteractiveUITest,
                        WindowOpenAboutBlankToUseQuiet) {
+#if BUILDFLAG(IS_OZONE)
+  if (ui::OzonePlatform::RunningOnWaylandForTest()) {
+    GTEST_SKIP() << "Wayland does not support programmatic window activation.";
+  }
+#endif
   browser()->GetProfile()->GetPrefs()->SetBoolean(
       prefs::kEnableQuietNotificationPermissionUi, true);
   ASSERT_TRUE(embedded_test_server()->Start());
@@ -562,6 +590,11 @@
 
 IN_PROC_BROWSER_TEST_F(PermissionsSecurityModelInteractiveUITest,
                        WindowOpenBlob) {
+#if BUILDFLAG(IS_OZONE)
+  if (ui::OzonePlatform::RunningOnWaylandForTest()) {
+    GTEST_SKIP() << "Wayland does not support programmatic window activation.";
+  }
+#endif
   ASSERT_TRUE(embedded_test_server()->Start());
   const GURL url(embedded_test_server()->GetURL("/empty.html"));
   content::RenderFrameHost* main_rfh =
@@ -605,6 +638,11 @@
 
 IN_PROC_BROWSER_TEST_F(PermissionsSecurityModelInteractiveUITest,
                        WindowOpenFileSystemBrowserNavigation) {
+#if BUILDFLAG(IS_OZONE)
+  if (ui::OzonePlatform::RunningOnWaylandForTest()) {
+    GTEST_SKIP() << "Wayland does not support programmatic window activation.";
+  }
+#endif
   ASSERT_TRUE(embedded_test_server()->Start());
   const GURL url(embedded_test_server()->GetURL("/empty.html"));
   content::RenderFrameHost* main_rfh =
diff --git a/chrome/test/base/interactive_test_utils_aura.cc b/chrome/test/base/interactive_test_utils_aura.cc
index 624a7a2..fb5f7ee 100644
--- a/chrome/test/base/interactive_test_utils_aura.cc
+++ b/chrome/test/base/interactive_test_utils_aura.cc
@@ -7,6 +7,7 @@
 #include "build/build_config.h"
 #include "chrome/test/base/interactive_test_utils.h"
 #include "ui/aura/window.h"
+#include "ui/views/widget/widget.h"
 
 namespace ui_test_utils {
 
@@ -26,6 +27,9 @@
 
 bool ShowAndFocusNativeWindowAura(gfx::NativeWindow window) {
   window->Show();
+  if (views::Widget* widget = views::Widget::GetWidgetForNativeWindow(window)) {
+    widget->Activate();
+  }
   window->Focus();
   return true;
 }
Loading diff…

Original Bug Report

reported by [email protected]

Autofill Prompt Spoofing via Cross-Origin Rendering in Chrome 139.0.7258.139 on macOS 15.6

Steps to reproduce the problem

Reproduction Steps:

> Prerequisites: > Ensure the following data is stored in Chrome:

  • At least one address entry with an email address: chrome://settings/addresses
  • At least one credit card: chrome://settings/payments

PoC 1 – Address Autofill (Multiple Fields)

  1. Navigate to: https://attacker.hackerbro.net/exploit.html
  2. Click the “Verify Info” button.
  3. Click on the autofill suggestion that appears.
  4. Observe the data being injected into an overlayed form from a different origin.

PoC 2 – Credit Card Autofill (Multiple Fields)

  1. Navigate to: https://attacker.hackerbro.net/exploit.html?creditcard
  2. Click the “Verify Info” button.
  3. Click on the autofill suggestion that appears.
  4. Observe the data being injected into an overlayed form from a different origin.

PoC 3 – Name Autofill (Single Field)

  1. Navigate to: https://attacker.hackerbro.net/exploit.html?single
  2. Click the “Verify Info” button.
  3. Click on the autofill suggestion that appears.
  4. Observe the data being injected into an overlayed form from a different origin.

Reference:

https://issues.chromium.org/u/1/issues/40056880?pli=1

Expected Behavior:

  • Autofill prompts should only appear for input elements that are in the same origin as the page requesting the autofill.
  • The browser should verify and bind the autofill UI to the correct origin context, preventing cross-origin spoofing.

Actual Behavior:

  • Autofill prompts can be triggered or rendered in a cross-origin context, allowing spoofing of the trusted origin.
  • There is no reliable origin validation in the autofill UI layer.

Recommendation:

  • Enforce strict same-origin checks before displaying autofill UI.
  • Autofill prompts should never be rendered in an iframe or any cross-origin element.
  • Any UI trigger must be tied to same-origin input events with visual trust indicators.

Problem Description

  • In Chrome version 139.0.7258.139 on macOS 15.6, the autofill prompt can be rendered over a different origin, allowing malicious sites to spoof the origin context of the autofill UI. This can lead to a serious phishing risk where a user is tricked into autofilling sensitive data (e.g., usernames, passwords, credit card details) into a form controlled by a malicious domain.

Environment:

  • Chrome Version: 139.0.7258.139
  • OS: macOS Sonoma 15.6

Impact:

  • Phishing: Users can be tricked into submitting sensitive information to attackers.
  • Credential theft: Autofill may reveal stored usernames and passwords.
  • Loss of trust: Users assume autofill prompts come only from trusted origins.

Summary

Autofill Prompt Spoofing via Cross-Origin Rendering in Chrome 139.0.7258.139 on macOS 15.6

Additional Data

Category: Security
Chrome Channel: Stable
Regression: Yes \

View on issue tracker