High watch CVSS 7.5 chrome UAF 📄 Reporter bug report 🔧 Commit mapped

Overview

High
Severity
7.5
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.
Tracker535749174
Fix commitbab2ac4268d7 (chromium/src) +1/-1
CWECWE-416 (Use-after-free)
CVSS vectorCVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:H
CISA KEVNot listed
CreditedGoogle
Reported2026-07-17 (per vendor advisory)
Fix landed2026-07-24 (public git)
Disclosed2026-08-06
Patch gap13 days — fix public in source before the advisory

Background

`AppMenu` / `ZoomView`
AppMenu is the browser’s three-dot menu, and ZoomView is the inline row inside it that holds the zoom -/+ buttons (decrement_button_), the percentage label zoom_label_ and the full-screen button.
`zoom_label_max_width_`
A cached width for the zoom label, held as a ZoomView member; .reset() clears it so that it is recalculated after the label text changes.
`NotifyAccessibilityEventDeprecated`
A views::View call that fires an accessibility event (here ax::mojom::Event::kAlert) synchronously into the accessibility system, so arbitrary observer code can run before it returns.
Re-entrancy UAF
A use-after-free in which a call made by an object runs code that destroys that same object, and the caller then touches its own members after the call returns.

Root Cause Analysis

The patched block lives in a ZoomView method that updates the zoom controls. The hunk does not show the method’s name, only that it takes an on_construction flag. The method sets zoom_label_ to the new percentage and, when not called during construction, fires a kAlert accessibility event on the label so screen readers announce the change. Before the patch, zoom_label_max_width_.reset() ran after NotifyAccessibilityEventDeprecated(). The commit identifies this as a UAF on zoom_label_max_width_, which means the ZoomView (or its owning menu) could be destroyed during the accessibility notification, and the later reset() would then write into freed memory. The commit does not say how the notification leads to destruction; synchronous accessibility dispatch causing the menu to close and tear down its views is the likely mechanism (inferred).

The fix moves zoom_label_max_width_.reset() before the notification, so the potentially re-entrant call is the last statement in the block and no member of this is accessed after it returns.

Key insight
A member of this (zoom_label_max_width_) was modified after a synchronous, potentially re-entrant accessibility notification that can free this. Reordering so all state updates happen before the notification removes the post-callback access.

Attack Path

  1. Open the app menu The user opens the browser’s AppMenu, which constructs a ZoomView; the initial update runs with on_construction true and skips the alert.
  2. Change zoom while the menu is open A later zoom change (e.g. pressing the menu’s +/- buttons) re-runs the update with on_construction false, setting zoom_label_ text and firing the kAlert accessibility event.
  3. Teardown during notification While the event is dispatched, other code destroys the ZoomView or its menu (inferred; the patch does not show what performs the deletion).
  4. Write to freed member Back in the pre-patch code, zoom_label_max_width_.reset() writes into the freed ZoomView, which is the use-after-free the advisory names.

Impact Assessment

The UAF is in the browser process’s Views UI, so heap corruption there would be outside the renderer sandbox. Turning a single std::optional-style reset of a freed object into code execution has not been demonstrated (inferred). Reaching the bug requires user interaction with the browser’s own app menu, specifically a zoom change while the menu is open. It also requires a condition that tears down the menu during the accessibility alert, which likely depends on accessibility clients being active or on a menu-closing race (inferred). Nothing in the diff shows ordinary web content triggering it on its own. The vendor advisory rates this high severity and does not report in-the-wild exploitation; NVD scores it CVSS 7.5.

Changed Functions

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

Files Changed

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

Audit Directions

  • Member access after synchronous notifications
    In chrome/browser/ui/views and ui/views, look for code that fires NotifyAccessibilityEvent*, observer callbacks or SetText/SetEnabled side effects and then keeps using this. Either move state updates before the callout or guard the access with a base::WeakPtr/ViewTracker.
  • Menu-hosted custom views
    Other custom rows in AppMenu and similar menus (e.g. the edit/cut-copy-paste row and extension menu rows) run while the menu can be closed asynchronously. Check their update paths for the same “notify, then touch members” ordering.
  • Cached layout state reset after events
    Audit patterns where cached sizes (*_max_width_, preferred-size caches) are invalidated after a notification rather than before it. These are easy to reorder without changing behaviour, as this fix did.
From bab2ac4268d7dfd0efc20fc6ae3a941b417c1a70 Mon Sep 17 00:00:00 2001
From: Emily Shack <emshack@chromium.org>
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 <emshack@chromium.org>
Reviewed-by: Allen Bauer <kylixrd@chromium.org>
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 vm...@google.com

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