CVE-2026-79052
Overview
Background
- `WindowEventDispatcher`
- The Aura component that routes input events to windows and lives alongside the
WindowTreeHostthat owns the root window. - `OnWindowHidden`
- A
WindowEventDispatchermethod that tears down dispatch and gesture state when a window becomes invisible, and may synchronously run code that destroys other windows. - `ScopedDeleteBlocker`
- An
aura::WindowRAII guard that pins a window alive for its lexical scope, preventing that window from being deleted until the guard is destroyed. - `WindowTreeHost`
- The host object that owns the root window (
host_->window()) and the dispatcher itself, so destroying the root window destroys the dispatcher too.
Root Cause Analysis
Verify before building a PoC
What the commit does not establish: Blocker is added after old_dispatch_target_ is cleared, not at the block top; re-entrancy is from gesture cleanup only. Commit says scenario 'should never happen'; web reachability, default preconditions and code-execution impact are unsupported by diff/advisory.
WindowEventDispatcher::OnWindowHidden runs cleanup logic — clearing old_dispatch_target_ and unwinding gesture state — while a window is being hidden. This cleanup can synchronously re-enter application and observer code (for example, gesture-state teardown that “may end up destroying the hidden window”), and in the buggy scenario that re-entrancy can cascade all the way up to destroying the root window owned by host_. Because the root window’s destruction also destroys its WindowTreeHost and therefore the very WindowEventDispatcher executing OnWindowHidden, the method continues touching this and host_ after they have been freed, yielding a use-after-free. The invariant violated is that OnWindowHidden implicitly assumes the dispatcher and its host root window outlive the method’s own body.
The fix constructs an aura::Window::ScopedDeleteBlocker blocker(host_->window()) at the top of the affected block, pinning the root window (and transitively the host and dispatcher) alive until the method returns, so any re-entrant attempt to delete the root window is deferred past the point where this is still in use.
OnWindowHidden re-enters window-destruction code that can free the dispatcher’s own root window — and thus this — mid-method; the fix blocks root-window deletion for the method’s duration with a ScopedDeleteBlocker, guaranteeing the dispatcher survives its own cleanup.Attack Path
- Trigger a hide
The attacker drives page or UI state (via script-controlled navigation, focus, or window changes) that causes an Aura window to be hidden, invoking
WindowEventDispatcher::OnWindowHidden. - Re-enter during cleanup Inside the method, gesture-state cleanup runs application/observer callbacks synchronously, as the code notes it “may end up destroying the hidden window.”
- Cascade to the root window
The attacker arranges the callback chain so this teardown destroys the root window owned by
host_, which also tears down theWindowTreeHostand the executingWindowEventDispatcher. - Use freed dispatcher
Control returns into the remainder of
OnWindowHidden, which dereferences the now-freedthisandhost_, causing a use-after-free. - Exploit the dangling state By shaping heap reallocation between the free and the subsequent dereference, the attacker corrupts controlled memory to escalate toward code execution.
Impact Assessment
WindowEventDispatcher/WindowTreeHost objects, which run in the privileged browser process. Successful exploitation lets them read or write freed heap memory and potentially achieve code execution outside the renderer sandbox. The precondition is reaching the re-entrant root-window-destruction scenario during OnWindowHidden, which the patch author notes “should never happen” but is nonetheless reachable.Files Changed
ui/aura/window_event_dispatcher.cc
Audit Directions
- Re-entrant self-destructionLook for methods that run observer or application callbacks capable of destroying the object’s own owner (
host_, parent, or root window) while continuing to usethisafterward. - Missing scoped guardsAudit
WindowEventDispatcherand other Aura teardown paths for cleanup blocks that lack aScopedDeleteBlockeror weak-pointer check around code that “may destroy” windows. - Root-window lifetime assumptionsSearch for code that dereferences
host_->window()or the dispatcher after synchronous teardown steps, where the root window’s continued existence is assumed rather than enforced.
Patch
From 7b842f1861b4deb1e1138eca555f56338d23b41c Mon Sep 17 00:00:00 2001 From: Mitsuru Oshima <[email protected]> Date: Mon, 20 Jul 2026 18:54:20 -0700 Subject: [PATCH] Block the deletion of root window in OnWindowHidden The scenario in the bug should never happen. (It would cause a lot of other types of problems) Fixed: 517518019 Change-Id: I5610b3b2366746a1c8511f029444f809eb5a5d39 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8126836 Reviewed-by: Achuith Bhandarkar <[email protected]> Commit-Queue: Mitsuru Oshima <[email protected]> Cr-Commit-Position: refs/heads/main@{#1665117} --- diff --git a/ui/aura/window_event_dispatcher.cc b/ui/aura/window_event_dispatcher.cc index 002e39e2..35fd163f 100644 --- a/ui/aura/window_event_dispatcher.cc +++ b/ui/aura/window_event_dispatcher.cc @@ -379,6 +379,9 @@ if (invisible->Contains(old_dispatch_target_)) old_dispatch_target_ = nullptr; + // Block the deletion of the root window, its host thus this dispatcher. + aura::Window::ScopedDeleteBlocker blocker(host_->window()); + // Cleaning up gesture state may end up destroying the hidden window. We use a // weak pointer to detect this. base::WeakPtr<aura::Window> invisible_weak = invisible->GetWeakPtrAsWindow();
Original Bug Report
Potential Use-After-Free in WindowEventDispatcher::OnWindowHidden via reentrant destruction
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 has been identified in the browser process within WindowEventDispatcher::OnWindowHidden. Synchronous gesture cleanup can trigger a nested event loop that synchronously destroys the dispatcher, leading to a UAF when member variables are accessed after the reentrant call returns.
Affected files:
ui/aura/window_event_dispatcher.cc
Estimated timestamp from git blame: 2013-11-26
Description
A potential Use-After-Free (UAF) vulnerability exists in ui/aura/window_event_dispatcher.cc. The function WindowEventDispatcher::OnWindowHidden invokes invisible->CleanupGestureState(). While it guards the target window with a weak pointer (invisible_weak), it lacks any self-liveness check or weak pointer guard for the WindowEventDispatcher instance itself (this).
// ui/aura/window_event_dispatcher.cc
base::WeakPtr<aura::Window> invisible_weak = invisible->GetWeakPtrAsWindow();
invisible->CleanupGestureState(); // <--- Re-enters and can synchronously free 'this'
if (reason != WINDOW_MOVING) {
client::CaptureClient* capture_client =
client::GetCaptureClient(host_->window()); // <--- Potential UAF read of host_
Window* capture_window =
capture_client ? capture_client->GetCaptureWindow() : nullptr;
if (!invisible_weak || invisible->Contains(event_dispatch_target_)) {
event_dispatch_target_ = nullptr; // <--- Potential UAF write to event_dispatch_target_
}
...
}
During CleanupGestureState(), active touch points are cancelled, which can synchronously dispatch synthetic touch-cancelled events. On desktop platforms (such as Linux/Ozone/X11 and Windows), an event handler processing this event can synchronously close the top-level widget (e.g., via Widget::CloseNow()). This triggers a synchronous teardown sequence where the WindowTreeHost destroys the WindowEventDispatcher (this).
Upon return from CleanupGestureState(), this has been deallocated, but the code proceeds to dereference this->host_ and perform writes to this->event_dispatch_target_, resulting in a UAF read and write inside the privileged browser process.
Potential Trigger Steps
Note: Our analysis tool does not currently have the capability to run code or execute a live proof of concept; therefore, these are theoretical, potential steps to demonstrate reachability.
- A compromised renderer process establishes a cross-origin subframe and registers active touch state within its boundaries.
- The renderer detaches the subframe, triggering
OnWindowRemovingFromRootWindowand subsequentlyWindowEventDispatcher::OnWindowHiddenon the browser UI thread. OnWindowHiddeninvokesinvisible->CleanupGestureState(), which generates and synchronously dispatches a synthetic touch-cancelled event.- A registered event handler on the target chain processes the cancellation and synchronously calls
Widget::CloseNow()on the top-level widget. - The host destroys the dispatcher synchronously, returning its memory slot to PartitionAlloc.
- Control returns to
OnWindowHidden, where the freed dispatcher memory is accessed when queryinghost_->window()and writing toevent_dispatch_target_.
Suggested Fix
Add a self-liveness check using base::WeakPtr to ensure the WindowEventDispatcher is still valid after performing gesture cleanup:
base::WeakPtr<aura::Window> invisible_weak = invisible->GetWeakPtrAsWindow();
base::WeakPtr<WindowEventDispatcher> weak_this = weak_ptr_factory_.GetWeakPtr();
invisible->CleanupGestureState();
if (!weak_this)
return;
Evaluated with Chrome root at commit: 5133b93d189b383c37805b1cf3a9d2dbfe8d7379
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.