Skip to main content
CVE Vulnerability Database
Vulnerability Database/CVE-2026-59803

CVE-2026-59803: rpcx Denial-of-Service Vulnerability

CVE-2026-59803 is a denial-of-service vulnerability in rpcx through version 1.9.3, allowing unauthenticated attackers to exhaust memory via compressed messages. This article covers technical details, affected versions, and mitigation.

Published:

CVE-2026-59803 Overview

CVE-2026-59803 is a denial-of-service vulnerability in the rpcx Go RPC framework through version 1.9.3. The flaw resides in protocol.Message.Decode inside protocol/message.go. When a message has the compression flag set, the payload is gzip-decompressed through util.Unzip with no cap on the decompressed output size. The only built-in size guard, protocol.MaxMessageLength, is checked against the compressed wire-frame length, not the decompressed size. Because decoding runs inside readRequest before authentication, a single unauthenticated connection can trigger the flaw. The issue is fixed in commit 047aec1.

Critical Impact

An unauthenticated attacker can send a sub-2 MB gzip-compressed message that expands to multiple gigabytes of heap allocation, causing out-of-memory conditions and full service unavailability.

Affected Products

  • rpcx versions through 1.9.3
  • rpcx servers exposing the wire protocol to untrusted peers
  • Fixed in rpcx commit 047aec1 (Pull Request #943)

Discovery Timeline

  • 2026-07-08 - CVE-2026-59803 published to NVD
  • 2026-07-08 - Last updated in NVD database

Technical Details for CVE-2026-59803

Vulnerability Analysis

The vulnerability is a classic decompression bomb, classified under [CWE-409] Improper Handling of Highly Compressed Data. The rpcx wire protocol allows clients to set a compression flag inside each message header. When set, the server invokes util.Unzip on the payload during Message.Decode. The decompression routine writes into an unbounded in-memory buffer.

The server enforces MaxMessageLength against the on-the-wire frame length only. A gzip payload with a very high compression ratio bypasses this check while still expanding to gigabytes in memory. Decoding runs inside readRequest, which executes before any authentication handler runs. Attackers do not need credentials or prior session state to trigger the condition.

A single TCP connection sending a payload under 2 MB can force the server to allocate multi-gigabyte heap regions. The Go runtime terminates the process with an out-of-memory error, taking down the RPC service.

Root Cause

The root cause is missing output-size enforcement during gzip decompression. util.Unzip reads the compressed stream until end-of-stream without applying a byte ceiling. protocol.MaxMessageLength was designed to bound frame size but does not propagate to the decompressed length, leaving decoders without a defensive limit.

Attack Vector

The attack requires only network reachability to the rpcx service port. The attacker crafts a gzip stream containing repetitive data that compresses at ratios exceeding 1000:1. The malicious frame is sent as a standard rpcx message with the compression bit set in the header. The server decodes and decompresses the payload before dispatching to authenticated handlers.

go
// Security patch: protocol/compressor.go
// Source: https://github.com/smallnest/rpcx/commit/047aec18efa7d037105e2b72c36dd2ae05e1acc6
 	Unzip([]byte) ([]byte, error)
 }
 
+// LimitedUnzipper is an optional interface a Compressor can implement to cap
+// the size of decompressed data, guarding against decompression-bomb attacks.
+// If a compressor implements it, Message.Decode uses it when
+// MaxDecompressedSize is set. maxSize <= 0 means no limit.
+type LimitedUnzipper interface {
+	UnzipLimited(data []byte, maxSize int64) ([]byte, error)
+}
+
 // GzipCompressor implements gzip compressor.
 type GzipCompressor struct {
 }

The patch introduces a LimitedUnzipper interface and a new MaxDecompressedLength variable in protocol/message.go that bounds the decompressed payload size before allocation occurs.

Detection Methods for CVE-2026-59803

Indicators of Compromise

  • Sudden Go runtime runtime: out of memory panics in rpcx server logs without corresponding legitimate traffic volume
  • Small inbound TCP frames (under 2 MB) followed by rapid resident memory growth of the rpcx process
  • Repeated short-lived connections from a single source terminating shortly after sending one compressed message
  • Process crashes or restarts of rpcx workers with no application-layer stack traces beyond the decoder path

Detection Strategies

  • Monitor rpcx process resident set size (RSS) and correlate spikes against inbound connection metadata
  • Inspect network telemetry for frames with the rpcx compression flag set originating from untrusted networks
  • Alert on process crash-loop patterns for services built on github.com/smallnest/rpcx
  • Deploy application-layer logging around Message.Decode calls to surface anomalous decompression ratios

Monitoring Recommendations

  • Track memory allocation rates on hosts running rpcx and trigger alerts on sudden multi-gigabyte jumps
  • Instrument OOM killer events at the kernel level and correlate with rpcx PID lifecycle
  • Baseline normal compressed message sizes to identify statistical outliers indicating bomb payloads
  • Log source IP addresses of connections that precede process termination for post-incident analysis

How to Mitigate CVE-2026-59803

Immediate Actions Required

  • Update rpcx to a build containing commit 047aec1 or later from the rpcx repository
  • Configure protocol.MaxDecompressedLength to a value appropriate for legitimate workloads (for example, 16 MB or 32 MB)
  • Restrict network exposure of rpcx endpoints to trusted peers where feasible using firewall rules or service mesh policies
  • Deploy per-process memory limits via cgroups or container runtime settings to contain OOM impact

Patch Information

The fix is available in rpcx commit 047aec1, merged through Pull Request #943. The patch adds a LimitedUnzipper interface in protocol/compressor.go and a MaxDecompressedLength global in protocol/message.go. When set, Message.Decode calls UnzipLimited instead of the unbounded Unzip. Consult the VulnCheck RPCX DoS Advisory and GitHub Issue #942 for full remediation context.

Workarounds

  • Place rpcx behind an authenticating reverse proxy or mTLS gateway to eliminate unauthenticated attacker access
  • Enforce OS-level memory ceilings using systemdMemoryMax= or Kubernetes container resources.limits.memory to force fast fail and restart instead of host exhaustion
  • Implement rate limiting and connection quotas per source IP on upstream load balancers
  • Disable compressed message acceptance on internet-facing rpcx services if the application does not require it
bash
# Configuration example: set decompression cap in Go code before starting server
# import "github.com/smallnest/rpcx/protocol"
# protocol.MaxMessageLength = 4 * 1024 * 1024      // 4 MB compressed frame cap
# protocol.MaxDecompressedLength = 32 * 1024 * 1024 // 32 MB decompressed cap

# Kubernetes container memory cap to bound blast radius
resources:
  limits:
    memory: "512Mi"
  requests:
    memory: "256Mi"

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Default Legacy - Prefooter | Experience the World’s Most Advanced Cybersecurity Platform

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.