GHSA-jwjp-4649-v8jp

Suggest an improvement
Source
https://github.com/advisories/GHSA-jwjp-4649-v8jp
Import Source
https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/08/GHSA-jwjp-4649-v8jp/GHSA-jwjp-4649-v8jp.json
JSON Data
https://api.osv.dev/v1/vulns/GHSA-jwjp-4649-v8jp
Published
2026-08-12T19:30:43Z
Modified
2026-08-12T19:45:10Z
Severity
  • 7.5 (High) CVSS_V3 - CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H CVSS Calculator
Summary
SIPSorcery vulnerable to Denial of Service via out-of-bounds read in SCTP SACK chunk parsing
Details

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)+FIXED_PARAMETERS(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 + 65529*4 = 262144buffer[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 + 65535*4 = 262168 > 262144; buffer is 262144 (DEFAULT_ADVERTISED_RECEIVE_WINDOW, 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 + 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

Database specific
{
    "cwe_ids":  [
        "CWE-125",
        "CWE-755"
    ],
    "github_reviewed":  true,
    "github_reviewed_at":  "2026-08-12T19:30:43Z",
    "nvd_published_at":  null,
    "severity":  "HIGH"
}
References

Affected packages

NuGet / SIPSorcery

Package

Name
SIPSorcery
View open source insights on deps.dev
Purl
pkg:nuget/SIPSorcery

Affected ranges

Type
ECOSYSTEM
Events
Introduced
0 Unknown introduced version / All previous versions are affected
Fixed
10.0.14

Affected versions

1.*
1.3.0-PRE
1.3.1
1.4.0
1.4.1
1.5.0
1.5.2
1.5.3
1.5.5
1.5.6
1.6.0
1.6.1
1.6.2
2.*
2.0.0
2.0.1
3.*
3.0.0
3.0.1
3.0.2
3.0.3
3.0.4
3.1.0
3.2.0
3.3.0
3.4.0
3.5.0
3.6.0
4.*
4.0.0-rc
4.0.1-rc
4.0.2-rc
4.0.3-rc
4.0.4-rc
4.0.7-rc
4.0.8-rc
4.0.13-pre
4.0.28-pre
4.0.29-pre
4.0.30-pre
4.0.31-pre
4.0.32-pre
4.0.33-pre
4.0.34-pre
4.0.35-pre
4.0.40-pre
4.0.41-pre
4.0.42-pre
4.0.43-pre
4.0.44-pre
4.0.45-pre
4.0.46-pre
4.0.47-pre
4.0.49-pre
4.0.50-pre
4.0.51-pre
4.0.55-pre
4.0.58-pre
4.0.59-pre
4.0.60-pre
5.*
5.1.0
5.1.1
5.1.2
5.1.4-pre
5.1.5-pre
5.1.6-pre
5.1.7-pre
5.1.8-pre
5.2.0
5.2.3
5.3.0-pre
5.3.3-pre
6.*
6.0.1-pre
6.0.2
6.0.3
6.0.4
6.0.6
6.0.7
6.0.8
6.0.9
6.0.11
6.0.12
6.1.0-pre
6.1.1-pre
6.2.0
6.2.1
6.2.3
6.2.4
8.*
8.0.0
8.0.1
8.0.3
8.0.4
8.0.5
8.0.6
8.0.7
8.0.9
8.0.10
8.0.11
8.0.12
8.0.13
8.0.14
8.0.15-pre
8.0.20-pre
8.0.21-pre
8.0.22
8.0.23
10.*
10.0.1
10.0.2
10.0.3
10.0.4-pre
10.0.5
10.0.6
10.0.7
10.0.8
10.0.9
10.0.10
10.0.11
10.0.12
10.0.13

Database specific

last_known_affected_version_range
"<= 10.0.13"
source
"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/08/GHSA-jwjp-4649-v8jp/GHSA-jwjp-4649-v8jp.json"