Overview

High
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactUse after free in Platform
DescriptionUse after free in Platform
ComponentPlatform
Bug ClassUAF
Tracker540058837
Fix commit1a454d58b0eb (chromium/src) +8/-0
CISA KEVNot listed
CreditedGoogle
Disclosed2026-09-08

Changed Functions

FunctionChangeNotes
if
third_party/blink/renderer/platform/widget/widget_base.cc
modified

Files Changed

  • third_party/blink/renderer/platform/widget/widget_base.cc
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.
Loading diff…

Original Bug Report

reported by [email protected]

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

  1. MiraclePtr / BackupRefPtr (BRP): The dangling pointer is the stack-resident this pointer (a bare pointer) and not a raw_ptr<>. Additionally, all external raw_ptr references to WidgetBase (e.g., LayerTreeView::delegate_) are nullified or destroyed prior to WidgetBase deletion, so the allocation is not quarantined.
  2. Sibling Guards: Sibling callers of UpdateTextInputStateInternal() (such as ForceTextInputStateUpdate and OnImeEventGuardFinish) are properly guarded, but DidBeginMainFrame was 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.

  1. Serve a page with a valid HTMLInCanvas Origin Trial token to enable the CanvasDrawElement feature.
  2. Embed a local subframe containing a focused <textarea>, an <embed> or <object> plugin element, and a <canvas> registered for the paint event (populating canvas_elements_needing_onpaint_).
  3. In the canvas synchronous paint event handler (which runs during WillCommit), 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.
  4. When WidgetBase::DidBeginMainFrame() runs and forces a layout update inside TextInputInfo(), the plugin disposal will run synchronous attacker JavaScript.
  5. In the plugin’s Destroy() JS handler, detach the local frame, destroying the WidgetBase instance.
  6. Reclaim/spray the heap to replace the freed WidgetBase memory and control the client_ 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.

View on issue tracker