Overview

High
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactUse after free in Views
DescriptionUse after free in Views
ComponentViews
Bug ClassUAF
Tracker535749174
Fix commitbab2ac4268d7 (chromium/src) +1/-1
CISA KEVNot listed
CreditedGoogle
Disclosed2026-08-06

Changed Functions

FunctionChangeNotes
if
chrome/browser/ui/views/toolbar/app_menu.cc
modified

Files Changed

  • chrome/browser/ui/views/toolbar/app_menu.cc
From bab2ac4268d7dfd0efc20fc6ae3a941b417c1a70 Mon Sep 17 00:00:00 2001
From: Emily Shack <[email protected]>
Date: Fri, 24 Jul 2026 10:29:00 -0700
Subject: [PATCH] Prevent a UAF in AppMenu::ZoomView

Reorders two calls to prevent a UAF on zoom_label_max_width_. ZoomView
logic should not be impacted by this reordering.

Bug: 535749174
Change-Id: Iaafdc0238690f8361156bcc3cf0136700481a7bd
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8137962
Commit-Queue: Emily Shack <[email protected]>
Reviewed-by: Allen Bauer <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1667971}
---

diff --git a/chrome/browser/ui/views/toolbar/app_menu.cc b/chrome/browser/ui/views/toolbar/app_menu.cc
index 58fd795..82231536 100644
--- a/chrome/browser/ui/views/toolbar/app_menu.cc
+++ b/chrome/browser/ui/views/toolbar/app_menu.cc
@@ -916,13 +916,13 @@
       decrement_button_->SetEnabled(zoom > contents->GetMinimumZoomPercent());
     }
     zoom_label_->SetText(base::FormatPercent(zoom));
+    zoom_label_max_width_.reset();
     if (!on_construction) {
       // An alert notification will ensure that the zoom label is always
       // announced even if is not focusable.
       zoom_label_->NotifyAccessibilityEventDeprecated(ax::mojom::Event::kAlert,
                                                       true);
     }
-    zoom_label_max_width_.reset();
   }
 
   void UpdateFullScreenButton() {
Loading diff…

Original Bug Report

reported by [email protected]

Potential UAF in AppMenu::ZoomView::UpdateZoomControls due to reentrant accessibility event

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 AppMenu::ZoomView::UpdateZoomControls because a synchronous platform accessibility alert is notified without a liveness guard. Reentrant UI events during synchronous event dispatch on Windows can trigger a menu teardown, causing subsequent heap operations on freed ZoomView and Label instances. This can lead to memory corruption in the unsandboxed browser process.

Affected files:

  • chrome/browser/ui/views/toolbar/app_menu.cc

Estimated timestamp from git blame: 2018-03-12

Root Cause Analysis

In AppMenu::ZoomView::UpdateZoomControls inside chrome/browser/ui/views/toolbar/app_menu.cc, the code fires a synchronous platform kAlert accessibility event. Immediately after this call, with no liveness or validity check on the view, it performs a write to an inline member variable zoom_label_max_width_:

// chrome/browser/ui/views/toolbar/app_menu.cc:906-926
void UpdateZoomControls(bool on_construction = false) {
  WebContents* contents = GetActiveWebContents();
  int zoom = 100;
  if (contents) {
    ...
    increment_button_->SetEnabled(zoom < contents->GetMaximumZoomPercent());
    decrement_button_->SetEnabled(zoom > contents->GetMinimumZoomPercent());
  }
  zoom_label_->SetText(base::FormatPercent(zoom));
  if (!on_construction) {
    // An alert notification will ensure that the zoom label is always
    // announced even if is not focusable.
    zoom_label_->NotifyAccessibilityEventDeprecated(ax::mojom::Event::kAlert,
                                                    true);          // Synchronous Event Call
  }
  zoom_label_max_width_.reset();                                    // Write to member of |this|
}

On Windows, zoom_label_->NotifyAccessibilityEventDeprecated(ax::mojom::Event::kAlert, true) triggers synchronous native UI Automation (UIA) and MSAA event firing (::NotifyWinEvent and ::UiaRaiseAutomationEvent in ui/accessibility/platform/ax_platform_node_win.cc).

Per ui/views/SECURITY.md, executing these synchronous COM/UIA calls invokes a nested Single-Threaded Apartment (STA) message pump. An active UIA client (such as a screen reader or assistive technology) can process this alert and reenter Chromium synchronously by invoking accessible actions.

Specifically, if the client queries the collapse pattern (IExpandCollapseProvider::Collapse) on the app menu button:

  1. The call enters BrowserAppMenuButton::HandleAccessibleAction with ax::mojom::Action::kCollapse.
  2. This invokes CloseMenu() and synchronously resets the unique pointer to AppMenu via menu_.reset().
  3. Synchronous menu runner cleanup (~MenuRunnerImpl) destroys the parent MenuItemView structure, which immediately deletes the ZoomView and its child zoom_label_ from the PartitionAlloc heap.

When control returns:

  1. Inside ViewAccessibility::NotifyEvent, view_->OnAccessibilityEvent(event_type) is called. Since view_ (zoom_label_) has been freed, this results in a virtual call Use-After-Free (UAF).
  2. Inside AppMenu::ZoomView::UpdateZoomControls, zoom_label_max_width_.reset() is called. Since this (ZoomView) has been freed, this writes a boolean flag to a fixed offset inside the freed PartitionAlloc slot.

Because these operations are performed via raw implicit this pointers and raw C++ object references, MiraclePtr (BackupRefPtr) does not offer protection.


Suggested/Potential Trigger Steps

Note: These steps are based on static code path analysis and have not been validated with a live proof-of-concept exploit.

  1. Run Chrome on Windows with an active UI Automation client or screen reader.
  2. Open the 3-dot App Menu.
  3. Click the ‘+’ or ‘−’ button in the Zoom row.
  4. During the synchronous UiaRaiseAutomationEvent inside NotifyAccessibilityEventDeprecated, the UIA client issues an IExpandCollapseProvider::Collapse call on the app menu button.
  5. BrowserAppMenuButton::HandleAccessibleAction(kCollapse) executes, calling CloseMenu(), which synchronously deletes the AppMenu, ZoomView, and zoom_label_.
  6. Upon return, the browser process accesses the freed zoom_label_ during OnAccessibilityEvent and writes to the freed ZoomView memory slot during zoom_label_max_width_.reset().

To prevent UAF from reentrant menu teardowns during accessibility events, wrap the synchronous event notification in a views::ViewTracker to verify if the view is still alive before executing any further operations.

void UpdateZoomControls(bool on_construction = false) {
  WebContents* contents = GetActiveWebContents();
  int zoom = 100;
  if (contents) {
    ...
    increment_button_->SetEnabled(zoom < contents->GetMaximumZoomPercent());
    decrement_button_->SetEnabled(zoom > contents->GetMinimumZoomPercent());
  }
  zoom_label_->SetText(base::FormatPercent(zoom));
  if (!on_construction) {
    views::ViewTracker tracker(this);
    zoom_label_->NotifyAccessibilityEventDeprecated(ax::mojom::Event::kAlert,
                                                    true);
    if (!tracker.view()) {
      return;
    }
  }
  zoom_label_max_width_.reset();
}

Evaluated with Chrome root at commit: b5b015ea5f690560237d1f0cff1405844cd12b8d


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