Overview

Critical
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactUse after free in Views
DescriptionUse after free in Views
ComponentViews
Bug ClassUAF
Tracker516962178
Fix commitb2d9af47f62b (chromium/src) +5/-1
CISA KEVNot listed
CreditedGoogle
Disclosed2026-06-30

Changed Functions

FunctionChangeNotes
if
ui/views/controls/menu/menu_controller.cc
modified

Files Changed

  • ui/views/controls/menu/menu_controller.cc
From b2d9af47f62bf666797d3dc5a3383331a3bb62b9 Mon Sep 17 00:00:00 2001
From: Allen Bauer <[email protected]>
Date: Thu, 28 May 2026 12:35:18 -0700
Subject: [PATCH] Added additional `this` tracking in MenuController:OnMousePressed().

Guards against a11y tools signaling the menu to close during the
notification of the newly hot-tracked button.

Change-Id: Ida8121655c53bc1c4f59c0aaf9a25226ee73c40a
Bug: 516962178
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7882246
Auto-Submit: Allen Bauer <[email protected]>
Commit-Queue: Allen Bauer <[email protected]>
Reviewed-by: David Yeung <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1637875}
---

diff --git a/ui/views/controls/menu/menu_controller.cc b/ui/views/controls/menu/menu_controller.cc
index 10649a65..00f21ac 100644
--- a/ui/views/controls/menu/menu_controller.cc
+++ b/ui/views/controls/menu/menu_controller.cc
@@ -907,13 +907,17 @@
     View* view =
         forward_to_root->GetEventHandlerForPoint(event_for_root.location());
     Button* button = Button::AsButton(view);
+    auto this_ref = AsWeakPtr();
     if (hot_button_ != button) {
       SetHotTrackedButton(button);
     }
 
+    if (!this_ref) {
+      return true;
+    }
+
     // Empty menu items are always handled by the menu controller.
     if (!IsViewClass<EmptyMenuMenuItem>(view)) {
-      base::WeakPtr<MenuController> this_ref = AsWeakPtr();
       bool processed = forward_to_root->ProcessMousePressed(event_for_root);
       // This object may be destroyed as a result of a mouse press event (some
       // item may close the menu).
Loading diff…

Original Bug Report

reported by [email protected]

Potential UAF in MenuController::OnMousePressed due to synchronous deletion in SetHotTrackedButton

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 (UAF) vulnerability exists in the browser process inside MenuController::OnMousePressed. A call to SetHotTrackedButton can trigger synchronous menu deletion via platform-specific accessibility events before a safeguarding weak pointer is captured. This leads to subsequent operations, including a virtual method call on a stack raw pointer, executing on freed memory.

Affected files:

  • ui/views/controls/menu/menu_controller.cc

Estimated timestamp from git blame: 2016-03-24

Summary

A potential Use-After-Free (UAF) vulnerability has been identified in the browser process inside MenuController::OnMousePressed (located in ui/views/controls/menu/menu_controller.cc).

When a mouse press event targets a different button inside a menu, the controller invokes SetHotTrackedButton. However, this call occurs before the safeguarding AsWeakPtr() reference (this_ref) is established. Because SetHotTrackedButton dispatches synchronous accessibility events that can cause the menu widget and the controller to be deleted, returning from this call can result in executing subsequent code (including a virtual method call and a heap write) on freed memory.

Vulnerability Analysis

In ui/views/controls/menu/menu_controller.cc, inside MenuController::OnMousePressed:

    Button* button = Button::AsButton(view);
    if (hot_button_ != button) {
      SetHotTrackedButton(button);                                         // Line 911
    }

    // Empty menu items are always handled by the menu controller.
    if (!IsViewClass<EmptyMenuMenuItem>(view)) {                           // Line 915 - Potential UAF read
      base::WeakPtr<MenuController> this_ref = AsWeakPtr();                // Line 916 - Potential UAF read
      bool processed = forward_to_root->ProcessMousePressed(event_for_root); // Line 917 - Potential UAF virtual call
      if (!this_ref) {
        return true;
      }
  1. At line 911, the controller calls SetHotTrackedButton(button) to update the hot-tracked button.
  2. Within SetHotTrackedButton (line 3796), an accessibility event is synchronously fired at line 3825:
    hot_button_->NotifyAccessibilityEventDeprecated(ax::mojom::Event::kSelection, true);
    
  3. This notification is synchronously dispatched through platform-specific accessibility channels (e.g., using AppKit’s NSAccessibilityPostNotification on macOS, or GLib’s g_signal_emit_by_name on Linux).
  4. An external accessibility listener or client reacting to this event can synchronously trigger actions that close or dismiss the menu (e.g., destroying the widget or window).
  5. This synchronous destruction deletes the MenuController and its associated view hierarchy (including the target view and the root view forward_to_root).
  6. Once SetHotTrackedButton returns, the execution flow in OnMousePressed continues:
    • Line 915: IsViewClass<EmptyMenuMenuItem>(view) checks if the now-freed view is an empty menu item (UAF read).
    • Line 916: AsWeakPtr() is called on the deleted MenuController (this), resulting in accessing the freed weak_ptr_factory_ member (UAF read).
    • Line 917: forward_to_root->ProcessMousePressed(...) executes a virtual method call on the freed MenuHostRootView (UAF virtual call). Since forward_to_root is a stack-allocated raw pointer, it is not protected by MiraclePtr/BackupRefPtr, which could allow a virtual table hijack if the heap is groomed.
    • Line 927: current_mouse_event_target_ = forward_to_root writes to a member of the deleted this, causing a UAF heap write.

Potential Attack Steps

Please note: Since our static-analysis tooling does not have the capability to execute code or run test cases, these are potential/suggested steps to reproduce the vulnerability based on code review.

  1. Enable system-level accessibility features (or a screen reader) to ensure platform-specific synchronous accessibility events are active.
  2. Open any Views-based menu containing clickable button elements (e.g., zoom/controls inside the application menu).
  3. Trigger a mouse-press event on a non-hot-tracked button inside the menu.
  4. Ensure the resulting accessibility selection notification (ax::mojom::Event::kSelection) triggers a synchronous callback that dismisses the menu widget (such as by simulating a focus-shift or window state change inside the accessibility handler).
  5. Observe if returning from SetHotTrackedButton triggers a crash due to UAF reads/writes in OnMousePressed.

Suggested Fix

To resolve this issue, the AsWeakPtr() reference must be acquired before SetHotTrackedButton is called, and checked immediately after.

--- ui/views/controls/menu/menu_controller.cc
+++ ui/views/controls/menu/menu_controller.cc
@@ -907,11 +907,15 @@
     View* view =
         forward_to_root->GetEventHandlerForPoint(event_for_root.location());
     Button* button = Button::AsButton(view);
+    base::WeakPtr<MenuController> this_ref = AsWeakPtr();
     if (hot_button_ != button) {
       SetHotTrackedButton(button);
     }
 
+    if (!this_ref) {
+      return true;
+    }
+
     // Empty menu items are always handled by the menu controller.
     if (!IsViewClass<EmptyMenuMenuItem>(view)) {
-      base::WeakPtr<MenuController> this_ref = AsWeakPtr();
       bool processed = forward_to_root->ProcessMousePressed(event_for_root);

Evaluated with Chrome root at commit: b1520ef4a76878853a31f0943b565e42060edec8


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.

View on issue tracker