The Merkle
library in ZKSync's core protocol contains a critical validation issue that prevents verification of minimal but valid Merkle tree states. At the heart of the vulnerability is a well-intentioned but overly restrictive check in _validatePathLengthForSingleProof
:
This validation unconditionally rejects empty Merkle paths - a decision that breaks the foundational mathematics of Merkle trees. By definition, a single-node Merkle tree (height = 0) is a valid construction where the leaf hash is identical to the root hash, requiring no proof path since no siblings exist to prove against. The current implementation makes it impossible to represent this state, despite it being both mathematically valid and practically necessary.
This limitation propagates through the ZKSync ecosystem in subtle but dangerous ways. Systems built on this library, like token distribution contracts or state transition verifiers, are forced into one of three harmful patterns:
Creation of synthetic proof paths using dummy nodes, wasting gas and complicating verification
Implementation of parallel verification logic specifically for single-node states, fragmenting security-critical code
Complete bypass of Merkle verification for initial states, potentially missing important security checks
What makes this particularly concerning is that the same codebase correctly handles single-node trees in its batch verification path through calculateRootPaths
. This inconsistency suggests the restriction wasn't a deliberate security decision but rather an oversight that made it through multiple audits.
The vulnerability manifests most clearly in the initialization phase of Merkle-based systems. Consider a standard merkle airdrop contract:
The issue becomes even more apparent when we look at how the same codebase handles batch verification:
This inconsistency creates a footgun: developers seeing the batch verification work correctly might assume single proofs work the same way, leading to subtle vulnerabilities in production systems.
The solution requires realigning the validation with Merkle tree mathematics while preserving the security properties of the current implementation. Here's a corrected implementation:
This fix harmonizes single-node and batch verification behaviors while maintaining strict validation for all other cases.
The change is fully backward compatible - existing multi-node proofs continue working exactly as before, while systems can now correctly handle single-node states without workarounds.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.