CVE-2026-10003
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifui/views/widget/widget_delegate.cc |
modified | |
TabModalConfirmDialogViewsui/views/widget/widget_delegate.h |
modified | |
TestBaseWidgetDelegateui/views/widget/widget_delegate.h |
modified | |
UpdateRecommendedMessageBoxui/views/widget/widget_delegate.h |
modified | |
ViewTrackerui/views/widget/widget_delegate.h |
modified | |
WebDialogBrowserTestui/views/widget/widget_delegate.h |
modified |
Files Changed
ui/views/widget/widget_delegate.ccui/views/widget/widget_delegate.h
Patch
From 5c153abc2d8518e22f3c9de4f149dcfb7308bb6b Mon Sep 17 00:00:00 2001
From: Dana Fried <dfried@chromium.org>
Date: Wed, 20 May 2026 12:26:25 -0700
Subject: [PATCH] [Views] Prevent dangling focus preference
Widget keeps an optional pointer to its initially-focused view. This
should be robust to the view going away at some later point, not just
during teardown (where it's not safe either, but less likely to get
dereferenced).
This changes the optional<View*> to unique_ptr<ViewTracker>.
Unique pointer is used to avoid importing ViewTracker, ViewObserver,
etc. into the #includes of the delegate class, which is included in
many places (and because many widgets don't bother setting this
parameter, so there's no point in allocating additional memory unless
it's needed).
Fixed: 513609324
Change-Id: Id7c393894a1b1a21584c6e43720a5f94154dab04
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7864987
Reviewed-by: Keren Zhu <kerenzhu@chromium.org>
Commit-Queue: Keren Zhu <kerenzhu@chromium.org>
Commit-Queue: Dana Fried <dfried@chromium.org>
Auto-Submit: Dana Fried <dfried@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1633754}
---
diff --git a/ui/views/widget/widget_delegate.cc b/ui/views/widget/widget_delegate.cc
index 897ec458..f80ad158 100644
--- a/ui/views/widget/widget_delegate.cc
+++ b/ui/views/widget/widget_delegate.cc
@@ -18,6 +18,7 @@
#include "ui/display/screen.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/views/view.h"
+#include "ui/views/view_tracker.h"
#include "ui/views/views_delegate.h"
#include "ui/views/widget/widget.h"
#include "ui/views/window/client_view.h"
@@ -78,11 +79,12 @@
}
View* WidgetDelegate::GetInitiallyFocusedView() {
- return params_.initially_focused_view.value_or(nullptr);
+ return params_.initially_focused_view ? params_.initially_focused_view->view()
+ : nullptr;
}
bool WidgetDelegate::HasConfiguredInitiallyFocusedView() const {
- return params_.initially_focused_view.has_value();
+ return params_.initially_focused_view != nullptr;
}
BubbleDialogDelegate* WidgetDelegate::AsBubbleDialogDelegate() {
@@ -466,7 +468,10 @@
void WidgetDelegate::SetInitiallyFocusedView(View* initially_focused_view) {
DCHECK(!GetWidget());
- params_.initially_focused_view = initially_focused_view;
+ if (!params_.initially_focused_view) {
+ params_.initially_focused_view = std::make_unique<ViewTracker>();
+ }
+ params_.initially_focused_view->SetView(initially_focused_view);
}
void WidgetDelegate::SetModalType(ui::mojom::ModalType modal_type) {
diff --git a/ui/views/widget/widget_delegate.h b/ui/views/widget/widget_delegate.h
index 07ba390..cb2d7b2f 100644
--- a/ui/views/widget/widget_delegate.h
+++ b/ui/views/widget/widget_delegate.h
@@ -53,6 +53,7 @@
class TabModalConfirmDialogViews;
class TestBaseWidgetDelegate;
class UpdateRecommendedMessageBox;
+class ViewTracker;
class WebDialogBrowserTest;
FORWARD_DECLARE_TEST(AcceleratorCommandsFullscreenBrowserTest,
ToggleFullscreen);
@@ -322,7 +323,7 @@
// The widget's initially focused view, if any. This can only be set before
// this WidgetDelegate is used to initialize a Widget.
- std::optional<View*> initially_focused_view;
+ std::unique_ptr<ViewTracker> initially_focused_view;
// This is used by modal dialogs to override and constrain desired bounds
// calculations.
Original Bug Report
Browser-process Use-After-Free in BrowserFocusControllerDelegateViews
Project Fortify, an experimental security project, has identified the following potential security issue. If you’re a feature owner CC-ed on this bug, please do your best to review these reports. Please see https://chromium.googlesource.com/chromium/src/+/main/docs/security/ai-generated-security-bugs-faq.md for more information.
Overview: A potential Use-After-Free vulnerability exists in the browser process due to a dangling pointer in WidgetDelegate’s initially_focused_view. This occurs because the pointer is stored in an unprotected std::optional and is not cleared when the referenced View is destroyed. Triggering accessibility shortcuts like F6 or Alt+Shift+A can result in a virtual function call on freed memory.
Affected files:
chrome/browser/ui/focus/browser_focus_controller_delegate_views.ccui/views/widget/widget_delegate.hchrome/browser/ui/views/download/bubble/download_toolbar_ui_controller.ccui/views/widget/widget_delegate.ccui/views/window/dialog_delegate.cc
Estimated timestamp from git blame: Unknown (Google3 checkout)
Description
A potential Use-After-Free (UAF) vulnerability has been identified in the browser process, specifically within BrowserFocusControllerDelegateViews::ActivateFirstInactiveBubbleForAccessibility(). The issue stems from how WidgetDelegate manages its initially_focused_view pointer, which is used to determine focus when a bubble or dialog is activated for accessibility.
Root Cause Analysis
In ui/views/widget/widget_delegate.h, the initially_focused_view field is defined as:
std::optional<View*> initially_focused_view;
Because this pointer is wrapped in std::optional, it is not converted to raw_ptr<View> by Chromium’s automated rewriter and thus lacks MiraclePtr/BackupRefPtr protection. Furthermore, there is no mechanism (such as a ViewTracker or ViewObserver) to clear this pointer if the referenced View is destroyed during the lifetime of the delegate.
In the context of the Download Bubble, this field can be set to a child view (e.g., a button within a download row). If that download row is removed while the bubble remains open, the pointer becomes dangling.
Vulnerable Sink
The vulnerability is potentially triggered when a user presses the F6 (Rotate Pane Focus) or Alt+Shift+A (Focus Inactive Popup) keyboard shortcuts. The following code path in chrome/browser/ui/focus/browser_focus_controller_delegate_views.cc retrieves the dangling pointer and performs a virtual call:
// line 112
views::View* focusable = bubble->GetInitiallyFocusedView();
// ...
if (focusable) {
focusable->RequestFocus(); // Virtual call on potentially freed memory
}
Potential Attack Scenario
While these steps are theoretical and have not been validated by a running proof-of-concept, an attacker could potentially trigger the vulnerability as follows:
- Induce the browser to show the Download Bubble in an inactive state (e.g., by initiating multiple downloads from a site).
- Cause a specific download to be removed (e.g., via interaction in another tab or automated cleanup), which destroys the associated
Viewthat was captured as theinitially_focused_view. - The user, perhaps guided by a screen reader or keyboard navigation, presses F6 or Alt+Shift+A to focus the bubble.
- The system attempts to call
RequestFocus()on the dangling pointer, potentially allowing an attacker who has groomed the heap to gain arbitrary code execution in the unsandboxed browser process.
Suggested Fix
The initially_focused_view should be managed using a views::ViewTracker or a base::WeakPtr<views::View> to ensure the pointer is invalidated when the View is destroyed. Additionally, the kAnchoredDialogKey property should be audited to ensure it does not bypass modern memory safety protections.
Evaluated with Chrome root at commit: b3153093eb3c78c3e88ccf562bcbc20437a04b0e
Results so far have been promising, but there can be wrong deductions. Feel free to adjust as follows:
- If you are familiar with the severity guidelines, you may adjust the severity.
- If this is a false positive, and there’s no work to be done, please close as WAI.
- If there is work to do here but not a vulnerability, please change the issue type to Task/Bug/FR.
Data from false positives will be used to improve accuracy over time. And please feel free to reach out to me directly if you have concerns or feedback on the project.