Summary
SIPSorcery vulnerable to Denial of Service via out-of-bounds read in SCTP SACK chunk parsing
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 validateschunkLength >= 4andposn+chunkLength <= length; the counts inside the value are never checked.RTCSctpTransport.DoReceivecallsSctpPacket.Parse(recvBuffer, 0, bytesRead)on a reusedrecvBuffer = new byte[262144].
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
- 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. - Processing:
DoReceive(RTCSctpTransport.cs:286) reads into reusedrecvBuffer(262144 bytes, :280) →SctpPacket.Parse(recvBuffer, 0, bytesRead)(:302) →ParseChunks→ SACK dispatch (SctpChunk.Parse:340-341) →SctpSackChunk.ParseChunk. Guard:ParseChunkschecks onlychunkLength>=4andposn+chunkLength<=length(SctpPacket.cs:195-203). Bypass:chunkLength=16is well-formed; the counts are never validated. - Sink: gap-ack loop (SctpSackChunk.cs:146) calls
NetConvert.ParseUInt16(buffer, reportPosn)withreportPosnstarting atstartPosn(16)+FIXED_PARAMETERS(12)=28, climbing+4each iteration. Guard: none on the count. Bypass:NetConvert.ParseUInt16(NetConvert.cs:30) indexesbuffer[posn]unchecked. - Impact: at iteration 65529,
reportPosn = 28 + 65529*4 = 262144→buffer[262144]→IndexOutOfRangeException→ genericcatchat 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.ParseUInt16unchecked indexing (NetConvert.cs:30).ParseChunksvalidates onlychunkLength(SctpPacket.cs:195-203).- OOB math:
28 + 65535*4 = 262168 > 262144; buffer is 262144 (DEFAULT_ADVERTISED_RECEIVE_WINDOW, SctpAssociation.cs:62).numGapAckBlocksalone suffices, the dup-TSN loop is not needed. DoReceivecatch split: recoverablecatch(ApplicationException)at :345 (continue) vs genericcatch(Exception)at :356 (break);_receiveThreadstarted 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.
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).
A read operation accesses a memory location beyond the intended buffer boundary. Typical impact: sensitive data disclosure or crash.
GHSA-JWJP-4649-V8JP has a CVSS score of 7.5 (High). The vector is network-reachable, no privileges required, and no user interaction. A CVSS score reflects the worst-case severity of the vulnerability, not your specific exposure. Whether this affects your application depends on whether the vulnerable code is present and reachable in your environment. A fixed version is available (10.0.14); upgrading removes the vulnerable code path.
Affected versions
Security releases
Kodem intelligence
Severity tells you how bad this could be in the worst case. It does not tell you whether you are exposed. Exploitability and impact are functions of runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A vulnerable package can sit in your dependency tree and never run.
Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter. Kodem's runtime-powered SCA identifies whether this CVE is reachable in your applications.
Already deployed Kodem?
See it in your environmentNew to Kodem? Get a demo →Remediation advice
Validate startPosn + FIXED_PARAMETERS_LENGTH + numGapAckBlocks*4 + numDuplicateTSNs*4 <= 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
Frequently Asked Questions
- What is GHSA-JWJP-4649-V8JP? GHSA-JWJP-4649-V8JP is a high-severity out-of-bounds read vulnerability in SIPSorcery (nuget), affecting versions <= 10.0.13. It is fixed in 10.0.14. A read operation accesses a memory location beyond the intended buffer boundary.
- How severe is GHSA-JWJP-4649-V8JP? GHSA-JWJP-4649-V8JP has a CVSS score of 7.5 (High). This score reflects the worst-case severity of the vulnerability, not your specific exposure. Whether it represents real risk in your environment depends on whether the vulnerable code is present and reachable.
- Which versions of SIPSorcery are affected by GHSA-JWJP-4649-V8JP? SIPSorcery (nuget) versions <= 10.0.13 is affected.
- Is there a fix for GHSA-JWJP-4649-V8JP? Yes. GHSA-JWJP-4649-V8JP is fixed in 10.0.14. Upgrade to this version or later.
- Is GHSA-JWJP-4649-V8JP exploitable, and should I be worried? Whether GHSA-JWJP-4649-V8JP is exploitable in your environment depends on whether the vulnerable code is present and reachable. A CVSS score is a worst-case rating; it does not account for your specific deployment, configuration, or usage patterns. Kodem, an Intelligent Application Security platform, uses runtime intelligence to show which vulnerabilities actually execute in production, so you can focus on the ones that represent real risk. Get a demo
- What actually determines whether GHSA-JWJP-4649-V8JP is exploitable, and how bad it is? Exploitability and impact are not fixed properties of a CVE. They depend on runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A high CVSS score on a dependency that never runs is not the same as real risk. Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter.
- How do I fix GHSA-JWJP-4649-V8JP? Upgrade
SIPSorceryto 10.0.14 or later.