Medium chrome Logic Error 📄 Reporter bug report 🔧 Commit mapped

Overview

Medium
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactIncorrect security UI in Autofill
DescriptionIncorrect security UI in Autofill
ComponentAutofill
Bug ClassLogic Error
Tracker417052041
Fix commit51fa5641e7d8 (chromium/src) +131/-0
CISA KEVNot listed
CreditedKhalil Zhani
Disclosed2026-06-30

Changed Functions

FunctionChangeNotes
TEST
chrome/browser/ui/views/autofill/popup/popup_view_utils_unittest.cc
modified

Files Changed

  • chrome/browser/ui/views/autofill/popup/popup_view_utils.cc
  • chrome/browser/ui/views/autofill/popup/popup_view_utils.h
  • chrome/browser/ui/views/autofill/popup/popup_view_utils_unittest.cc
  • chrome/browser/ui/views/autofill/popup/popup_view_views.cc
  • components/autofill/core/common/autofill_features.cc
From 51fa5641e7d83003604a65a8810c329e252bc529 Mon Sep 17 00:00:00 2001
From: Mikita Kuchyn <[email protected]>
Date: Wed, 04 Mar 2026 08:44:19 -0800
Subject: [PATCH] [CPV] Prevent color picker overlapping Autofill

Color picker can obscure autofill popup on Windows. That CL
prevents that from happening by adding OverlapsWithHTMLFormPopup
function.

Bug: 417052041
Change-Id: I992a1291f452689087be668647149df920292b51
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7552031
Reviewed-by: Christoph Schwering <[email protected]>
Reviewed-by: Keren Zhu <[email protected]>
Commit-Queue: Mikita Kuchyn <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1593994}
---

diff --git a/chrome/browser/ui/views/autofill/popup/popup_view_utils.cc b/chrome/browser/ui/views/autofill/popup/popup_view_utils.cc
index 428f0ff..67adc56 100644
--- a/chrome/browser/ui/views/autofill/popup/popup_view_utils.cc
+++ b/chrome/browser/ui/views/autofill/popup/popup_view_utils.cc
@@ -7,9 +7,12 @@
 #include <algorithm>
 #include <optional>
 
+#include "base/containers/to_vector.h"
 #include "chrome/browser/picture_in_picture/picture_in_picture_window_manager.h"
 #include "chrome/browser/platform_util.h"
 #include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/views/autofill/popup/popup_base_view.h"
+#include "chrome/browser/ui/views/chrome_widget_sublevel.h"
 #include "chrome/browser/ui/views/extensions/extension_popup.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/interaction/browser_elements_views.h"
@@ -18,6 +21,7 @@
 #include "components/autofill/core/browser/suggestions/suggestion_type.h"
 #include "components/autofill/core/browser/ui/popup_open_enums.h"
 #include "components/autofill/core/common/autofill_features.h"
+#include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents.h"
 #include "extensions/common/constants.h"
 #include "ui/display/screen.h"
@@ -117,6 +121,38 @@
 
 }  // namespace
 
+namespace internal {
+bool BoundsOverlapWithHtmlFormPopup(
+    const gfx::Rect& popup_bounds,
+    const std::vector<PopupWidgetProperties>& widget_properties) {
+  return std::ranges::any_of(
+      widget_properties, [&popup_bounds](const auto& view) {
+        return view.is_showing && view.is_html_form_popup &&
+               view.bounds.Intersects(popup_bounds);
+      });
+}
+}  // namespace internal
+
+bool BoundsOverlapWithHtmlFormPopup(const gfx::Rect& popup_bounds,
+                                    content::WebContents* web_contents) {
+  // Currently HTML Form Popup overlap problem occurs only on Windows. On other
+  // platforms the Autofill popup correctly shows up above the HTML Form Popup.
+  // But the fix is enabled on other platforms as well, just in case.
+
+  // GetPopupWidgets() only returns popups associated with the current tab.
+  std::vector<internal::PopupWidgetProperties> widget_properties =
+      base::ToVector(web_contents->GetPopupWidgets(),
+                     [](content::RenderWidgetHostView* view) {
+                       return internal::PopupWidgetProperties({
+                           .is_showing = view->IsShowing(),
+                           .is_html_form_popup = view->IsHTMLFormPopup(),
+                           .bounds = view->GetViewBounds(),
+                       });
+                     });
+  return internal::BoundsOverlapWithHtmlFormPopup(popup_bounds,
+                                                  widget_properties);
+}
+
 void CalculatePopupYAndHeight(int popup_preferred_height,
                               const gfx::Rect& visible_content_area_bounds,
                               const gfx::Rect& element_bounds,
diff --git a/chrome/browser/ui/views/autofill/popup/popup_view_utils.h b/chrome/browser/ui/views/autofill/popup/popup_view_utils.h
index 978022c..8cc3e8cf 100644
--- a/chrome/browser/ui/views/autofill/popup/popup_view_utils.h
+++ b/chrome/browser/ui/views/autofill/popup/popup_view_utils.h
@@ -55,6 +55,29 @@
 bool BoundsOverlapWithAnyOpenPrompt(const gfx::Rect& screen_bounds,
                                     content::WebContents* web_contents);
 
+// Returns whether any HTML-based form popup (like a color picker) from the same
+// `web_contents` overlaps `popup_bounds`.
+bool BoundsOverlapWithHtmlFormPopup(const gfx::Rect& popup_bounds,
+                                    content::WebContents* web_contents);
+
+namespace internal {
+// To test the overlap logic without requiring a full browser environment,
+// this struct extracts the minimum state needed from RenderWidgetHostView,
+// allowing to unit test cleanly.
+struct PopupWidgetProperties {
+  bool is_showing;
+  bool is_html_form_popup;
+  gfx::Rect bounds;
+};
+
+// The core logic for `BoundsOverlapWithHtmlFormPopup()`, exposed in the
+// internal namespace strictly for unit testing. Production code should use the
+// WebContents* version above.
+bool BoundsOverlapWithHtmlFormPopup(
+    const gfx::Rect& popup_bounds,
+    const std::vector<PopupWidgetProperties>& popup_widgets);
+}  // namespace internal
+
 // Returns the total vertical space on `visible_content_area_bounds` on a
 // specific `side` of the `element_bounds`.
 int GetAvailableVerticalSpaceOnSideOfElement(
diff --git a/chrome/browser/ui/views/autofill/popup/popup_view_utils_unittest.cc b/chrome/browser/ui/views/autofill/popup/popup_view_utils_unittest.cc
index bf7918b..981e6cd3 100644
--- a/chrome/browser/ui/views/autofill/popup/popup_view_utils_unittest.cc
+++ b/chrome/browser/ui/views/autofill/popup/popup_view_utils_unittest.cc
@@ -491,4 +491,41 @@
   }
 }
 
+TEST(PopupViewUtilsTest, HtmlPopupOverlapsWithAutofillPopup) {
+  const internal::PopupWidgetProperties kBasePopup = {
+      .is_showing = true,
+      .is_html_form_popup = true,
+      .bounds = gfx::Rect(10, 10, 100, 100)};
+
+  // Empty list.
+  EXPECT_FALSE(internal::BoundsOverlapWithHtmlFormPopup(
+      gfx::Rect(50, 50, 100, 100), {}));
+
+  // Bounds overlap.
+  EXPECT_TRUE(internal::BoundsOverlapWithHtmlFormPopup(
+      gfx::Rect(50, 50, 100, 100), {kBasePopup}));
+
+  // Bounds do not overlap.
+  EXPECT_FALSE(internal::BoundsOverlapWithHtmlFormPopup(
+      gfx::Rect(200, 200, 100, 100), {kBasePopup}));
+
+  // View is not showing.
+  internal::PopupWidgetProperties hidden_popup = kBasePopup;
+  hidden_popup.is_showing = false;
+  EXPECT_FALSE(internal::BoundsOverlapWithHtmlFormPopup(
+      gfx::Rect(50, 50, 100, 100), {hidden_popup}));
+
+  // View is not an HTML form popup.
+  internal::PopupWidgetProperties non_html_popup = kBasePopup;
+  non_html_popup.is_html_form_popup = false;
+  EXPECT_FALSE(internal::BoundsOverlapWithHtmlFormPopup(
+      gfx::Rect(50, 50, 100, 100), {non_html_popup}));
+
+  // Multiple widgets: one non-overlapping, one overlapping.
+  internal::PopupWidgetProperties non_overlapping_popup = kBasePopup;
+  non_overlapping_popup.bounds = gfx::Rect(200, 200, 10, 10);
+  EXPECT_TRUE(internal::BoundsOverlapWithHtmlFormPopup(
+      gfx::Rect(50, 50, 100, 100), {non_overlapping_popup, kBasePopup}));
+}
+
 }  // namespace autofill
diff --git a/chrome/browser/ui/views/autofill/popup/popup_view_views.cc b/chrome/browser/ui/views/autofill/popup/popup_view_views.cc
index 76702aa..3f1d4c2 100644
--- a/chrome/browser/ui/views/autofill/popup/popup_view_views.cc
+++ b/chrome/browser/ui/views/autofill/popup/popup_view_views.cc
@@ -1345,6 +1345,15 @@
     return false;
   }
 
+  if (base::FeatureList::IsEnabled(
+          features::kAutofillPopupCheckHtmlFormPopupOverlap)) {
+    if (BoundsOverlapWithHtmlFormPopup(popup_bounds,
+                                       controller_->GetWebContents())) {
+      controller_->Hide(SuggestionHidingReason::kOverlappingWithAnotherPrompt);
+      return false;
+    }
+  }
+
   // The pip surface is given the most preference while rendering. So, the
   // autofill popup should not be shown when the picture in picture window
   // hides the autofill form behind it.
diff --git a/components/autofill/core/common/autofill_features.cc b/components/autofill/core/common/autofill_features.cc
index 3cde955..7ccffd3a 100644
--- a/components/autofill/core/common/autofill_features.cc
+++ b/components/autofill/core/common/autofill_features.cc
@@ -856,6 +856,12 @@
 BASE_FEATURE(kAutofillPolicyControlledFeatureManualText,
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+// If the feature is enabled, Autofill popups perform additional check to
+// detect if they are obscured by top-level HTML form popups (e.g color picker).
+// If so, Autofill Popup won't be shown.
+BASE_FEATURE(kAutofillPopupCheckHtmlFormPopupOverlap,
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 // If the feature is enabled, before triggering suggestion acceptance, the row
 // view checks that a substantial portion of its content was visible for some
 // minimum required period.
diff --git a/components/autofill/core/common/autofill_features.h b/components/autofill/core/common/autofill_features.h
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/chrome/browser/ui/views/autofill/popup/popup_view_utils_unittest.cc b/chrome/browser/ui/views/autofill/popup/popup_view_utils_unittest.cc
index bf7918b..981e6cd3 100644
--- a/chrome/browser/ui/views/autofill/popup/popup_view_utils_unittest.cc
+++ b/chrome/browser/ui/views/autofill/popup/popup_view_utils_unittest.cc
@@ -491,4 +491,41 @@
   }
 }
 
+TEST(PopupViewUtilsTest, HtmlPopupOverlapsWithAutofillPopup) {
+  const internal::PopupWidgetProperties kBasePopup = {
+      .is_showing = true,
+      .is_html_form_popup = true,
+      .bounds = gfx::Rect(10, 10, 100, 100)};
+
+  // Empty list.
+  EXPECT_FALSE(internal::BoundsOverlapWithHtmlFormPopup(
+      gfx::Rect(50, 50, 100, 100), {}));
+
+  // Bounds overlap.
+  EXPECT_TRUE(internal::BoundsOverlapWithHtmlFormPopup(
+      gfx::Rect(50, 50, 100, 100), {kBasePopup}));
+
+  // Bounds do not overlap.
+  EXPECT_FALSE(internal::BoundsOverlapWithHtmlFormPopup(
+      gfx::Rect(200, 200, 100, 100), {kBasePopup}));
+
+  // View is not showing.
+  internal::PopupWidgetProperties hidden_popup = kBasePopup;
+  hidden_popup.is_showing = false;
+  EXPECT_FALSE(internal::BoundsOverlapWithHtmlFormPopup(
+      gfx::Rect(50, 50, 100, 100), {hidden_popup}));
+
+  // View is not an HTML form popup.
+  internal::PopupWidgetProperties non_html_popup = kBasePopup;
+  non_html_popup.is_html_form_popup = false;
+  EXPECT_FALSE(internal::BoundsOverlapWithHtmlFormPopup(
+      gfx::Rect(50, 50, 100, 100), {non_html_popup}));
+
+  // Multiple widgets: one non-overlapping, one overlapping.
+  internal::PopupWidgetProperties non_overlapping_popup = kBasePopup;
+  non_overlapping_popup.bounds = gfx::Rect(200, 200, 10, 10);
+  EXPECT_TRUE(internal::BoundsOverlapWithHtmlFormPopup(
+      gfx::Rect(50, 50, 100, 100), {non_overlapping_popup, kBasePopup}));
+}
+
 }  // namespace autofill
Loading diff…

Original Bug Report

reported by [email protected]

Autofill prompt can be obscured by color picker

Steps to reproduce the problem

Similar to issue 415838602 and issue 339481295.

  1. Open repro.html
  2. Press down arrow key, then double press enter

Problem Description

Autofill prompt can be obscured by color picker

Summary

Autofill prompt can be obscured by color picker

Additional Data

Category: Security
Chrome Channel: Canary
Regression: N/A

View on issue tracker