# SIPSorcery vulnerable to Denial of Service via out-of-bounds read in SCTP SACK chunk parsing

Unchecked SACK gap-ack/dup-TSN counts in SIPSorcery's SctpSackChunk.ParseChunk cause an out-of-bounds read that kills the SCTP receive thread, permanently DoSing all WebRTC data channels.

- Payout: Research
- Severity: high
- Program: SIPSorcery
- Found by: manus-use
- Disclosed: 2026-08-12
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-jwjp-4649-v8jp
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-jwjp-4649-v8jp
- Tags: area:oss domain:oss impact:dos kind:research platform:ghsa sev:high tech:websocket technique:source-review vuln:dos vuln:memory-corruption

**Target:** SCTP SACK chunk parser in WebRTC SCTP transport (RTCSctpTransport)
**Root cause:** SctpSackChunk.ParseChunk reads numGapAckBlocks and numDuplicateTSNs (up to 65535) from the attacker-controlled chunk and loops that many times reading 4 bytes each, without validating counts against chunk length or the 262144-byte receive buffer; NetConvert.ParseUInt16/32 index unchecked.
**Steps:**
1. Establish a negotiated WebRTC peer post-DTLS so SCTP packets reach RTCSctpTransport.DoReceive.
2. Craft a checksum-valid SCTP packet: 12-byte common header + SACK chunk (type 3) with `chunkLength=16`, `numGapAckBlocks=0xFFFF`, `numDuplicateTSNs=0xFFFF`; compute CRC32C.
3. Send it; DoReceive reads into reused 262144-byte recvBuffer and calls `SctpPacket.Parse(recvBuffer, 0, bytesRead)`.
4. ParseChunks validates only `chunkLength>=4` and `posn+chunkLength<=length`, then dispatches to SctpSackChunk.ParseChunk.
5. Gap-ack loop starts at reportPosn=28 and climbs +4 per iteration; at iteration 65529 reportPosn=262144 → `buffer[262144]` → IndexOutOfRangeException.
**How found:** Code review of SctpSackChunk.ParseChunk: noticed numGapAckBlocks/numDuplicateTSNs read directly from the chunk and used as loop counts with no validation against chunk length or buffer size, while ParseChunks only checks chunkLength; traced the OOB math 28+65535*4=262168 > 262144 and the exception-handling split in DoReceive.
**Exploitation:** A single crafted SACK chunk from a negotiated peer triggers IndexOutOfRangeException, a SystemException that skips the recoverable `catch (ApplicationException) { continue; }` and hits the generic `catch (Exception) { break; }`, exiting the once-started receive thread with no restart — permanently killing the SCTP association and all data channels.
**Insight:** When a length field is validated but inner count fields are not, compute the worst-case index from the count and compare to the actual buffer size; also check whether the resulting exception type is caught by the recoverable handler or falls through to a fatal break that kills a long-lived thread.

