CVE-2026-87460
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifthird_party/blink/renderer/platform/widget/widget_base.cc |
modified |
Files Changed
third_party/blink/renderer/platform/widget/widget_base.cc
Patch
From 1a454d58b0eb6ab832f5db00c18bb3b7380f8df4 Mon Sep 17 00:00:00 2001 From: Dave Tapuska <[email protected]> Date: Wed, 29 Jul 2026 08:23:59 -0700 Subject: [PATCH] Prevent use-after-free in WidgetBase by adding weak pointer checks. In WidgetBase::DidBeginMainFrame and WidgetBase::ShowVirtualKeyboardOnElementFocus, synchronous calls to update text input state or show the virtual keyboard can result in the destruction of the WidgetBase instance. This CL adds weak pointer checks to safely return early if the instance is destroyed during these calls. BUG=540058837,540058837 Change-Id: I9c87677f6ec186faaefda461f2a9f0ef49e19bb3 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8162668 Commit-Queue: Dave Tapuska <[email protected]> Reviewed-by: Vladimir Levin <[email protected]> Cr-Commit-Position: refs/heads/main@{#1670274} --- diff --git a/third_party/blink/renderer/platform/widget/widget_base.cc b/third_party/blink/renderer/platform/widget/widget_base.cc index 8b34b48..3880f16c 100644 --- a/third_party/blink/renderer/platform/widget/widget_base.cc +++ b/third_party/blink/renderer/platform/widget/widget_base.cc @@ -702,7 +702,11 @@ } void WidgetBase::DidBeginMainFrame() { + base::WeakPtr<WidgetBase> weak_this = weak_ptr_factory_.GetWeakPtr(); UpdateTextInputState(); + if (!weak_this) { + return; + } client_->DidBeginMainFrame(); } @@ -1394,6 +1398,7 @@ } void WidgetBase::ShowVirtualKeyboardOnElementFocus() { + base::WeakPtr<WidgetBase> weak_this = weak_ptr_factory_.GetWeakPtr(); #if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_IOS_TVOS) // On ChromeOS, virtual keyboard is triggered only when users leave the // mouse button or the finger and a text input element is focused at that @@ -1405,6 +1410,9 @@ #else ShowVirtualKeyboard(); #endif + if (!weak_this) { + return; + } // TODO(rouslan): Fix ChromeOS and Windows 8 behavior of autofill popup with // virtual keyboard.
Original Bug Report
Potential Use-After-Free in WidgetBase::DidBeginMainFrame
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 WidgetBase::DidBeginMainFrame because UpdateTextInputState() can synchronously trigger document layout updates and user script execution, which can destroy the WidgetBase instance. Upon return, the function performs a virtual method call on the client_ pointer from the freed WidgetBase object. This could potentially allow an attacker to execute arbitrary code in the sandboxed renderer process.
Affected files:
third_party/blink/renderer/platform/widget/widget_base.cc
Estimated timestamp from git blame: 2022-09-16
Potential Use-After-Free in WidgetBase::DidBeginMainFrame
Location
third_party/blink/renderer/platform/widget/widget_base.cc:704-707
Description
A potential Use-After-Free (UAF) vulnerability exists in WidgetBase::DidBeginMainFrame due to a missing liveness guard. Calling UpdateTextInputState() can trigger synchronous layout updates and user script execution, leading to the destruction of the WidgetBase instance. Upon return, the function performs a virtual method call on the client_ pointer of the freed WidgetBase instance, leading to a potential Remote Code Execution (RCE) primitive in the sandboxed renderer process.
Root Cause Analysis
In third_party/blink/renderer/platform/widget/widget_base.cc, WidgetBase::DidBeginMainFrame() has the following implementation:
void WidgetBase::DidBeginMainFrame() {
UpdateTextInputState();
client_->DidBeginMainFrame();
}
When UpdateTextInputState() is called, it routes to UpdateTextInputStateInternal(false, false), which eventually invokes frame_widget->TextInputInfo() to query text input metadata.
If the layout is currently dirty, InputMethodController::TextInputInfo() forces a style and layout update:
GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kEditing);
During UpdateStyleAndLayout(), the document instantiates an HTMLFrameOwnerElement::PluginDisposeSuspendScope. If any <embed> or <object> elements are scheduled for detachment or disposal (due to prior DOM modifications), they are collected. When the scope exits, the deferred plugin disposals are processed via PerformDeferredPluginDispose(), which executes web_plugin_->Destroy() inside WebPluginContainerImpl::Dispose() on the main thread.
Since plugin teardown operates under ScriptForbiddenScope::AllowUserAgentScript, it can run arbitrary, synchronous user JavaScript. If this JavaScript detaches the local frame widget, it calls WebFrameWidgetImpl::Close(), which triggers widget_base_->Shutdown() and widget_base_.reset(), synchronously deleting the WidgetBase instance.
Although UpdateTextInputStateInternal contains a base::WeakPtr<WidgetBase> weak_this guard that catches this destruction and returns early, the calling function WidgetBase::DidBeginMainFrame() lacks any such guard. Once control returns to DidBeginMainFrame(), the execution attempts to access client_->DidBeginMainFrame(). Since the WidgetBase instance was freed, reading this->client_ causes a Use-After-Free. Because client_ is a virtual interface (WidgetBaseClient), this results in an exploitable virtual method dispatch.
Mitigations Checked
- MiraclePtr / BackupRefPtr (BRP): The dangling pointer is the stack-resident
thispointer (a bare pointer) and not araw_ptr<>. Additionally, all externalraw_ptrreferences toWidgetBase(e.g.,LayerTreeView::delegate_) are nullified or destroyed prior toWidgetBasedeletion, so the allocation is not quarantined. - Sibling Guards: Sibling callers of
UpdateTextInputStateInternal()(such asForceTextInputStateUpdateandOnImeEventGuardFinish) are properly guarded, butDidBeginMainFramewas missed.
Suggested Steps to Trigger (Potential)
Note: Since our security analysis tools do not have the capability to execute code, these are potential steps derived from static analysis of the codebase.
- Serve a page with a valid
HTMLInCanvasOrigin Trial token to enable theCanvasDrawElementfeature. - Embed a local subframe containing a focused
<textarea>, an<embed>or<object>plugin element, and a<canvas>registered for thepaintevent (populatingcanvas_elements_needing_onpaint_). - In the canvas synchronous
paintevent handler (which runs duringWillCommit), mutate the layout/CSS so the plugin element is scheduled to be detached (e.g.,display: none), and dirty the layout of the textarea’s document. - When
WidgetBase::DidBeginMainFrame()runs and forces a layout update insideTextInputInfo(), the plugin disposal will run synchronous attacker JavaScript. - In the plugin’s
Destroy()JS handler, detach the local frame, destroying theWidgetBaseinstance. - Reclaim/spray the heap to replace the freed
WidgetBasememory and control theclient_pointer, leading to arbitrary virtual call execution on return.
Suggested Fix
Add a base::WeakPtr check in WidgetBase::DidBeginMainFrame() to detect if the widget was destroyed during UpdateTextInputState():
void WidgetBase::DidBeginMainFrame() {
base::WeakPtr<WidgetBase> weak_this = weak_ptr_factory_.GetWeakPtr();
UpdateTextInputState();
if (!weak_this) {
return;
}
client_->DidBeginMainFrame();
}
Evaluated with Chrome root at commit: 94d9235ebe3b7276e5284f0dc5d55577ff949908
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.