Feb 20, 2026·7 min read·4 visits
Geth versions < 1.16.8 are vulnerable to a two-pronged DoS attack. Attackers can either crash the node process instantly by sending truncated encrypted messages (triggering a panic) or burn 100% CPU by flooding the node with invalid Blob transactions that force expensive KZG verification without disconnection.
A high-severity Denial of Service vulnerability in go-ethereum (Geth) allowing attackers to crash nodes via malformed ECIES handshakes or exhaust CPU resources using invalid EIP-4844 KZG proofs. This flaw exposes the fragility of the P2P layer when handling computationally expensive crypto operations.
Welcome back to the wonderful world of decentralized infrastructure, where a single bad line of code can bring down a billion-dollar network. Today, we are dissecting CVE-2026-22862, a nasty little Denial of Service (DoS) cocktail found in go-ethereum (Geth), the client that basically powers the entire Ethereum network.
This vulnerability is actually a "buy one, get one free" special. It combines two distinct flavors of failure. First, we have the modern, sophisticated attack vector stemming from EIP-4844 (Proto-Danksharding). This introduced "blobs"—huge chunks of data attached to transactions. To make sure these blobs are valid, we use Kate-Zaverucha-Goldreich (KZG) commitments. It’s heavy math. It’s expensive. And as it turns out, Geth was a bit too polite when handling people who lied about their math.
The second vector is a classic, old-school cryptographic fumble. It involves the Elliptic Curve Integrated Encryption Scheme (ECIES) used for P2P handshakes. While the first vector exhausts your CPU, this second vector is a sniper shot: a malformed packet that triggers a Go runtime panic, instantly killing the process. It’s the digital equivalent of tripping over your own shoelaces while holding a tray of crystal glasses.
Let’s break down the two flaws. The first is an Asymmetric Resource Consumption bug in the transaction pool. When a peer sends a blob transaction, the node must verify the KZG proof to ensure the data matches the commitment. This is CPU-intensive. The flaw was in the TxFetcher. If a peer sent a transaction with an invalid proof, Geth would burn the CPU cycles to verify it, realize it was garbage, log a polite error... and then keep the connection open.
This is the "Infinite Patience" anti-pattern. An attacker could flood a node with thousands of invalid blob transactions. Generating a fake proof is computationally free (just flip a byte). Verifying it is expensive. The attacker keeps feeding the node garbage, and the node politely eats it until it starves to death (CPU exhaustion).
The second flaw is a buffer underflow leading to a panic in the crypto/ecies package. The Decrypt function acts as the gatekeeper for encrypted P2P messages. It checks if the incoming message is long enough to contain the overhead (public key + HMAC). However, it forgot to account for the underlying AES block size. If you send a message that satisfies the overhead check but is still too short for a single AES block, the underlying cipher implementation throws a fit. In Go, an unrecovered panic in a goroutine crashes the entire program. Game over.
Let's look at the code, because nothing says "oops" like a git diff. First, the ECIES panic. This is a text-book input validation failure.
// crypto/ecies/ecies.go - The Vulnerable Code
func (prv *PrivateKey) Decrypt(c []byte, s1, s2 []byte) ([]byte, error) {
// ... (parsing logic)
// The check was too lenient:
// It only checked for overhead, ignoring the AES block size requirement.
if len(c) < (rLen + hLen + 1) {
return nil, fmt.Errorf("ecies: invalid message length")
}
// BOOM: If c is shorter than a full block, the AES decryption panics here.
return symDecrypt(params, key, c[rLen:len(c)-hLen])
}The fix was embarrassingly simple: enforce the block size.
// The Fix
if len(c) < (rLen + hLen + params.BlockSize) {
return nil, fmt.Errorf("ecies: invalid message length")
}Now for the KZG exhaustion in TxFetcher. The fix wasn't about math; it was about attitude. The developers had to teach the node to be rude.
// eth/fetcher/tx_fetcher.go
// BEFORE: Just an error, maybe try the next one?
if err := validateTx(tx); err != nil {
log.Debug("Invalid transaction", "err", err)
continue // Loop continues, peer stays connected
}
// AFTER: protocol violation -> immediate disconnect
if err := validateTx(tx); err != nil {
if errors.Is(err, txpool.ErrKZGVerificationError) {
// "Get off my lawn"
f.dropPeer(peer.id)
return
}
}Exploiting this requires a basic understanding of the Ethereum P2P wire protocol (RLPx). We don't even need to sync the chain; we just need to say "Hello" and then be annoying.
Attack Scenario A: The ECIES Nuke
R || C || d. R is the ephemeral public key (65 bytes), d is the HMAC (32 bytes).C to be non-empty but smaller than 16 bytes (AES block size). For example, 1 byte.len > 65+32+0), passes the header parsing, and attempts AES-128-CTR decryption.panic: index out of range or runtime error in the crypto library. The Geth process terminates immediately.Attack Scenario B: The KZG Swarm If the node is patched against the panic or you want to be subtle, you use the CPU exhaustion method.
NewPooledTransactionHashes message claiming you have juicy new blob transactions.GetPooledTransactions), send transactions where the Sidecar contains a mutated proof (cellProof[0][0] ^= 0xFF).Denial of Service bugs in blockchain clients are often dismissed as "annoyances," but in a decentralized network, they are critical infrastructure threats. Geth represents the super-majority of execution clients on Ethereum. If a vulnerability allows a cheap, remote crash (like the ECIES panic), a single attacker could theoretically knock offline 70-80% of the network's validators in minutes.
This isn't just about nodes going offline. It's about Finality. If enough validators crash simultaneously, the chain stops finalizing blocks. The network partitions. DeFi protocols relying on timely updates get liquidated. Oracles fail. It is a mess.
The KZG vector is subtler but equally dangerous for individual node operators. It allows for targeted griefing. Competitors could exhaust specific validator nodes to make them miss attestations, causing them to get slashed (penalized) by the protocol.
The remediation is straightforward: Update to Geth v1.16.8. There are no config flags or weird environment variables that will save you here. The code itself is broken.
If you are a developer writing P2P protocols, let this be a lesson:
aes.Decrypt handles garbage gracefully.> [!NOTE]
> The patch introduces a dropPeer mechanism specifically for KZG errors. This is a specific counter-measure ensuring that computational asymmetry cannot be weaponized.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
go-ethereum Ethereum Foundation | < 1.16.8 | 1.16.8 |
| Attribute | Detail |
|---|---|
| CWE | CWE-20 (Improper Input Validation) |
| Attack Vector | Network (P2P) |
| CVSS v3.1 | 7.5 (High) |
| Impact | Denial of Service (Crash & Resource Exhaustion) |
| Component | core/txpool & crypto/ecies |
| Exploit Status | PoC Available |