Chrome · Autofill
CVE-2026-13860
Logic Error in Autofill
Overview
Medium
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
TESTchrome/browser/ui/views/autofill/popup/popup_view_utils_unittest.cc |
modified |
Files Changed
chrome/browser/ui/views/autofill/popup/popup_view_utils.ccchrome/browser/ui/views/autofill/popup/popup_view_utils.hchrome/browser/ui/views/autofill/popup/popup_view_utils_unittest.ccchrome/browser/ui/views/autofill/popup/popup_view_views.cccomponents/autofill/core/common/autofill_features.cc
Patch
From 51fa5641e7d83003604a65a8810c329e252bc529 Mon Sep 17 00:00:00 2001
From: Mikita Kuchyn <kuchyn@google.com>
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 <schwering@google.com>
Reviewed-by: Keren Zhu <kerenzhu@chromium.org>
Commit-Queue: Mikita Kuchyn <kuchyn@chromium.org>
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 ch...@gmail.com
Autofill prompt can be obscured by color picker
Steps to reproduce the problem
Similar to issue 415838602 and issue 339481295.
- Open repro.html
- 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
References
On This Page