Back to Blog

GHSA-c677-q3wr-gggq: Remote DoS in Valkey's Cluster Bus

Tobias Jensen

GHSA-c677-q3wr-gggq: Remote DoS in Valkey's Cluster Bus

A medium-severity vulnerability (CVSS 6.5) in Valkey lets an unauthenticated attacker crash any cluster node with a single malformed packet. The cluster bus trusts an attacker-controlled gossip count, computes a pointer past the end of the receive buffer, dereferences it, and the process dies with a SIGSEGV.

You need zero credentials and zero complexity. One crafted PING/PONG/MEET frame to the cluster bus port takes the node down.

The bug

Attacker-controlled gossip count

medium

The count field in a PING/PONG/MEET packet is read directly from the wire with no upper-bound check against the actual packet size.

Unbounded pointer arithmetic

high

getInitialPingExt() computes a pointer at gossip[count], landing past the receive buffer when count exceeds the real payload.

Immediate dereference

critical

getPingExtLength() reads ext->length at the out-of-bounds address before any size validation runs. The process crashes.

Where

clusterIsValidPacket() in src/cluster_legacy.c is supposed to reject malformed cluster bus packets before they reach the handler. For PING, PONG, and MEET message types, it parses the gossip section and any trailing extension data.

The function reads count (the number of gossip entries) from the packet header:

uint16_t extensions = ntohs(msg->extensions);
uint16_t count = ntohs(msg->count);

explen = sizeof(clusterMsg) - sizeof(union clusterMsgData);
explen += (sizeof(clusterMsgDataGossip) * count);

explen now holds the expected packet size based on the gossip count. When the extension flag is set, the code computes a pointer to the first extension:

if (msg->mflags[0] & CLUSTERMSG_FLAG0_EXT_DATA) {
    clusterMsgPingExt *ext = getInitialPingExt(msg, count);
    while (extensions--) {
        uint32_t extlen = getPingExtLength(ext); // dereferences OOB pointer
        if (extlen % 8 != 0) {
            return 0;
        }
        if ((totlen - explen) < extlen) {
            return 0;
        }
        explen += extlen;
        ext = getNextPingExt(ext);
    }
}

The getInitialPingExt helper does raw array indexing with the attacker-supplied count:

static clusterMsgPingExt *getInitialPingExt(clusterMsg *hdr, int count) {
    clusterMsgPingExt *initial = (clusterMsgPingExt *)&(hdr->data.ping.gossip[count]);
    return initial;
}

The size check (totlen - explen) < extlen sits inside the loop, but it runs after getPingExtLength(ext) dereferences the pointer. If count exceeds what totlen can hold, getInitialPingExt produces a pointer into unmapped memory. getPingExtLength reads from that address and the process segfaults before validation can reject the packet.

The ordering problem

Validation runs after the dereference. (totlen - explen) < extlen could catch the mismatch, but getPingExtLength has already read from an invalid address.

The attack

Attack sequence

Attacker connects to cluster bus (port 16379)

TCP connection, no authentication required

Sends PING/MEET with count=100, extensions=1

Actual packet body contains no gossip data

clusterIsValidPacket reads count from header

explen = base + (sizeof(gossip) * 100)

getInitialPingExt(msg, 100)

Computes pointer at gossip[100], far past buffer end

getPingExtLength(ext) dereferences OOB pointer

Reads ext->length from unmapped heap memory

SIGSEGV, node crashes

Cluster loses a node, failover and rebalancing begin

An attacker needs TCP access to the cluster bus port, which defaults to 16379 (data port + 10000). The cluster bus has no authentication handshake. One packet crashes one node.

The fix

Commit 61f990f adds two bounds checks before the pointer dereference.

Vulnerable (pre-61f990f)Fixed
 explen = sizeof(clusterMsg) - sizeof(union clusterMsgData); explen += (sizeof(clusterMsgDataGossip) * count); -// No check — falls straight into extension parsing+// Check 1: gossip entries must fit in the packet+if (totlen < explen) {+    serverLog(LL_WARNING, "...");+    return 0;+}+ if (msg->mflags[0] & CLUSTERMSG_FLAG0_EXT_DATA) {     clusterMsgPingExt *ext = getInitialPingExt(msg, count);     while (extensions--) {+        // Check 2: room for extension header before read+        if ((totlen - explen) < sizeof(clusterMsgPingExt)) {+            serverLog(LL_WARNING, "...");+            return 0;+        }         uint32_t extlen = getPingExtLength(ext);         // ...     } }

Check 1 confirms totlen can hold the gossip entries implied by count before getInitialPingExt computes the pointer. An inflated count gets the packet rejected.

Check 2 confirms at least sizeof(clusterMsgPingExt) bytes remain before each call to getPingExtLength. The dereference now sits behind a guard.

Impact

Who is affected

Any Valkey deployment with cluster-enabled yes running version 9.0.2 or earlier. The cluster bus port accepts connections without authentication by default. If an attacker can reach it, they can crash the node.

Production clusters failover and rebalance when a node goes down. An attacker who crashes multiple nodes can degrade or kill the cluster.

Attack surface

The cluster bus port is the data port + 10000 (default: 16379). Most deployments expose it on the same network as the data port with no additional access controls. Cloud deployments behind security groups that allow intra-VPC traffic on the port range are reachable from any compromised host in the VPC.

Recommendations

Mitigations

Upgrade to patched versions: 9.0.3, 8.1.6, 8.0.7, or 7.2.12.

Restrict cluster bus port access. Place firewall rules or security groups that limit connections to the cluster bus port to known cluster member IPs only.

Separate the cluster bus network. Run cluster bus traffic on a dedicated interface or VLAN isolated from application traffic.

Monitor for anomalous connections. Alert on TCP connections to the cluster bus port from non-cluster sources.

CWE classification

CWE-125: Out-of-bounds Read. clusterIsValidPacket reads past the receive buffer because it does not validate an attacker-controlled array index before dereferencing the computed pointer.

Advisory details

FieldValue
Advisory IDGHSA-c677-q3wr-gggq
CVECVE-2026-21863
SeverityMedium (CVSS 6.5)
Affected packagevalkey-server
Affected versions9.0.2 and earlier
Patched versions9.0.3, 8.1.6, 8.0.7, 7.2.12
CWECWE-125
Reporter@0xkato

Further reading