High · GHSA-28gm-jrmw-xx93 Fixed · merged C# / VoIP · WebRTC

One malformed UDP packet could tear down a SIPSorcery media session

TargetSIPSorcery (.NET)
ClassPre-auth remote DoS
Triggerone malformed UDP packet
ReportedPrivately, before fix
FixedPR #1677 (merged)

SIPSorcery is a widely used .NET stack for real-time communications: SIP telephony, VoIP, and WebRTC. Like every RTC stack, its media plane lives on UDP: audio and video arrive as RTP packets, and the connection is negotiated with ICE, whose keep-alives are STUN packets. That media socket takes bytes straight off the network, before any authentication. That is simply how real-time media works.

We found that a single crafted UDP packet, sent by anyone who could reach that port, could crash the receive path and close the entire RTP/ICE channel, dropping the call. No handshake, no credentials, no session state required. One packet.

Send one short, malformed RTP or STUN packet at the media socket and the receiver throws while parsing it, and then tears down the whole channel in response.

Two small assumptions that together are fatal

The bug is the seam between two pieces of code that are each locally reasonable:

Neither is obviously wrong on its own. A parser may assume well-formed input; a receive loop may want to fail loudly. But put them together on a socket that accepts unauthenticated packets from the open network, and the invariant that actually matters, “a malformed packet is dropped, not fatal,” is violated. One packet drives the channel into the closed state.

// the shape of the receive path, before the fix
OnPacket(byte[] buf) {
    var pkt = RTPPacket.Parse(buf);      // reads fixed offsets; a short buf throws
    ...
}
OnException(ex) {
    Close();                             // one bad packet -> whole channel torn down
}

Because UDP is connectionless and the source address is spoofable, the attacker needs no place in the call and no prior packets. The media port is discoverable from the SDP/ICE exchange, and a single datagram is enough to end an in-progress session: a clean, cheap, pre-authentication denial of service.

The fix

SIPSorcery PR #1677 (merged) closes both halves of the seam:

The issue was reported privately ahead of the fix and is tracked as advisory GHSA-28gm-jrmw-xx93 (High). If you build on SIPSorcery, take the release that includes PR #1677.

Why this is the kind of bug RedMirror finds

A parser that reads fixed offsets and a receive loop that closes on error each pass code review in isolation; nothing in either file is a “known-bad” pattern a linter flags. The defect only exists in the relationship between them, on the specific socket that receives untrusted input. RedMirror models how a packet actually flows through the receive path and looks for a reachable state where an unauthenticated input drives the system somewhere it shouldn't go: here, an active channel reaching closed with no consent from either peer. It reports the concrete input that gets there, so the maintainer can reproduce it before an attacker does.

Find the pre-auth edges in your own stack

Anything that parses untrusted bytes off a socket (media, protocol handlers, deserializers) has a seam like this. RedMirror audits for exactly the shape: an unauthenticated input that reaches a bad state, reported as a concrete, reproducible path.

Start an audit Read the docs