Skip to content

feat: add detector for singly-hashed Merkle leaves#2946

Open
ep0chzer0 wants to merge 2 commits intocrytic:masterfrom
ep0chzer0:feature/merkle-singly-hashed-leaf
Open

feat: add detector for singly-hashed Merkle leaves#2946
ep0chzer0 wants to merge 2 commits intocrytic:masterfrom
ep0chzer0:feature/merkle-singly-hashed-leaf

Conversation

@ep0chzer0
Copy link
Contributor

Summary

Adds a new detector that identifies potential second preimage attacks on Merkle trees when using OpenZeppelin's MerkleProof library.

  • Detects calls to MerkleProof.verify(), verifyCalldata(), processProof(), and processProofCalldata()
  • Traces the leaf parameter backwards to count keccak256 applications
  • Flags leaves with fewer than 2 keccak256 hashes (vulnerable to second preimage attack)
  • Follows through helper functions to avoid false positives when double-hashing is done in separate functions

Closes #2675

The Vulnerability

When using Merkle proofs, leaves should be double-hashed (keccak256(keccak256(data))) to prevent second preimage attacks. If a leaf is only singly-hashed or not hashed at all, an attacker who knows an intermediate node value (64 bytes) can forge a valid proof.

Reference: https://www.rareskills.io/post/merkle-tree-second-preimage-attack

Example Detection

// BAD: Single hash - will be flagged
bytes32 leaf = keccak256(abi.encodePacked(account, amount));
MerkleProof.verify(proof, root, leaf);

// GOOD: Double hash - not flagged
bytes32 leaf = keccak256(bytes.concat(keccak256(abi.encodePacked(account, amount))));
MerkleProof.verify(proof, root, leaf);

Test Plan

  • Added test contract with 9 test cases (5 vulnerable, 4 safe patterns)
  • Python syntax validated
  • Black formatting checked
  • Test artifacts need to be generated (no local solc on ARM)

Note: The test zip artifact and snapshot file need to be generated. I can update once CI runs or if maintainers can provide guidance on generating these without local solc.

Files Changed

  • slither/detectors/statements/merkle_singly_hashed_leaf.py - New detector
  • slither/detectors/all_detectors.py - Registration
  • tests/e2e/detectors/test_detectors.py - Test registration
  • tests/e2e/detectors/test_data/merkle-singly-hashed-leaf/0.8.20/merkle_singly_hashed_leaf.sol - Test contract

@ep0chzer0 ep0chzer0 requested a review from smonicas as a code owner January 21, 2026 23:45
@ep0chzer0 ep0chzer0 force-pushed the feature/merkle-singly-hashed-leaf branch 3 times, most recently from aff7cf3 to 24c4892 Compare January 28, 2026 08:01
Adds a new detector that identifies potential second preimage attacks on
Merkle trees when using OpenZeppelin's MerkleProof library.

The detector flags cases where the leaf parameter passed to MerkleProof.verify(),
verifyCalldata(), processProof(), or processProofCalldata() has fewer than 2
keccak256 hashes applied. Without double-hashing, attackers can potentially
forge proofs by presenting intermediate nodes as leaves.

Closes crytic#2675

Reference: https://www.rareskills.io/post/merkle-tree-second-preimage-attack
Adds the required test files:
- Compiled zip artifact for merkle_singly_hashed_leaf.sol
- Snapshot file with expected detector output (5 findings)
@ep0chzer0 ep0chzer0 force-pushed the feature/merkle-singly-hashed-leaf branch from 24c4892 to 4406e9a Compare February 23, 2026 17:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add a detector for singly-hashed Merkle leaves using OZ's MerkleProof library

1 participant