CVE-2026-9984
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifcontent/browser/renderer_host/legacy_render_widget_host_win.cc |
modified |
Files Changed
content/browser/renderer_host/legacy_render_widget_host_win.cc
Patch
From c50e173c8fb7547db51be54971e01793c6fbc6bd Mon Sep 17 00:00:00 2001 From: Alex Moshchuk <[email protected]> Date: Tue, 19 May 2026 11:10:05 -0700 Subject: [PATCH] Fix potential UAF in LegacyRenderWidgetHostHWND::InitOrDeleteSelf() LegacyRenderWidgetHostHWND::InitOrDeleteSelf() contains several calls that are known to be re-entrant on Windows, including WindowImpl::Init(), NotifyWinEvent(), and DirectManipulationHelper::CreateInstance(). Guard against those calls potentially destroying `this`. Bug: 513002543 Change-Id: Ie21f55d69c4165f6762114f124fa538d86e7130c Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7854110 Commit-Queue: Alex Moshchuk <[email protected]> Reviewed-by: Arthur Sonzogni <[email protected]> Cr-Commit-Position: refs/heads/main@{#1633009} --- diff --git a/content/browser/renderer_host/legacy_render_widget_host_win.cc b/content/browser/renderer_host/legacy_render_widget_host_win.cc index 5128325..dae7552 100644 --- a/content/browser/renderer_host/legacy_render_widget_host_win.cc +++ b/content/browser/renderer_host/legacy_render_widget_host_win.cc @@ -94,8 +94,14 @@ // returns NULL if Direct Manipulation is not available. Recreate // |direct_manipulation_helper_| when parent changed (compositor and window // event target updated). - direct_manipulation_helper_ = + base::WeakPtr<LegacyRenderWidgetHostHWND> ref( + msg_handler_weak_factory_.GetWeakPtr()); + std::unique_ptr<DirectManipulationHelper> direct_manipulation_helper = DirectManipulationHelper::CreateInstance(hwnd()); + if (!ref) { + return; + } + direct_manipulation_helper_ = std::move(direct_manipulation_helper); if (direct_manipulation_helper_) { direct_manipulation_helper_->UpdateEventHandler( host_->GetNativeView()->GetHost()->GetWeakPtr(), @@ -225,7 +231,21 @@ set_window_ex_style(WS_EX_TRANSPARENT); set_window_class_name(ui::kLegacyRenderWidgetHostHwnd); set_window_name(L"Chrome Legacy Window"); + + // WindowImpl::Init (::CreateWindowEx), NotifyWinEvent, and + // DirectManipulationHelper::CreateInstance (CoCreateInstance / Activate / + // Enable) can synchronously dispatch window messages. Re-entrant dispatch may + // reach RenderWidgetHostViewAura::OnWindowDestroying -> + // LegacyRenderWidgetHostHWND::Destroy() -> ::DestroyWindow() -> + // WM_NCDESTROY -> OnNCDestroy -> delete this. Guard against |this| being + // freed mid-method. + base::WeakPtr<LegacyRenderWidgetHostHWND> ref( + msg_handler_weak_factory_.GetWeakPtr()); + WindowImpl::Init(parent, gfx::Rect()); + if (!ref) { + return false; + } // We create a system caret regardless of accessibility mode since not all // assistive software that makes use of a caret is classified as a screen @@ -241,8 +261,13 @@ // Ignore failure from this call. Some SKUs of Windows such as Hololens do not // support MSAA, and this call failing should not stop us from initializing // UI Automation support. + Microsoft::WRL::ComPtr<IAccessible> window_accessible; ::CreateStdAccessibleObject(hwnd(), OBJID_WINDOW, - IID_PPV_ARGS(&window_accessible_)); + IID_PPV_ARGS(&window_accessible)); + if (!ref) { + return false; + } + window_accessible_ = std::move(window_accessible); if (::ui::AXPlatform::GetInstance().IsUiaProviderEnabled()) { // The usual way for UI Automation to obtain a fragment root is through @@ -277,6 +302,9 @@ // accessibility support, by seeing if they respond to this event. NotifyWinEvent(EVENT_SYSTEM_ALERT, hwnd(), kIdScreenReaderHoneyPot, CHILDID_SELF); + if (!ref) { + return false; + } } // Disable pen flicks (http://crbug.com/506977) @@ -295,8 +323,12 @@ // UpdateParent() will assign an event target to it. Note Direct // Manipulation is enabled on Windows 10+. The CreateInstance function // returns NULL if Direct Manipulation is not available. - direct_manipulation_helper_ = + std::unique_ptr<DirectManipulationHelper> direct_manipulation_helper = DirectManipulationHelper::CreateInstance(hwnd()); + if (!ref) { + return false; + } + direct_manipulation_helper_ = std::move(direct_manipulation_helper); } return true;
Original Bug Report
Potential Browser-Process Use-After-Free in LegacyRenderWidgetHostHWND::InitOrDeleteSelf
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 re-entrancy vulnerability in the Windows-specific legacy window initialization can lead to a Use-After-Free (UAF) in the browser process. Synchronous message dispatch during window creation or COM activation allows the object to be destroyed before the initialization function completes, resulting in memory corruption when execution resumes.
Affected files:
content/browser/renderer_host/legacy_render_widget_host_win.cccontent/browser/renderer_host/legacy_render_widget_host_win.h
Estimated timestamp from git blame: 2026-01-29
Summary
A potential Use-After-Free (UAF) vulnerability exists in LegacyRenderWidgetHostHWND::InitOrDeleteSelf within content/browser/renderer_host/legacy_render_widget_host_win.cc. The method performs several operations that synchronously dispatch window messages or pump the Windows message loop. If the LegacyRenderWidgetHostHWND object is destroyed during one of these re-entrant calls, the method continues to execute on a freed this pointer, leading to arbitrary writes and virtual function calls in the unsandboxed browser process.
Root Cause Analysis
In LegacyRenderWidgetHostHWND::InitOrDeleteSelf, several calls are known to be re-entrant on Windows:
WindowImpl::Init(Line 221): Calls::CreateWindowEx, which synchronously dispatches messages likeWM_CREATEandWM_GETMINMAXINFOto the window procedure.NotifyWinEvent(Line 271): A synchronous API that can trigger WinEvent hooks or cause accessibility clients (like screen readers) to query the window viaWM_GETOBJECTsynchronously.DirectManipulationHelper::CreateInstance(Line 292): Performs COM operations, includingIDirectManipulationManager::Activate, which is documented to potentially dispatch messages and pump the loop.
Unlike other re-entrancy-prone methods in the same class (such as UpdateParent, OnKeyboardRange, and OnMouseRange), InitOrDeleteSelf lacks base::WeakPtr guards. If a destruction request for the parent window (e.g., a renderer-initiated window.close()) is processed during these synchronous calls, the LegacyRenderWidgetHostHWND (a child window) is recursively destroyed. This reaches OnNCDestroy, which executes delete this;. When control returns to InitOrDeleteSelf, the method resumes and performs multiple writes to member variables (e.g., ax_fragment_root_, window_tree_host_prop_) and a virtual call via host_->UpdateTooltip() on freed memory.
Potential Impact
This is a high-severity UAF in the unsandboxed browser process. An attacker who can control the heap layout (e.g., via a compromised renderer) could potentially occupy the freed memory during the re-entrant loop and hijack the subsequent virtual calls or writes to achieve arbitrary code execution (RCE) in the context of the browser process.
Suggested Reproductions Steps
Note: These steps are theoretical as our analysis is based on static code review.
- On a Windows system with an active WinEvent client (e.g., Narrator or a custom hook), navigate to a page that opens a new popup via
window.open(). - Immediately trigger a close operation on the popup (e.g.,
window.close()) to queue a destruction task. - If the destruction task is processed during the synchronous dispatch inside
InitOrDeleteSelf(specifically during theNotifyWinEventorDirectManipulationHelper::CreateInstancecalls), a UAF should occur when the function resumes. - In a build with AddressSanitizer (ASan), this would manifest as a
heap-use-after-freewith the free stack atLegacyRenderWidgetHostHWND::OnNCDestroyand the use stack atLegacyRenderWidgetHostHWND::InitOrDeleteSelf.
Recommended Fix
The fix should follow the pattern already used in UpdateParent. Utilize the existing msg_handler_weak_factory_ to create a WeakPtr guard before any re-entrant calls and verify the object’s liveness before proceeding.
Example fix for re-entrant points:
base::WeakPtr<LegacyRenderWidgetHostHWND> ref(msg_handler_weak_factory_.GetWeakPtr());
NotifyWinEvent(...);
if (!ref) return false;
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.