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 <[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.
- 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