Feb 20, 2026·6 min read·11 visits
Attackers can spam Geth nodes with invalid EIP-4844 blob transactions. The node wastes massive CPU cycles verifying these bogus cryptographic proofs before dropping the connection. This leads to a complete Denial of Service.
A critical Denial of Service (DoS) vulnerability in go-ethereum (Geth) versions prior to 1.16.8 allows attackers to crash nodes via the P2P layer. By flooding a node with invalid KZG proofs (introduced in EIP-4844), an attacker can trigger asymmetric resource exhaustion, forcing the victim to perform expensive elliptic curve pairing operations for free until the CPU hits 100% and the node stalls.
In the Ethereum ecosystem, the concept of 'Gas' is religion. You want the EVM to compute something? You pay for it. This economic friction prevents infinite loops and resource abuse. But there is a dark alleyway where Gas doesn't exist: the P2P layer (devp2p). Before a transaction makes it into a block and costs money, it floats around the mempool, whispered from peer to peer.
CVE-2026-22868 is what happens when complex cryptography meets optimistic networking. With the introduction of EIP-4844 (Proto-Danksharding), Ethereum added 'blobs'—cheap data storage attached to transactions. To ensure this data is valid, we use KZG (Kate-Zaverucha-Goldberg) commitments.
Here's the rub: Verifying a KZG proof involves elliptic curve pairings. In computational terms, a pairing is expensive. It's like asking a bouncer to solve a Sudoku puzzle before letting someone in. This vulnerability allows an attacker to line up thousands of fake people at the club entrance, handing the bouncer impossible Sudoku puzzles. The bouncer (your CPU) spends all night trying to solve them, while legitimate guests (actual transactions) are left standing in the rain.
The root cause isn't a buffer overflow or a memory leak; it's algorithmic asymmetry. Generating a garbage byte string is instant. Verifying that byte string as a valid KZG proof against a commitment takes milliseconds of pure CPU grind.
In versions of Geth prior to 1.16.8, the TxFetcher (the component that grabs transactions from peers) was too polite. When a peer sent a batch of transactions containing blob sidecars, the node would dutifully attempt to verify the KZG proofs for each one.
The fatal flaw was in the error handling logic. When a proof failed verification, the node would mark it as invalid, but it wouldn't immediately realize it was under attack. It lacked a 'fail-fast' mechanism for this specific vector. This meant an attacker could establish a connection and stream a firehose of invalid blobs. The victim node would peg a core at 100% usage churning through kzg4844.VerifyBlobProof calls.
To add insult to injury, there was a secondary, dumber flaw in the ECIES (encryption) layer. The handshake logic allowed for messages where the ciphertext length was technically valid by one check but too short for the actual block size, leading to further wasted cycles in the decryption routine before the code realized it was processing junk.
Let's look at the patch in eth/fetcher/tx_fetcher.go. The fix is simple but revealing: it introduces a 'drop dead' mechanism.
Before the fix, the fetcher would process the batch. After the fix, the developers explicitly map the ErrKZGVerificationError to a protocol violation.
// eth/fetcher/tx_fetcher.go (The Fix)
// ... inside the transaction processing loop ...
if err := t.validate(tx); err != nil {
// The new check: Is this a KZG error?
if errors.Is(err, txpool.ErrKZGVerificationError) {
// MARK THE VIOLATION
violation = err
break // Stop processing this batch immediately
}
}
// ... later in the function ...
if delivery.violation != nil {
log.Warn("Disconnect peer for protocol violation",
"peer", delivery.origin,
"error", delivery.violation)
// THE BAN HAMMER
f.dropPeer(delivery.origin)
}The key change is treating a KZG failure not just as a 'bad transaction' but as a hostile act. If you send me bad math, we aren't friends anymore.
They also hardened crypto/ecies/ecies.go to enforce block size limits earlier:
// crypto/ecies/ecies.go
- if len(c) < (rLen + hLen + 1) {
+ if len(c) < (rLen + hLen + params.BlockSize) {This small change prevents the CPU from engaging the elliptic curve Diffie-Hellman (ECDH) logic on packets that are obviously too small to contain a valid payload.
Exploiting this requires a custom devp2p client (or a modified version of Geth). You cannot trigger this via RPC; you must speak the wire protocol on port 30303.
Here is the attack chain:
NewPooledTransactionHashes message (ETH protocol version 68).blob_kzg_commitments, insert random valid curve points. For the blob_proofs, insert random junk data.GetPooledTransactions, send the poisoned payload.The Result:
By the time the node realizes the 100th proof is bad, it has wasted significant time. If the attacker opens 50 concurrent connections and rotates them, the node becomes unresponsive to legitimate peers and falls out of sync with the network.
This is a High Availability (HA) nightmare. For a solo staker, your node crashing means missing attestations and losing money. For an infrastructure provider (like Infura or Alchemy), it means degraded service availability.
Because this attack is low-cost (the attacker generates junk, the victim computes math), it is highly asymmetric.
The fix is straightforward: Update to Geth v1.16.8.
If you cannot update immediately (why?), you can mitigate this by restricting your P2P port (30303) to trusted peers only, effectively converting your node into a private sentry. However, this stops you from discovering new peers and is not a viable long-term solution for a public blockchain node.
> [!NOTE] > If you are running a multi-client setup (e.g., for staking), check if your other clients (Lighthouse, Prysm, etc.) have their own DoS protections, but remember: Geth is the Execution Layer. If it dies, your Consensus Layer client has nothing to propose.
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 ID | CWE-20 (Improper Input Validation) |
| Attack Vector | Network (P2P) |
| CVSS v3.1 | 7.5 (High) |
| Impact | Denial of Service (CPU Exhaustion) |
| Component | TxFetcher / KZG Verification |
| Exploit Status | PoC Available / High Reproducibility |
The product receives input or data, but does not validate or incorrectly validates that the input has the properties that are required to process the data safely and correctly.