CVE-2026-19159
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
forui/views/controls/menu/menu_item_view.cc |
modified | |
ifui/views/controls/menu/menu_item_view.cc |
modified |
Files Changed
ui/views/controls/menu/menu_item_view.cc
Patch
From 355923849eca301965e0ce42a54d11308cd964a1 Mon Sep 17 00:00:00 2001
From: Dana Fried <dfried@chromium.org>
Date: Wed, 22 Jul 2026 07:53:13 -0700
Subject: [PATCH] [Menus, Views] Avoid potential UAF due to self-deletion.
Bug: 536067175
Change-Id: I107f88d2fc29a7cb5f936936acf3698b553b3af1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8127481
Reviewed-by: Dmytro Yeroshkin <yeroshkin@chromium.org>
Commit-Queue: Dmytro Yeroshkin <yeroshkin@chromium.org>
Auto-Submit: Dana Fried <dfried@chromium.org>
Commit-Queue: Dana Fried <dfried@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1666289}
---
diff --git a/ui/views/controls/menu/menu_item_view.cc b/ui/views/controls/menu/menu_item_view.cc
index 00a60ca..ee30f96d 100644
--- a/ui/views/controls/menu/menu_item_view.cc
+++ b/ui/views/controls/menu/menu_item_view.cc
@@ -64,6 +64,7 @@
#include "ui/views/style/typography_provider.h"
#include "ui/views/vector_icons.h"
#include "ui/views/view_class_properties.h"
+#include "ui/views/view_tracker.h"
#include "ui/views/view_utils.h"
#include "ui/views/widget/widget.h"
@@ -1070,20 +1071,30 @@
// visible items. Copy the children, since we may mutate them as we go.
const Views children = submenu_->children();
bool has_visible_menu_items = false;
+
+ // Making changes to selection, etc. can cause `this` to be deleted. Track the
+ // continued existence of this object while updating.
+ ViewTracker tracker(this);
+
for (View* child : children) {
MenuItemView* const child_menu = AsViewClass<MenuItemView>(child);
if (!child_menu) {
continue;
}
if (IsViewClass<EmptyMenuMenuItem>(child)) {
+ const bool selected = child_menu->IsSelected();
// Prevent view destruction until selection is updated.
// We remove the child before updating selection in case of re-entrancy.
std::unique_ptr<View> removed_child = submenu_->RemoveChildViewT(child);
- if (child_menu->IsSelected()) {
+ if (tracker && selected) {
// Update selection to this menu before deleting the currently
// selected child.
GetMenuController()->SetSelection(
this, MenuController::SELECTION_UPDATE_IMMEDIATELY);
+ // This can also delete `this`, so check for that.
+ if (!tracker) {
+ return;
+ }
}
submenu_
->InvalidateLayout(); // Ideally the submenu would have a layout
Original Bug Report
Potential Use-After-Free in MenuItemView::UpdateEmptyMenusAndMetrics via SetSelection Reentrancy
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 browser-process Use-After-Free (UAF) memory safety vulnerability exists in MenuItemView::UpdateEmptyMenusAndMetrics. Synchronous platform accessibility notifications triggered during MenuController::SetSelection can synchronously delete the parent MenuItemView tree. When execution resumes, accessing the unique_ptr member submenu_ of the freed MenuItemView instance leads to a heap Use-After-Free sink.
Affected files:
ui/views/controls/menu/menu_item_view.cc
Estimated timestamp from git blame: 2025-01-27
Summary
A potential heap Use-After-Free (UAF) memory safety issue exists in MenuItemView::UpdateEmptyMenusAndMetrics inside the browser process. This is caused by executing synchronous layout and sizing logic on the unique_ptr member submenu_ of a freed MenuItemView immediately after invoking MenuController::SetSelection with SELECTION_UPDATE_IMMEDIATELY, which can synchronously delete this due to platform accessibility re-entrancy.
Vulnerability Details
Inside ui/views/controls/menu/menu_item_view.cc:1060, UpdateEmptyMenusAndMetrics() executes a loop that modifies the children of a submenu:
// ui/views/controls/menu/menu_item_view.cc:1060-1098
void MenuItemView::UpdateEmptyMenusAndMetrics() {
CHECK(HasSubmenu());
const Views children = submenu_->children();
bool has_visible_menu_items = false;
for (View* child : children) {
MenuItemView* const child_menu = AsViewClass<MenuItemView>(child);
...
if (IsViewClass<EmptyMenuMenuItem>(child)) {
std::unique_ptr<View> removed_child = submenu_->RemoveChildViewT(child);
if (child_menu->IsSelected()) {
GetMenuController()->SetSelection(
this, MenuController::SELECTION_UPDATE_IMMEDIATELY); // <-- Can trigger synchronous deletion of `this`
}
submenu_
->InvalidateLayout(); // <-- UAF: Access of `this->submenu_` after `this` is freed
}
...
}
...
submenu_->UpdateMenuPartSizes(); // <-- UAF: Always reached
}
If the placeholder EmptyMenuMenuItem is currently selected, calling SetSelection fires multiple synchronous platform accessibility events (via SetHotTrackedButton(nullptr) or SetPopupFocusOverride()). When assistive technologies or screen readers are active (native platform accessibility is enabled on the browser UI thread), the platform COM or AT event loops can synchronously re-enter the Chromium UI thread and request the menu tree be closed/destroyed.
This re-entrant path executes MenuRunnerImpl::Release() setting delete_after_run_ = true, which ultimately deletes the MenuController and performs delete this; on the MenuRunnerImpl itself (see ui/views/controls/menu/menu_runner_impl.cc:235-247). Deleting MenuRunnerImpl destructs its owned menu_ (which is the root MenuItemView), resulting in cascading destruction that deletes the parent MenuItemView on which UpdateEmptyMenusAndMetrics is running.
When execution control resumes and returns from SetSelection, UpdateEmptyMenusAndMetrics immediately dereferences this->submenu_ to call InvalidateLayout(). Because submenu_ is stored as std::unique_ptr<SubmenuView> (not raw_ptr<>), it is not protected by MiraclePtr and can be loaded from a freed (or potentially attacker-reclaimed) memory region, causing a browser-process control flow hijack through subsequent virtual function calls (e.g. GetLayoutManager()->InvalidateLayout()).
Potential Attack Vector / Reproduction Flow
- The user launches Chromium with native platform accessibility active (e.g., NVDA, Microsoft Narrator, or Orca screen reader running).
- The user opens an empty nested submenu (which displays the selected
(empty)placeholder item). - Web content triggers a dynamic menu model mutation (e.g., using
history.pushState()to fire aNavigationEntryCommittednavigation on a back/forward long-press model, or modifying an observed bookmark structure via extensions). - This invokes
OnMenuStructureChanged(), triggeringChildrenChanged()and subsequentlyUpdateEmptyMenusAndMetrics()on the active submenu item. - During the placeholder removal,
SetSelection(this, SELECTION_UPDATE_IMMEDIATELY)is invoked, triggering synchronous re-entrancy and closing the menu. - Both the
MenuControllerandMenuItemViewtree are deleted on the stack. - When
SetSelectionreturns, the execution flow reaches the UAF sinksubmenu_->InvalidateLayout(), causing memory corruption.
Note: These steps are based on static analysis and automated verification of the Chromium views lifecycle, as our tooling cannot run or compile production binaries dynamically.
Suggested Fix
To resolve this issue, the execution lifetime of the MenuItemView needs to be safely guarded. The safest approach is to use a views::ViewTracker to track the liveness of this across the call to SetSelection:
if (child_menu->IsSelected()) {
views::ViewTracker tracker(this);
GetMenuController()->SetSelection(
this, MenuController::SELECTION_UPDATE_IMMEDIATELY);
if (!tracker.view()) {
return;
}
}
Evaluated with Chrome root at commit: bf775e5d75cb9e1767e2cd02cc93efa0077d14a5
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.