← Chrome — 2026-W40

5343c336cd97d19868024a11e1e5f3b299d979f8  [chromecast] Fix UAF in BufferedSpdyFramer::OnGoAwayFrameData

severity high class UAF confidence 0.97 signal score 8.5 net/ patch-now AI review CONFIRMED
Primitive: use-after-free of goaway_fields_/this after visitor_->OnGoAway destructs the framer
Triage note: visitor_->OnGoAway() synchronously destroys the SpdySession and its BufferedSpdyFramer, then old code called goaway_fields_.reset() on freed this. Fix std::move()s goaway_fields_ to a local first. Network-reachable from a malicious HTTP/2 GOAWAY; explicit 'Fix UAF'.
Structural signals: smartptr_member_added (+3.0), msg_strong (+3.0), area:net/ (+1.2), surgical (+1.3)

The bug at a glance

Use-after-free in net/spdy’s BufferedSpdyFramer, which runs inside the privileged network service / browser process while parsing attacker-influenced HTTP/2 control frames; a browser-process UAF reachable from any HTTP/2 (or gRPC/Cast) peer is typically rated High.

A malicious or compromised HTTP/2 server (the commit subject flags the Cast receiver path) can send a crafted GOAWAY frame to free the framer object and then have Chrome dereference it, giving an attacker a controlled free-then-use in the process that brokers all network traffic.

Root cause

In BufferedSpdyFramer::OnGoAwayFrameData, once the GOAWAY payload has finished streaming the code calls visitor_->OnGoAway(goaway_fields_->…). That visitor callback synchronously tears down the SpdySession, and because the SpdySession owns the BufferedSpdyFramer, the framer object (and its goaway_fields_ member) is destructed inside the call. The original code then executed goaway_fields_.reset() on the just-freed member, a use-after-free. The invariant violated is that this/goaway_fields_ must not be touched after a visitor callback that can re-enter and destroy the framer. The fix moves goaway_fields_ into a local std::unique_ptr fields before the callback, so ownership (and the GoAwayFields storage) lives on the stack frame; the callback’s arguments are read from the local, and no member access occurs after OnGoAway returns, so the dangling destruction is eliminated.

Key code

net/spdy/buffered_spdy_framer.cc — steal ownership of goaway_fields_ onto the stack before the re-entrant visitor call

std::unique_ptr<GoAwayFields> fields = std::move(goaway_fields_);
visitor_->OnGoAway(fields->last_accepted_stream_id, fields->error_code,
                   fields->debug_data);
return true;

Patch walkthrough

  • net/spdy/buffered_spdy_framer.cc — OnGoAwayFrameData previously called visitor_->OnGoAway() reading directly from the goaway_fields_ member, then ran goaway_fields_.reset(). Because visitor_->OnGoAway can synchronously destroy the SpdySession that owns this framer, that trailing member access was a UAF. The patch replaces it with a std::move of goaway_fields_ into a stack local and passes fields->… into OnGoAway, then returns true — the GoAwayFields object is now owned by the stack local and destroyed when the frame unwinds, not by a member touch after the callback.

Background

BufferedSpdyFramer — net/spdy helper that buffers multi-part HTTP/2 control frames (HEADERS, GOAWAY, etc.) and surfaces complete frames to a BufferedSpdyFramer::Visitor, usually the SpdySession.

GOAWAY frame — HTTP/2 connection-shutdown frame carrying last_accepted_stream_id, error_code and optional debug_data; receiving it normally causes Chrome to tear down the SpdySession.

goaway_fields_ — A std::unique_ptr member of BufferedSpdyFramer that accumulates the streamed GOAWAY payload before the visitor is notified.

Re-entrant destruction — visitor_->OnGoAway destroys the SpdySession, which owns the BufferedSpdyFramer, so the callback deletes this and its members mid-method — the classic Chrome callback-frees-the-object UAF shape.

Vulnerability window

  1. Fix authored — Commit 5343c336cd, dated 2026-09-28, landed to main (CL 8272371).
  2. Tracking — Internal bug referenced in the change; described as a UAF crash fixed by stealing ownership of goaway_fields_ before the callback.
  3. Validation — No regression test is included; correctness rests on the ownership move alone.

Proof of concept

The diff contains no regression test or repro, so no trigger code can be grounded in the patch. Conceptually (inferred): a peer HTTP/2 server completes a GOAWAY frame to BufferedSpdyFramer; OnGoAwayFrameData calls visitor_->OnGoAway, the SpdySession is synchronously destroyed (destroying the framer), and the pre-patch goaway_fields_.reset() then touches the freed framer. Reproducing the destroy-on-OnGoAway ordering and any heap grooming is (inferred).

Exploitation

  1. Reach — Get Chrome to hold an HTTP/2 connection to an attacker-controlled endpoint and send a GOAWAY whose delivery drives OnGoAwayFrameData to completion.
  2. Free — visitor_->OnGoAway synchronously destructs the SpdySession and its BufferedSpdyFramer, freeing the object whose goaway_fields_ is accessed next.
  3. Use / escalate — (inferred) Turning the dangling goaway_fields_.reset() into controlled read/write would require reclaiming the freed framer allocation with attacker-shaped data and is not shown by the patch; RCE/sandbox impact beyond the crash is (inferred).

Detection & hunting

For defenders and detection engineers:

  • ASAN/heap crash in OnGoAwayFrameData — On ASAN or MTE builds, a heap-use-after-free with BufferedSpdyFramer::OnGoAwayFrameData / SpdySession teardown on the stack is a direct hit; triage network-service crashes with goaway_fields_ in the free/use frames.
  • GOAWAY-triggered crashes — Correlate browser/network-service crashes against sessions that received a GOAWAY immediately prior; repeated crashes tied to a specific origin or Cast peer after GOAWAY are suspicious.
  • Malformed/edge-case GOAWAY traffic — At a TLS-terminating proxy or Cast gateway, flag peers that emit GOAWAY in unusual sequences or timing designed to force synchronous session teardown.

Audit directions

  • net/spdy visitor callbacks — Audit every BufferedSpdyFramer::Visitor dispatch (OnHeaders, OnRstStream, OnSettings, OnDataFrameHeader) for member or this access after the callback, since the visitor can destroy the owning SpdySession.
  • Callback-then-member pattern — Grep net/ for ‘visitor_->On…(member_->…); member_.reset();’ or member access following any delegate/visitor invocation that can re-enter and delete the object; prefer moving owned state to a stack local before the call.
  • SpdySession ownership graph — Map which framer/parser objects are owned by SpdySession and ensure none are touched after any path that may synchronously destroy the session (GOAWAY, fatal protocol errors, connection close).

Before / after

Loading diff…