Overview

Critical
Severity
8.8
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactUse after free in Views
DescriptionUse after free in Views
ComponentViews
Bug ClassUAF
Action tierwatch — corruption primitive but gated (uncommon) — not default-reachable
Computed by PatchGap's deterministic exploitability ruler from the fixing commit. patch-now = RCE-class & attacker-reachable in a default config, or exploited in the wild; watch = real security signal below that bar; noise = no security relevance.
Tracker516962178
Fix commitb2d9af47f62b (chromium/src) +5/-1
CWECWE-416 (Use-after-free)
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
CISA KEVNot listed
CreditedGoogle
Reported2026-05-27 (per vendor advisory)
Fix landed2026-05-28 (public git)
Disclosed2026-06-30
Patch gap33 days — fix public in source before the advisory

Background

`MenuController`
the Views object that drives an open menu’s input and lifetime; its OnMousePressed() handler (named in the patch’s Subject: line, not in the @@ header) runs as a member method, so continued execution touches this.
`base::WeakPtr` / `AsWeakPtr()`
a weak reference to MenuController; after the pointee is destroyed the WeakPtr evaluates to false, letting a method detect that its own this was freed mid-call.
`SetHotTrackedButton()`
sets the newly hot-tracked Button and fires an accessibility notification for it; per the commit message, a11y tools can respond by signaling the menu to close, which destroys the MenuController.
Reentrant destruction
the pattern where a synchronous callback invoked deep inside a method deletes the very object whose method is still on the stack, so any later member access is a use-after-free.

Root Cause Analysis

Inside OnMousePressed(), when the pointed-at Button differs from hot_button_, the code calls SetHotTrackedButton(button), which emits an accessibility notification for the freshly hot-tracked button. As the commit message states, a11y tooling can react to that notification by closing the menu, which synchronously destroys the MenuController while OnMousePressed() is still executing. Before the patch, the method’s WeakPtr self-check (base::WeakPtr<MenuController> this_ref = AsWeakPtr();) was captured only later, inside the if (!IsViewClass<EmptyMenuMenuItem>(view)) block guarding ProcessMousePressed, so nothing detected destruction that happened during SetHotTrackedButton(); execution fell through and kept operating on the freed this.

The fix hoists the capture to auto this_ref = AsWeakPtr(); before the SetHotTrackedButton() call and adds if (!this_ref) { return true; } immediately after it, so a menu closed during hot-track notification causes an early, safe return instead of dereferencing freed memory. This works because the guard runs before any subsequent member use, and the previously redundant inner this_ref declaration is removed since the hoisted one now covers the later ProcessMousePressed path as well.

Key insight
The single mistake was capturing the reentrancy self-check WeakPtr too late — after SetHotTrackedButton() rather than before it — leaving the window in which an accessibility-triggered menu close frees MenuController unguarded; the fix moves the capture earlier and adds an immediate if (!this_ref) return true; bailout.

Attack Path

  1. Open a menu with a11y observing With an accessibility tool active (that reacts to hot-track notifications), the user or attacker-influenced input opens a Views menu managed by MenuController.
  2. Trigger a hot-track change on mouse press A mouse press lands over a button such that hot_button_ != button, so OnMousePressed() enters the branch calling SetHotTrackedButton(button).
  3. Reentrantly destroy the controller The accessibility notification fired for the newly hot-tracked button causes the a11y tooling to signal the menu to close, synchronously destroying the MenuController while OnMousePressed() is still on the stack.
  4. Use the freed `this` Pre-patch, control returns from SetHotTrackedButton() and continues executing OnMousePressed() on the now-freed MenuController, accessing freed member state (use-after-free).
  5. Escalate via the freed allocation Grooming the freed MenuController allocation to gain a controlled read/write or control-flow primitive, and any further escalation to code execution, is (inferred); the diff shows only the reentrant UAF, not a concrete sink or primitive.

Impact Assessment

An attacker gains a use-after-free of a MenuController in the browser process, reachable when an accessibility tool is active and reacts to hot-track notifications by closing the menu during a mouse press. The vendor advisory rates this critical severity and does not report in-the-wild exploitation; NVD scores it CVSS 8.8. Turning the freed-object access into a controlled memory-corruption primitive or code execution is (inferred) and not demonstrated by the patch itself.

Changed Functions

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

Files Changed

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

Audit Directions

  • Callback-before-self-check ordering
    Look for methods that capture an AsWeakPtr()/weak_ptr guard after a call that can synchronously destroy this (notifications, observer callbacks, Process* handlers); the guard must be captured and checked before the first such call.
  • Accessibility-notification reentrancy
    Audit other Views input handlers (e.g., mouse/key/gesture paths in MenuController and related controls) that emit a11y notifications like SetHotTrackedButton(), since those can reenter and close/destroy the owning object mid-handler.
  • Fall-through after risky calls
    Flag handlers that continue touching member state after invoking code that “may close the menu”/destroy the object (as the removed comment warns) without an intervening liveness check on every such path.
From b2d9af47f62bf666797d3dc5a3383331a3bb62b9 Mon Sep 17 00:00:00 2001
From: Allen Bauer <kylixrd@chromium.org>
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 <kylixrd@chromium.org>
Commit-Queue: Allen Bauer <kylixrd@chromium.org>
Reviewed-by: David Yeung <dayeung@chromium.org>
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 vm...@google.com

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