Overview

Critical
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactUse after free in Cast
DescriptionUse after free in Cast
ComponentCast
Bug ClassUAF
Tracker513136593
Fix commit034c57cb7a2a (chromium/src) +4/-1
CISA KEVNot listed
CreditedGoogle
Disclosed2026-06-02

Changed Functions

FunctionChangeNotes
if
components/openscreen_platform/udp_socket.cc
modified

Files Changed

  • components/openscreen_platform/udp_socket.cc
From 034c57cb7a2a215024822b53ab27b860e05fd348 Mon Sep 17 00:00:00 2001
From: Jordan Bayles <jophba@chromium.org>
Date: Mon, 18 May 2026 16:34:50 -0700
Subject: [PATCH] Fix UAF in openscreen_platform::UdpSocket::OnReceived

This CL adds a weak pointer guard before calling udp_socket_->ReceiveMore(1) in UdpSocket::OnReceived to prevent a Use-After-Free if the client's OnRead callback synchronously destroys the UdpSocket instance.

Bug: 513136593
Change-Id: I6253d17915b1c03488d403117dbf6edca30dc4bd
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7856453
Reviewed-by: Muyao Xu <muyaoxu@google.com>
Commit-Queue: Jordan Bayles <jophba@chromium.org>
Commit-Queue: Muyao Xu <muyaoxu@google.com>
Auto-Submit: Jordan Bayles <jophba@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1632485}
---

diff --git a/components/openscreen_platform/udp_socket.cc b/components/openscreen_platform/udp_socket.cc
index 1fc4bf3..ff858f8a 100644
--- a/components/openscreen_platform/udp_socket.cc
+++ b/components/openscreen_platform/udp_socket.cc
@@ -152,6 +152,7 @@
     int32_t net_result,
     const std::optional<net::IPEndPoint>& source_endpoint,
     std::optional<base::span<const uint8_t>> data) {
+  base::WeakPtr<UdpSocket> weak_this = weak_ptr_factory_.GetWeakPtr();
   if (net_result != net::OK) {
     client_->OnRead(this, Error::Code::kSocketReadFailure);
   } else if (data) {
@@ -163,7 +164,9 @@
     client_->OnRead(this, std::move(packet));
   }
 
-  udp_socket_->ReceiveMore(1);
+  if (weak_this) {
+    udp_socket_->ReceiveMore(1);
+  }
 }
 
 void UdpSocket::BindCallback(int32_t result,
Loading diff…

Original Bug Report

reported by vm...@google.com

Potential Browser-process UAF in openscreen_platform::UdpSocket::OnReceived

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 without the Chrome Security team. Please see https://chromium.googlesource.com/chromium/src/+/main/docs/security/ai-generated-security-bugs-faq.md for more information.

Overview: A Use-After-Free (UAF) vulnerability potentially exists in the browser process within openscreen_platform::UdpSocket::OnReceived. A reentrant callback can synchronously trigger the destruction of the UdpSocket instance, leading to an invalid member access when execution returns to the function.

Affected files:

  • components/openscreen_platform/udp_socket.cc
  • components/openscreen_platform/udp_socket.h

Estimated timestamp from git blame: 2019-10-21

Root Cause Analysis

A potential Use-After-Free (UAF) has been identified in openscreen_platform::UdpSocket::OnReceived in components/openscreen_platform/udp_socket.cc. This method is the handler for network::mojom::UDPSocketListener, which is dispatched by a mojo::Receiver stored within the UdpSocket object.

When a network error or a specific packet is received, OnReceived calls a client callback (client_->OnRead). In certain configurations, such as the Cast receiver’s streaming application, this callback can trigger a synchronous teardown of the ownership chain that includes the UdpSocket instance. Because this destruction is synchronous, the UdpSocket object (including its this pointer and all members) is freed before the callback returns. Execution then proceeds to access the udp_socket_ member of the now-deleted object.

In components/openscreen_platform/udp_socket.cc:

void UdpSocket::OnReceived(
    int32_t net_result,
    const std::optional<net::IPEndPoint>& source_endpoint,
    std::optional<base::span<const uint8_t>> data) {
  if (net_result != net::OK) {
    client_->OnRead(this, Error::Code::kSocketReadFailure);   // (A) Synchronous callback
  } else if (data) {
    // ... packet processing ...
    client_->OnRead(this, std::move(packet));                 // (A') Synchronous callback
  }

  udp_socket_->ReceiveMore(1);                                // (B) UAF access here
}

The udp_socket_ member is a mojo::Remote<network::mojom::UDPSocket>. Since the access occurs on a freed this pointer and the member is a value type, MiraclePtr (BRP) does not provide protection in this specific code path.

Potential Destruction Chain

Based on code analysis, a suggested sequence for triggering the synchronous destruction in a Cast receiver context is:

  1. UdpSocket::OnReceived is called with a network error (net_result != net::OK).
  2. client_->OnRead is called, which notifies the openscreen::cast::Environment (third_party/openscreen/src/cast/streaming/public/environment.cc:145).
  3. The error propagates synchronously: Environment::OnError -> ReceiverSession::OnSocketInvalid -> ReceiverSessionClient::OnError (components/cast_streaming/browser/cast_streaming_session.cc:487).
  4. The application layer handles the error by calling StopApplication(), which executes receiver_session_client_.reset() (components/cast_receiver/browser/streaming_runtime_application.cc:100).
  5. This triggers a synchronous cascade of destructors, eventually calling ~UdpSocket() and freeing the memory while OnReceived is still on the stack.
  6. Control returns to UdpSocket::OnReceived, which dereferences the destructed udp_socket_ member.

Impact

This is a browser-process UAF. An attacker who can trigger this state (e.g., a compromised network process or potentially via crafted local network traffic in a Cast receiver environment) could achieve arbitrary code execution in the browser process by performing heap grooming during the synchronous teardown to control the freed memory.

Suggested Fix

The call to udp_socket_->ReceiveMore(1) should be guarded by a weak pointer check to ensure the object still exists after the client callback returns.

void UdpSocket::OnReceived(...) {
  base::WeakPtr<UdpSocket> weak_this = weak_ptr_factory_.GetWeakPtr();
  // ... existing callback logic ...
  if (weak_this) {
    udp_socket_->ReceiveMore(1);
  }
}

Alternatively, ensure that the destruction of the streaming session always occurs asynchronously (e.g., via base::SequencedTaskRunner::PostTask).

Evaluated with Chrome root at commit: b3153093eb3c78c3e88ccf562bcbc20437a04b0e


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