Overview

High
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactUse after free in Views
DescriptionUse after free in Views
ComponentViews
Bug ClassUAF
Tracker513208588
Fix commitd35c1b1b985e (chromium/src) +7/-4
CISA KEVNot listed
CreditedGoogle
Disclosed2026-05-27

Changed Functions

FunctionChangeNotes
if
ui/base/interaction/element_tracker.cc
modified

Files Changed

  • ui/base/interaction/element_tracker.cc
From d35c1b1b985ea1f464b496b46b348808e32153c3 Mon Sep 17 00:00:00 2001
From: Dana Fried <dfried@chromium.org>
Date: Tue, 19 May 2026 09:17:53 -0700
Subject: [PATCH] [Interaction] Use raw_ptr during all callbacks

This prevents a possible (but highly unlikely) UAF during certain
operations via a hard crash, which should indicate to the calling code
that it is doing something unsafe with the API.

Note that since CallbackList::Notify() is a variadic template function,
the raw_ptr is not unwrapped during that call, including the internal
loop over callbacks.

Bug: 513208588
Change-Id: I1833009714fb6bf782d0cee79be3160b0b3db4f4
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7857060
Commit-Queue: Dana Fried <dfried@chromium.org>
Commit-Queue: Foromo Daniel Soromou <koretadaniel@chromium.org>
Reviewed-by: Foromo Daniel Soromou <koretadaniel@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1632899}
---

diff --git a/ui/base/interaction/element_tracker.cc b/ui/base/interaction/element_tracker.cc
index 1f8f6b327..390a9df 100644
--- a/ui/base/interaction/element_tracker.cc
+++ b/ui/base/interaction/element_tracker.cc
@@ -93,7 +93,8 @@
     return custom_event_callbacks_.Add(callback);
   }
 
-  void NotifyElementShown(raw_ptr<TrackedElement, CtnExperimental>& element) {
+  void NotifyElementShown(
+      const raw_ptr<TrackedElement, CtnExperimental>& element) {
     DCHECK(element);
     DCHECK_EQ(identifier(), Unwrap(element->identifier()));
     // Zero context data is the "all contexts" entry and doesn't actually store
@@ -109,13 +110,14 @@
   }
 
   void NotifyElementActivated(
-      raw_ptr<TrackedElement, CtnExperimental>& element) {
+      const raw_ptr<TrackedElement, CtnExperimental>& element) {
     // Note: "All contexts" does not require the element to be present here.
     DCHECK(!context_ || element_lookup_.contains(element));
     activated_callbacks_.Notify(element);
   }
 
-  void NotifyElementHidden(TrackedElement* element) {
+  void NotifyElementHidden(
+      const raw_ptr<TrackedElement, CtnExperimental>& element) {
     if (context_) {
       const auto it = element_lookup_.find(element);
       CHECK(it != element_lookup_.end());
@@ -125,7 +127,8 @@
     hidden_callbacks_.Notify(element);
   }
 
-  void NotifyCustomEvent(TrackedElement* element) {
+  void NotifyCustomEvent(
+      const raw_ptr<TrackedElement, CtnExperimental>& element) {
     custom_event_callbacks_.Notify(element);
   }
 
Loading diff…

Original Bug Report

reported by vm...@google.com

Potential Browser-process UAF in ElementTracker::NotifyCustomEvent due to pointer snapshotting

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 without the Chrome Security team. 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 vulnerability exists in ui::ElementTracker where custom event notifications snapshot element pointers as bare pointers. This allows re-entrant destruction of an element to leave dangling pointers in active notification loops, bypassing internal safeguards and MiraclePtr mitigations.

Affected files:

  • ui/base/interaction/element_tracker.cc
  • ui/base/interaction/interaction_sequence.cc
  • components/user_education/webui/help_bubble_handler.cc

Estimated timestamp from git blame: 2023-06-24

Summary

A potential Use-After-Free (UAF) vulnerability has been identified in the ui::ElementTracker component. The issue stems from an inconsistency in how different event types handle element pointers during the notification process. While NotifyElementShown and NotifyElementActivated correctly pass references to raw_ptr to handle re-entrancy, NotifyCustomEvent snapshots the pointer as a bare C++ pointer before entering the notification loop. If a callback in the loop synchronously destroys the element, subsequent callbacks will be invoked with a dangling pointer.

Root Cause Analysis

ui::ElementTracker uses a notification_elements_ list of raw_ptr<TrackedElement> to protect elements currently undergoing notification. When NotifyElementHidden is called (due to an element being destroyed or hidden), it nulls out any matching entries in this list to prevent subsequent callbacks in an active loop from using the freed element.

In ui/base/interaction/element_tracker.cc, the methods for ‘Shown’ and ‘Activated’ events pass the element as a reference to a raw_ptr:

void NotifyElementShown(raw_ptr<TrackedElement, CtnExperimental>& element) {
  shown_callbacks_.Notify(element);
}

Because base::RepeatingCallbackList::Notify forwards this reference, the pointer is re-evaluated for each callback. If a re-entrant call nulls the raw_ptr, the remaining callbacks receive nullptr safely.

However, ElementData::NotifyCustomEvent (line 128) takes the pointer by value as a bare TrackedElement*:

void NotifyCustomEvent(TrackedElement* element) {
  custom_event_callbacks_.Notify(element);
}

When called from ElementTracker::NotifyCustomEvent (line 537), the raw_ptr& is converted to a bare pointer. This snapshots the address. If an early callback in the Notify() loop destroys the element, the re-entrancy protection in NotifyElementHidden will null the raw_ptr entry, but the local element variable in the Notify loop remains pointing to the now-freed memory.

Notably, since the raw_ptr is nulled before the object is actually freed, MiraclePtr (BackupRefPtr) may not quarantine the memory, as it believes no protected references remain.

Potential Impact and Reachability

An attacker who has compromised a renderer process (specifically the PDF extension renderer) can reach this logic via the PdfHelpBubbleHandlerFactory Mojo interface. By triggering a custom event on a TrackedElement and arranging for multiple subscribers (e.g., via an InteractionSequence or global listeners like CriticalUserJourneyService), the attacker can potentially cause a Use-After-Free in the unsandboxed browser process.

Dereferencing this dangling pointer—for instance, in the FilterCallback wrapper or during virtual method dispatch—could lead to arbitrary code execution in the browser process.

Suggested Attack Steps (Potential)

  1. From a compromised PDF-extension renderer, bind help_bubble::mojom::PdfHelpBubbleHandlerFactory and call CreateHelpBubbleHandler.
  2. Use TrackedElementVisibilityChanged to register an anchor element (e.g., kPdfInkSignaturesDrawElementId).
  3. Arrange for two or more subscribers to a custom event for that element.
  4. Trigger the custom event via TrackedElementCustomEvent in the Mojo interface.
  5. Ensure the first subscriber’s callback synchronously destroys the element (e.g., by closing the tab or navigating).
  6. The second subscriber will receive the snapshotted dangling pointer.

Change the signature of ElementData::NotifyCustomEvent to accept a reference to the raw_ptr instead of a bare pointer, ensuring it matches the pattern used by NotifyElementShown and NotifyElementActivated:

void NotifyCustomEvent(raw_ptr<TrackedElement, CtnExperimental>& element);

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