CVE-2025-3073
Overview
Background
- Autofill popup
- the suggestion dropdown Chrome renders over a web page’s form fields; its placement is validated so it does not overlap sensitive browser UI.
- PEPC (Page Embedded Permission Control)
- an embedded permission prompt element rendered by
EmbeddedPermissionPromptBaseView, distinct from the classic bubble permission prompt (PermissionPromptBubbleBaseView). - `ElementTrackerViews`
- a registry that maps a
ui::ElementIdentifier(such askMainViewId) to the currently visibleviews::View, used here to find a permission prompt view and test its screen bounds. - Overlap check
popup_view_utils.ccrefuses or repositions an Autofill popup whosescreen_boundsintersect a permission prompt, so Autofill suggestions cannot be drawn over a permission decision UI.
Root Cause Analysis
The overlap-detection helper (enclosing function not named in the hunk, in popup_view_utils.cc) only looked up PermissionPromptBubbleBaseView::kMainViewId when deciding whether the Autofill popup overlapped a permission prompt, and returned false (no overlap, popup allowed) if that specific bubble view was not present. It did not account for the newer embedded PEPC prompt (EmbeddedPermissionPromptBaseView::kMainViewId), so an Autofill popup could be placed overlapping a PEPC permission prompt while the check reported no conflict. This violates the invariant that Autofill suggestions must never overlay a permission prompt, since an overlay could obscure or spoof the permission decision (inferred).
The fix factors the lookup into a reusable BoundsOverlapWithView(screen_bounds, browser_view, view_id) helper and returns the logical OR of the overlap tests for both the bubble prompt and the PEPC prompt, so overlap with either prompt type now blocks the placement.
BoundsOverlapWithView and ORs in EmbeddedPermissionPromptBaseView::kMainViewId so either prompt type prevents an overlapping Autofill popup.Attack Path
- Trigger a PEPC prompt
A malicious page uses a page-embedded permission control so that an
EmbeddedPermissionPromptBaseViewpermission prompt is displayed. - Trigger the Autofill popup nearby
The page arranges a form field so that Chrome shows an Autofill suggestion popup whose
screen_boundsfall over the PEPC prompt. - Overlap check passes incorrectly
The pre-patch check only searches for
PermissionPromptBubbleBaseView::kMainViewId; finding no classic bubble, it returnsfalse, so Chrome does not treat the PEPC prompt as overlapped and allows the popup. - Popup overlays the permission UI The Autofill popup renders on top of the PEPC permission prompt, which can obscure or mislead the user about the permission being granted (inferred), the inappropriate implementation the advisory describes.
Impact Assessment
(inferred).Changed Functions
| Function | Change | Notes |
|---|---|---|
ifchrome/browser/ui/views/autofill/popup/popup_view_utils.cc |
modified |
Files Changed
chrome/browser/ui/views/autofill/popup/popup_view_utils.cc
Audit Directions
- Incomplete UI-surface enumerationLook for overlap/occlusion checks that enumerate a fixed list of security-sensitive views and may miss newer view types (embedded prompts, PiP windows, dialogs) added later.
- Popup-over-prompt protectionsAudit every place Autofill and other overlay popups are positioned to confirm they consult the full set of permission/consent surfaces, not just one prompt implementation.
- `ElementTrackerViews` lookups by single IDReview code that gates behavior on
GetFirstMatchingViewfor onekMainViewIdand returns “safe” when absent, since a sibling implementation with a different identifier may still be present.
Patch
From ba87ecce5f6c7c8f22331d3bc718b88232c96b8a Mon Sep 17 00:00:00 2001
From: Thomas Nguyen <tungnh@chromium.org>
Date: Mon, 17 Feb 2025 02:09:41 -0800
Subject: [PATCH] [PEPC] Don't show autofill overlaps with PEPC
Bug: 388680893
Change-Id: I96bb1e1e9fae5d5ef28f01f376e1826602509fc3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6268722
Commit-Queue: Thomas Nguyen <tungnh@chromium.org>
Reviewed-by: Mohamed Amir Yosef <mamir@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1420982}
---
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 7b8494fa..a5465fe 100644
--- a/chrome/browser/ui/views/autofill/popup/popup_view_utils.cc
+++ b/chrome/browser/ui/views/autofill/popup/popup_view_utils.cc
@@ -11,6 +11,7 @@
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/views/extensions/extension_popup.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
+#include "chrome/browser/ui/views/permissions/embedded_permission_prompt_base_view.h"
#include "chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.h"
#include "components/autofill/core/browser/suggestions/suggestion_type.h"
#include "components/autofill/core/browser/ui/popup_open_enums.h"
@@ -102,6 +103,18 @@
return {width, height};
}
+// Returns whether there is a visible view with `view_id` that overlaps
+// `screen_bounds`.
+bool BoundsOverlapWithView(const gfx::Rect& screen_bounds,
+ BrowserView* browser_view,
+ ui::ElementIdentifier view_id) {
+ auto* view_tracker = views::ElementTrackerViews::GetInstance();
+ views::View* view = view_tracker->GetFirstMatchingView(
+ view_id, view_tracker->GetContextForView(browser_view));
+ return view &&
+ view->GetWidget()->GetWindowBoundsInScreen().Intersects(screen_bounds);
+}
+
} // namespace
void CalculatePopupYAndHeight(int popup_preferred_height,
@@ -205,18 +218,10 @@
return false;
}
- views::View* const permission_bubble_view =
- views::ElementTrackerViews::GetInstance()->GetFirstMatchingView(
- PermissionPromptBubbleBaseView::kMainViewId,
- views::ElementTrackerViews::GetInstance()->GetContextForView(
- browser_view));
- if (!permission_bubble_view) {
- return false;
- }
-
- return permission_bubble_view->GetWidget()
- ->GetWindowBoundsInScreen()
- .Intersects(screen_bounds);
+ return BoundsOverlapWithView(screen_bounds, browser_view,
+ PermissionPromptBubbleBaseView::kMainViewId) ||
+ BoundsOverlapWithView(screen_bounds, browser_view,
+ EmbeddedPermissionPromptBaseView::kMainViewId);
}
bool BoundsOverlapWithPictureInPictureWindow(const gfx::Rect& screen_bounds) {