Medium CVSS 4.3 webkit UAF 🔧 Commit mapped

Overview

Medium
Severity
4.3
CVSS
No
Exploited ITW
Fixed
Fix Status
DescriptionProcessing maliciously crafted web content may lead to an unexpected Safari crash
ComponentWebKit Platform
Bug ClassUAF
Tracker296276
Fix commit674611789255 (WebKit/WebKit) +13/-11
CWECWE-416 (Use-after-free)
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:L
CISA KEVNot listed
CreditedPawel Wylecial of REDTEAM.PL working with Trend Micro Zero Day Initiative, Ignacio Sanmillan (@ulexec)
Disclosed2025-09-15

Background

IPC Connection/Client
WebKit’s inter-process message channel delivers decoded messages to a Client object via callbacks like didReceiveMessage.
CheckedPtr vs RefPtr
CheckedPtr detects use-after-free in debug but does not extend lifetime; RefPtr holds a reference that keeps the object alive.
Re-entrant teardown
A message handler can invalidate/close the connection and destroy the client while a dispatch call is still executing.

Root Cause Analysis

This fixes a use-after-free of the IPC Connection’s Client during message dispatch by replacing non-owning CheckedPtr access with a ref-holding RefPtr. Connection dispatches incoming messages to its Client (didReceiveMessage, didReceiveSyncMessage, didClose, didReceiveInvalidMessage) via checkedClient(), which returned a CheckedPtr<Client>. A CheckedPtr only verifies (in debug) that the pointee has not been freed; it does NOT keep the Client alive. Message handlers can run code that re-entrantly tears down the connection’s client (or the client can be destroyed on another thread), so a call like checkedClient()->didReceiveMessage(*this, decoder) could dereference a Client that is being or has been destroyed — a use-after-free.

The fix renames checkedClient() to protectedClient() returning RefPtr<Client> (m_client.get()), and updates the hot dispatch paths to take a local RefPtr client = m_client.get(), null-check it, and call through it, so the Client is guaranteed to stay alive for the duration of each dispatch call. dispatchDidCloseAndInvalidate and the throttling-termination path likewise load a RefPtr and bail if null.

The restored invariant is that the Client outlives every dispatch call made on it; a checked (non-owning) pointer was insufficient across calls that can drop the last reference.

Key insight
Message dispatch called into the Client through a non-owning CheckedPtr, so a handler that tore down the client mid-call left a dangling pointer; retaining the client with a RefPtr for the duration of each call fixes it.

Attack Path

  1. Send messages that re-enter A process on one end of the IPC connection sends messages whose handlers cause the connection’s Client to be torn down (invalidate/close) during dispatch.
  2. Dispatch through a non-owning pointer Connection calls checkedClient()->didReceive… which does not retain the Client across the call.
  3. Free during the call The Client is destroyed while a dispatch call is in flight, leaving a dangling pointer.
  4. Use-after-free Continued use of the freed Client corrupts memory in the receiving process.

Impact Assessment

A use-after-free on the IPC Client in whichever process receives the messages (UI, GPU, Network or WebContent), reachable when a peer sends messages that trigger re-entrant client teardown during dispatch. UAFs on core IPC objects are broadly reachable and exploitable with grooming; the advisory rates it a crash, but the class routinely escalates toward code execution in the receiving process.

Changed Functions

FunctionChangeNotes
Connection::protectedClient (was checkedClient)
Source/WebKit/Platform/IPC/Connection.h
modified Returns RefPtr<Client> (retaining) instead of CheckedPtr<Client> (non-owning).
Connection::dispatchMessage
Source/WebKit/Platform/IPC/Connection.cpp
modified Loads a local RefPtr client, RELEASE_ASSERTs it, and calls didReceiveMessage through it, keeping the client alive across dispatch.
Connection::dispatchSyncMessage / dispatchDidReceiveInvalidMessage / dispatchDidCloseAndInvalidate / enqueueIncomingMessage
Source/WebKit/Platform/IPC/Connection.cpp
modified Switch from checkedClient() to protectedClient()/RefPtr client with null checks before invoking client callbacks.
Connection::waitForAndDispatchImmediately
Source/WebKit/Platform/IPC/Connection.cpp
modified Uses protectedClient()->didReceiveMessage to retain the client across the synchronous dispatch.

Files Changed

  • Source/WebKit/Platform/IPC/Connection.cpp
  • Source/WebKit/Platform/IPC/Connection.h

Audit Directions

  • Same file: remaining checkedClient users
    Grep Connection.cpp/.h for any residual checkedClient()/CheckedPtr client uses on paths that can run client code and confirm they hold a RefPtr.
  • CheckedPtr across callbacks
    Across WebKit, look for CheckedPtr members dereferenced across virtual callbacks that can free the pointee; these need protected*/RefPtr upgrades.

Original Bug Report

The reporter's bug is still restricted on the tracker.