High watch ✔︎ verified CVSS 8.3 chrome UAF 📄 Reporter bug report 🔧 Commit mapped

Overview

High
Severity
8.3
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactUse after free in Passwords
DescriptionUse after free in Passwords
ComponentPasswords
Sub-componentPasswords
Bug ClassUAF
Action tierwatch — corruption primitive but gated (uncommon) — not default-reachable — factors set by independent review by AI
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.
Independent review by AIConfirmed
A second, independent AI reviewer (not a human) re-derived this analysis from the fixing commit and the vendor advisory, looking for errors.
Tracker513505608
Fix commit8112a56553fa (chromium/src) +20/-0
CWECWE-416 (Use-after-free)
CVSS vectorCVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:H/I:H/A:H
CISA KEVNot listed
CreditedGoogle
Reported2026-05-15 (per vendor advisory)
Fix landed2026-05-18 (public git)
Disclosed2026-05-27
Patch gap9 days — fix public in source before the advisory

Background

`PasswordGenerationPopupViewViews`
the Views implementation of Chrome’s password-generation popup, which owns child views such as the nudge buttons (password_generation_popup_view_views.cc:306).
`NudgePasswordButtons`
a child views::View holding the accept/cancel buttons of the generation nudge (password_generation_popup_view_views.cc:97).
`NotifyAXSelection`
a PopupBaseView method that fires native accessibility events for the currently selected view (popup_base_view.cc:363).
`views::ViewTracker`
a utility that holds a non-owning handle to a views::View and reports null once that view is destroyed.

Root Cause Analysis

PasswordGenerationPopupViewViews::ButtonSelectionUpdated caches a raw pointer to the nudge buttons by static_casting the nudge_password_buttons_view_ member at password_generation_popup_view_views.cc:366-367, then calls NotifyAXSelection(*nudge_password_buttons->GetAcceptButton()) or the cancel-button variant at :368-372, and finally dereferences the cached pointer with nudge_password_buttons->UpdateFocus(...) at :373. NotifyAXSelection fires native accessibility events (NotifyAccessibilityEventDeprecated(ax::mojom::Event::kMenuStart, ...) and kMenuPopupStart) at popup_base_view.cc:370-371 and then dereferences selected_view at :375. The invariant assumed by both functions is that the selected view and the nudge-buttons view remain alive across the accessibility-event call, but PasswordGenerationPopupViewViews::UpdateState (:343-348) sets nudge_password_buttons_view_ = nullptr and calls RemoveAllChildViews(), synchronously destroying those child views. If the accessibility-event firing re-enters and runs UpdateState, the cached nudge_password_buttons pointer and the selected_view reference become dangling, and the later UpdateFocus/SetPopupFocusOverride dereferences are use-after-free.

The fix wraps both sites in a views::ViewTracker (nudge_buttons_tracker, selected_view_tracker) and adds an early if (!tracker.view()) return; guard after the event call, so the stale pointers are never dereferenced once the view has been freed.

Key insight
The code dereferenced a view pointer/reference across a call (NotifyAXSelection) that can synchronously re-enter and destroy that view; the fix detects the destruction with a views::ViewTracker and bails out instead of touching freed memory.

Attack Path

  1. Show the generation popup Bring up the password-generation nudge so nudge_password_buttons_view_ is populated (password_generation_popup_view_views.cc:398-399).
  2. Select a button Cause ButtonSelectionUpdated to run, caching nudge_password_buttons and calling NotifyAXSelection (:366-372).
  3. Re-enter during AX firing With a native accessibility client active, the event fired at popup_base_view.cc:370-371 synchronously re-enters the browser thread. (inferred)
  4. Destroy the views The re-entrant work drives UpdateState, which nulls nudge_password_buttons_view_ and runs RemoveAllChildViews(), freeing the cached buttons view (:343-346).
  5. Use freed memory On return, nudge_password_buttons->UpdateFocus(...) (:373) / selected_view...SetPopupFocusOverride() (popup_base_view.cc:375) dereference the freed view.

Impact Assessment

An attacker who can drive popup state changes concurrently with accessibility-event firing can cause a use-after-free of popup child views in the unsandboxed browser process. The advisory rates this high severity and records no in-the-wild exploitation. Reaching the re-entrancy requires a native accessibility (UIA) client to be active, per the reporter’s description (inferred for the precise re-entrancy mechanism).

Changed Functions

FunctionChangeNotes
if
chrome/browser/ui/views/autofill/popup/popup_base_view.cc
modified

Files Changed

  • chrome/browser/ui/views/autofill/popup/popup_base_view.cc
  • chrome/browser/ui/views/passwords/password_generation_popup_view_views.cc

Audit Directions

  • Re-entrancy across accessibility events
    Treat any native accessibility event call (e.g. NotifyAccessibilityEventDeprecated, NotifyAXSelection) as a potential synchronous re-entry point and re-validate view lifetimes afterward.
  • Raw pointers cached across calls
    Audit UI code that caches a views::View* or reference and dereferences it after a callback; guard with views::ViewTracker/base::WeakPtr.
  • Synchronous state-reset paths
    Flag methods like UpdateState that call RemoveAllChildViews() and null member view pointers, and verify no in-flight caller holds those views.
From 8112a56553fa6c8213c80e3e18816dd11f5530cd Mon Sep 17 00:00:00 2001
From: Rafał Godlewski <[email protected]>
Date: Mon, 18 May 2026 04:04:35 -0700
Subject: [PATCH] [Passwords] Use view tracker for generation popup buttons

Ensures that the view, for which `NotifyAXSelection` was invoked, is
still alive after the call ends in both PasswordGenerationPopupViewViews
and PopupBaseView.

Fixed: 513505608
Change-Id: I466e4e748f1ba686d75f2eccf9a20c95a1472b82
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7852262
Reviewed-by: Vasilii Sukhanov <[email protected]>
Commit-Queue: Rafał Godlewski <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1632069}
---

diff --git a/chrome/browser/ui/views/autofill/popup/popup_base_view.cc b/chrome/browser/ui/views/autofill/popup/popup_base_view.cc
index 269b903..5efd1fde 100644
--- a/chrome/browser/ui/views/autofill/popup/popup_base_view.cc
+++ b/chrome/browser/ui/views/autofill/popup/popup_base_view.cc
@@ -48,6 +48,7 @@
 #include "ui/views/focus/focus_manager.h"
 #include "ui/views/layout/fill_layout.h"
 #include "ui/views/layout/layout_provider.h"
+#include "ui/views/view_tracker.h"
 #include "ui/views/widget/widget.h"
 
 #if DCHECK_IS_ON()
@@ -361,6 +362,7 @@
 }
 
 void PopupBaseView::NotifyAXSelection(views::View& selected_view) {
+  views::ViewTracker selected_view_tracker(&selected_view);
   if (!is_ax_menu_start_event_fired_) {
     // Fire the menu start event once, right before the first item is selected.
     // By firing these and the matching kMenuEnd events, we are telling screen
@@ -372,6 +374,15 @@
 
     is_ax_menu_start_event_fired_ = true;
   }
+
+  // Ensure the selected view was not destroyed, as e.g. firing native
+  // accessibility events on Windows can synchronously re-enter the browser
+  // thread and destroy the view.
+  // TODO(crbug.com/514228954): Consider removing accessibility event calls.
+  if (!selected_view_tracker.view()) {
+    return;
+  }
+
   selected_view.GetViewAccessibility().SetPopupFocusOverride();
 #if DCHECK_IS_ON()
   constexpr auto kDerivedClasses = base::MakeFixedFlatSet<std::string_view>(
diff --git a/chrome/browser/ui/views/passwords/password_generation_popup_view_views.cc b/chrome/browser/ui/views/passwords/password_generation_popup_view_views.cc
index d01d6ea0..279974d 100644
--- a/chrome/browser/ui/views/passwords/password_generation_popup_view_views.cc
+++ b/chrome/browser/ui/views/passwords/password_generation_popup_view_views.cc
@@ -41,6 +41,7 @@
 #include "ui/views/layout/box_layout.h"
 #include "ui/views/metadata/view_factory.h"
 #include "ui/views/vector_icons.h"
+#include "ui/views/view_tracker.h"
 #include "ui/views/widget/widget.h"
 
 namespace {
@@ -365,11 +366,19 @@
 
   auto* nudge_password_buttons =
       static_cast<NudgePasswordButtons*>(nudge_password_buttons_view_);
+  views::ViewTracker nudge_buttons_tracker(nudge_password_buttons);
+
   if (controller_->accept_button_selected()) {
     NotifyAXSelection(*nudge_password_buttons->GetAcceptButton());
   } else if (controller_->cancel_button_selected()) {
     NotifyAXSelection(*nudge_password_buttons->GetCancelButton());
   }
+
+  // Ensure the buttons were not destroyed during the NotifyAXSelection call.
+  if (!nudge_buttons_tracker.view()) {
+    return;
+  }
+
   nudge_password_buttons->UpdateFocus(controller_->accept_button_selected());
 }
 
Loading diff…

Original Bug Report

reported by [email protected]

Potential Browser-process UAF in PasswordGenerationPopupViewViews on Windows via UIA Re-entrancy

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 password generation popup on Windows. Synchronous re-entrancy during accessibility event firing allows a compromised renderer to trigger the destruction of the popup’s views while they are still being accessed by the browser process. This can lead to memory corruption or arbitrary code execution in the unsandboxed browser process.

Affected files:

  • chrome/browser/ui/views/passwords/password_generation_popup_view_views.cc
  • chrome/browser/ui/views/autofill/popup/popup_base_view.cc

Estimated timestamp from git blame: 2024-01-19

Root Cause Analysis

A potential Use-After-Free (UAF) vulnerability has been identified in PasswordGenerationPopupViewViews::ButtonSelectionUpdated on Windows. The issue stems from caching a raw pointer to a child view across a synchronous re-entrancy point triggered by Windows UI Automation (UIA).

In chrome/browser/ui/views/passwords/password_generation_popup_view_views.cc, the function ButtonSelectionUpdated caches a local pointer to nudge_password_buttons_view_ and calls NotifyAXSelection:

void PasswordGenerationPopupViewViews::ButtonSelectionUpdated() {
  // ...
  auto* nudge_password_buttons =
      static_cast<NudgePasswordButtons*>(nudge_password_buttons_view_);
  if (controller_->accept_button_selected()) {
    NotifyAXSelection(*nudge_password_buttons->GetAcceptButton()); // Re-entrancy point
  } else if (controller_->cancel_button_selected()) {
    NotifyAXSelection(*nudge_password_buttons->GetCancelButton());
  }
  nudge_password_buttons->UpdateFocus(controller_->accept_button_selected()); // Potential UAF
}

The call to NotifyAXSelection reaches PopupBaseView::NotifyAXSelection, which fires accessibility events (such as kMenuStart or kMenuPopupStart). On Windows, these events reach ::UiaRaiseAutomationEvent synchronously. When a UIA client (such as a screen reader) is active, this Windows API call can synchronously pump the message loop (STA pump).

If a compromised renderer has queued a Mojo message that triggers a state update in the popup (e.g., PasswordGenerationDriver::ShowPasswordEditingPopup), that message can be processed during this nested message loop. This results in a call to PasswordGenerationPopupViewViews::UpdateState(), which synchronously destroys the popup’s child views:

void PasswordGenerationPopupViewViews::UpdateState() {
  password_view_ = nullptr;
  nudge_password_buttons_view_ = nullptr; // Nulling member raw_ptr
  RemoveAllChildViews();                  // Synchronously deletes child views
  CreateLayoutAndChildren();
}

When the UIA pump returns, the original ButtonSelectionUpdated execution flow continues. The local pointer nudge_password_buttons now points to freed memory, and the subsequent call to UpdateFocus results in a Use-After-Free. Additionally, PopupBaseView::NotifyAXSelection may dereference a dangling reference to the selected_view after the re-entrant call returns.

MiraclePtr / BRP Protection

MiraclePtr (BRP) does not mitigate this issue because:

  1. The vulnerability involves a function-local raw pointer (nudge_password_buttons) and a reference (selected_view).
  2. The raw_ptr member nudge_password_buttons_view_ is explicitly set to nullptr in UpdateState() immediately before destruction, ensuring the object is not held in the quarantine when it is deleted.

Suggested Potential Reproduction Steps

  1. Ensure Windows is running with an active UIA client (e.g., Narrator).
  2. From a compromised renderer, trigger the password generation popup.
  3. Send a Mojo message to the browser process (e.g., ShowPasswordEditingPopup) that would trigger UpdateState().
  4. Trigger navigation within the popup (e.g., via a synthetic arrow key event) to cause ButtonSelectionUpdated to be called.
  5. Observe the browser process dereferencing the dangling pointer in ButtonSelectionUpdated after the synchronous accessibility event firing returns.

Fix Suggestion

Avoid using raw pointers to views across calls that can trigger synchronous re-entrancy. The ButtonSelectionUpdated function should either use base::WeakPtr to track the lifetime of the NudgePasswordButtons view or re-verify the validity of nudge_password_buttons_view_ after the call to NotifyAXSelection. More broadly, firing accessibility events on Windows should be evaluated for re-entrancy safety.

Evaluated with Chrome root at commit: b3153093eb3c78c3e88ccf562bcbc20437a04b0e


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