Overview

High
Severity
8.8
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactUse after free in Platform
DescriptionUse after free in Platform
ComponentPlatform
Bug ClassUAF
Action tierpatch-now — corruption primitive, web-reachable in default config (confirmed) — upheld by independent review by AI
Computed by PatchGap's deterministic exploitability ruler from the fixing commit. patch-now = RCE-class & attacker-reachable in a default config, or exploited in the wild; watch = real security signal below that bar; noise = no security relevance.
Independent review by AIConfirmed
A second, independent AI reviewer (not a human) re-derived this analysis from the fixing commit and the vendor advisory, looking for errors.
Tracker540058837
Fix commit1a454d58b0eb (chromium/src) +8/-0
CWECWE-416 (Use-after-free)
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
CISA KEVNot listed
CreditedGoogle
Reported2026-07-28 (per vendor advisory)
Fix landed2026-07-29 (public git)
Disclosed2026-09-08
Patch gap41 days — fix public in source before the advisory

Background

`WidgetBase`
a Blink platform object (third_party/blink/renderer/platform/widget/widget_base.cc) that backs a renderer widget and mediates frame lifecycle and input/IME interactions with its client_.
`base::WeakPtr` / `weak_ptr_factory_`
a weak-reference mechanism whose GetWeakPtr() yields a pointer that evaluates false once the owning object is destroyed, used to detect re-entrant self-destruction.
Synchronous re-entrancy
UpdateTextInputState() and ShowVirtualKeyboard() can dispatch synchronously into the browser/embedder and, as a side effect, cause the WidgetBase itself to be torn down before control returns.

Root Cause Analysis

WidgetBase::DidBeginMainFrame called UpdateTextInputState() and then unconditionally dereferenced this via client_->DidBeginMainFrame(); likewise WidgetBase::ShowVirtualKeyboardOnElementFocus called ShowVirtualKeyboard() and continued executing on this afterward. Because those synchronous calls can trigger destruction of the WidgetBase instance, the subsequent member access ran on a freed object — a use-after-free. The invariant violated is that a method must not touch instance state after invoking a call that may synchronously free the instance.

The fix captures weak_ptr_factory_.GetWeakPtr() into weak_this before the dangerous call and returns early if !weak_this afterward, so no member access occurs once the object has been destroyed.

Key insight
The methods continued to use this after a synchronous call that could delete the WidgetBase; the fix takes a base::WeakPtr before the call and bails out early when the weak pointer has been invalidated, preventing the post-free dereference.

Attack Path

  1. Reach the vulnerable methods A page arranges for WidgetBase::DidBeginMainFrame to run during frame production, or focuses a text input so WidgetBase::ShowVirtualKeyboardOnElementFocus is invoked.
  2. Force synchronous teardown During UpdateTextInputState() (or ShowVirtualKeyboard()), a synchronous notification to the client/embedder causes the owning WidgetBase to be destroyed before the call returns.
  3. Trigger the stale access With the pre-patch code, control returns into the method and it dereferences the now-freed this (e.g. client_->DidBeginMainFrame()), producing a use-after-free.
  4. Exploitation Controlling the reallocation of the freed WidgetBase memory could yield a corrupted-object primitive leading to further compromise (inferred); the patch itself only demonstrates the freed-object access.

Impact Assessment

An attacker able to drive frame lifecycle or focus events in a page could free a WidgetBase mid-call and cause the renderer to dereference freed memory, a use-after-free in the renderer process; the advisory classifies this as a use-after-free in the Platform component. Memory corruption of this kind is commonly a stepping stone to renderer code execution (inferred), but the patch does not itself demonstrate escalation beyond the freed-object access, and the advisory does not report in-the-wild exploitation.

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

Audit Directions

  • Member access after synchronous callbacks
    Audit methods that call into client_/embedder or IME/keyboard code and then continue touching this; each such call that can re-enter and destroy the object needs a WeakPtr guard.
  • Lifecycle and focus/IME entry points
    Review other WidgetBase and widget lifecycle methods (frame begin/commit, focus, input-state updates) for the same “call then dereference” shape.
  • WeakPtr guard completeness
    Where a WeakPtr check is added, verify every later dereference (not just the immediate next one) is dominated by the check, since a single guarded call can still be followed by unguarded state access.
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