CVE-2026-123805: SIPSorcery vulnerable to Denial of Service via out-of-bounds read in SCTP SACK chunk parsing
Summary SctpSackChunk.ParseChunk reads the numGapAckBlocks and numDuplicateTSNs fields (each up to 65535) directly from an attacker-controlled SCTP SACK chunk and loops that many times reading 4 bytes per iteration, with no validation of the counts against the chunk length or the receive buffer. A single crafted SACK chunk from a negotiated WebRTC peer forces reads past the end of the 262144-byte receive buffer, raising IndexOutOfRangeException, which is not caught by the recoverable handler and terminates the dedicated SCTP receive thread — permanently killing the SCTP association and all data channels.
Root Cause src/SIPSorcery/net/SCTP/Chunks/SctpSackChunk.cs: - ushort numGapAckBlocks = NetConvert.ParseUInt16(buffer, startPosn + 8); (:141) - ushort numDuplicateTSNs = NetConvert.ParseUInt16(buffer, startPosn + 10); (:142) - gap-ack loop (:146) and duplicate-TSN loop (:154) index the buffer via NetConvert.ParseUInt16/32 (buffer[posn], no bounds check — sys/Net/NetConvert.cs:30,41). SctpPacket.ParseChunks (SctpPacket.cs:195-203) only validates chunkLength >= 4 and posn+chunkLength <= length; the counts inside the value are never checked. RTCSctpTransport.DoReceive calls SctpPacket.Parse(recvBuffer, 0, bytesRead) on a reused recvBuffer = new byte[262144].
Impact IndexOutOfRangeException is a SystemException, not ApplicationException, so the recoverable catch (ApplicationException) { … continue; } at RTCSctpTransport.cs:345 is skipped and control falls to the generic catch (Exception) { … break; } at :356. The break exits the receive loop, DoReceive returns, and the dedicated receiveThread = new Thread(DoReceive) (:173, started once) exits with no restart → the SCTP association and every data channel are permanently dead (denial of service).
Proof of Concept A negotiated WebRTC peer (post-DTLS) sends a checksum-valid SCTP packet: 12-byte common header + a SACK chunk (type 3) with chunkLength=16, numGapAckBlocks=0xFFFF, numDuplicateTSNs=0xFFFF. CRC32C is attacker-computable. The gap-ack loop reaches buffer[262144] on a 262144-byte array (valid indices 0..262143) → IndexOutOfRangeException.
Attack Chain 1. Entry: post-DTLS negotiated peer sends a checksum-valid SCTP packet with a SACK chunk (chunkLength=16, numGapAckBlocks=0xFFFF). Guard: VerifyChecksum (CRC32C). Bypass: CRC32C is computable by the sender. 2. Processing: DoReceive (RTCSctpTransport.cs:286) reads into reused recvBuffer (262144 bytes, :280) → SctpPacket.Parse(recvBuffer, 0, bytesRead) (:302) → ParseChunks → SACK dispatch (SctpChunk.Parse :340-341) → SctpSackChunk.ParseChunk. Guard: ParseChunks checks only chunkLength>=4 and posn+chunkLength<=length (SctpPacket.cs:195-203). Bypass: chunkLength=16 is well-formed; the counts are never validated. 3. Sink: gap-ack loop (SctpSackChunk.cs:146) calls NetConvert.ParseUInt16(buffer, reportPosn) with reportPosn starting at startPosn(16)+FIXEDPARAMETERS(12)=28, climbing +4 each iteration. Guard: none on the count. Bypass: NetConvert.ParseUInt16 (NetConvert.cs:30) indexes buffer[posn] unchecked. 4. Impact: at iteration 65529, reportPosn = 28 + 655294 = 262144 → buffer[262144] → IndexOutOfRangeException → generic catch at RTCSctpTransport.cs:356 → break → receive thread exits, no restart → association permanently dead.
Bypass Evidence - Unchecked counts at SctpSackChunk.cs:141-142; loops at :146,:154. - NetConvert.ParseUInt16 unchecked indexing (NetConvert.cs:30). - ParseChunks validates only chunkLength (SctpPacket.cs:195-203). - OOB math: 28 + 655354 = 262168 > 262144; buffer is 262144 (DEFAULTADVERTISEDRECEIVEWINDOW, SctpAssociation.cs:62). numGapAckBlocks alone suffices — the dup-TSN loop is not needed. - DoReceive catch split: recoverable catch(ApplicationException) at :345 (continue) vs generic catch(Exception) at :356 (break); receiveThread started once at :176.
Affected Versions nuget:SIPSorcery <= 10.0.13 (verified present on release tag v10.0.13 and HEAD da944543).
Dedup NOT a duplicate of GHSA-qmvg-569h-hqrh — that fix (fe5a1fa) touched only SctpPacket.cs (the chunk-cursor zero-length infinite loop, CWE-835). This is a distinct out-of-bounds read (CWE-125) in SctpSackChunk count loops, untouched by that fix.
Suggested Fix Validate startPosn + FIXEDPARAMETERSLENGTH + numGapAckBlocks4 + numDuplicateTSNs4 <= posn + chunkLen before the loops, and/or make NetConvert.Parse bounds-checked, and/or treat IndexOutOfRangeException/ArgumentException as recoverable in DoReceive.
--- Reported by zx (Jace) — GitHub: @manus-use
Other sources
SIPSorcery is a WebRTC, SIP, and VoIP library for C# and .NET. Prior to 10.0.14, SctpSackChunk.ParseChunk reads the numGapAckBlocks and numDuplicateTSNs fields from an attacker-controlled SCTP SACK chunk without checking that the corresponding entries fit the declared chunk length. A negotiated WebRTC peer can send a checksum-valid malformed SACK chunk that drives the parser beyond the 262144-byte receive buffer. The resulting IndexOutOfRangeException bypasses the recoverable ApplicationException handler in RTCSctpTransport.DoReceive, causing the generic handler to exit the dedicated receive loop and permanently terminate the SCTP association and all data channels. This issue is fixed in 10.0.14.
— MITRE
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
nuget/SIPSorceryto a version that resolves this vulnerability.Fixed in 10.0.14 - Upgrade
Upgrade
nuget:SIPSorceryto a version that resolves this vulnerability.Fixed in 10.0.14
Event History
Frequently Asked Questions
Who can exploit this issue?
A negotiated WebRTC peer can exploit it by sending a checksum-valid malformed SCTP SACK chunk. No authentication, user interaction, or special privileges are required according to the supplied severity vector.
What is the operational impact of a successful exploit?
The malformed chunk can cause an IndexOutOfRangeException that terminates the dedicated SCTP receive loop. This permanently ends the SCTP association and all associated data channels, resulting in denial of service.
Which versions should be remediated?
SIPSorcery versions prior to 10.0.14 are affected. The issue is fixed in version 10.0.14.