← Chrome — 2026-W31

38c49d2a96defae98e7efcf2a2d06c8b17e5c77d  [M144] Prevent use-after-free in WidgetBase::UpdateSurfaceAndScreen.

severity high class UAF CVSS 8.1 signal score 12.46 AI review PLAUSIBLE
Structural signals: null_guard (+2.59), uaf_lifetime (+3.57), msg_strong (+3.0), msg_medium (+2.0), surgical (+1.3)

The bug at a glance

The subject and diff explicitly describe a use-after-free: client_->OrientationChanged() (and client_->UpdateLifecycle()) can synchronously destroy the WidgetBase, after which the function keeps dereferencing client_ and member state, giving a renderer-reachable UAF.

An attacker controlling page content can arrange for an orientation/lifecycle callback to tear down the owning widget while WidgetBase::UpdateSurfaceAndScreen is still mid-execution, turning a re-entrant destroy into a dangling-this use-after-free in the renderer.

Root cause

UpdateSurfaceAndScreen and the lifecycle helper call out to client_ methods (OrientationChanged, UpdateLifecycle) that can run script/observers which synchronously destroy the WidgetBase. On return the original stack frame continued to touch client_ and member fields through a now-freed ’this’. The fix captures a WeakPtr to ’this’ before each re-entrant client call and returns early if the weak pointer is invalidated, aborting further use of the freed object.

Key code

Weak-pointer guard after a re-entrant client callback that can free WidgetBase

if (orientation_changed) {
    auto weak_this = weak_ptr_factory_.GetWeakPtr();
    client_->OrientationChanged();
    if (!weak_this) {
      return;
    }
  }

Patch walkthrough

  • third_party/blink/renderer/platform/widget/widget_base.cc — Adds a weak_ptr_factory_.GetWeakPtr() snapshot before client_->UpdateLifecycle() and client_->OrientationChanged(), with an early return if the WidgetBase was destroyed during the call; this prevents the subsequent SetSuppressFrameRequestsWorkaroundFor704763Only() and DidUpdateSurfaceAndScreen() calls from dereferencing freed memory.

Background

WidgetBase — Blink platform object backing a renderer widget that owns surface/screen state and forwards lifecycle events to a client interface.

WeakPtr guard — Common Chromium idiom of capturing a WeakPtr before a re-entrant callback and bailing out if ’this’ was destroyed during it.

Re-entrant destruction — A callback into client code (orientation/lifecycle) can synchronously delete the caller object, invalidating the current ’this'.

Vulnerability window

  1. Reachability — Renderer reaches UpdateSurfaceAndScreen via a screen-info/orientation update during compositing (inferred).
  2. Trigger — client_->OrientationChanged() runs observers/script that destroy the owning WidgetBase (inferred).
  3. Primitive — Execution returns to the freed WidgetBase frame and dereferences client_/members, a use-after-free.
  4. Escalation — Controlled reclamation of the freed allocation could turn the UAF into memory corruption in the renderer (inferred).

Proof of concept

Conceptually, a page would register orientation-change / lifecycle handling that causes the widget’s host (e.g. a frame or plugin) to be detached and destroyed synchronously during the orientation callback, then rely on the post-callback code path still executing against the freed WidgetBase. No exploit code is provided.

Exploitation

  1. Setup — Construct a document/frame whose orientation or lifecycle callback can trigger widget teardown (inferred).
  2. Trigger — Cause a surface/screen update so OrientationChanged() fires and destroys the WidgetBase mid-function (inferred).
  3. Groom — Reallocate the freed WidgetBase storage with attacker-influenced data before the dangling dereference (inferred).
  4. Corrupt — Leverage the dangling client_/member access for a controlled read/write primitive in the renderer (inferred).

Detection & hunting

For defenders and detection engineers:

  • weggli: ‘_->$call(); $obj->$next’ patterns where a client callback is followed by further member use without a weak-ptr check — Grep for calls to client_ methods in widget_base.cc and sibling widget code that are not immediately followed by a weak_this validity check.
  • grep ‘GetWeakPtr’ vs re-entrant ‘client_->’ calls — Audit each client_-> callback that can run script/observers to confirm a WeakPtr guard exists before later member dereferences.

Audit directions

  • third_party/blink/renderer/platform/widget/* — Review other WidgetBase methods that call into client_ (lifecycle, visual properties, focus) for missing weak-this checks after re-entrant callbacks.
  • Blink callers of client interfaces that can destroy the caller — Look for any method pattern ‘callback(); then use member/this’ where callback can synchronously delete the object.

Before / after

Loading diff…