Skip to content

Latest commit

 

History

History
59 lines (45 loc) · 1.81 KB

File metadata and controls

59 lines (45 loc) · 1.81 KB

Z014: Missing Merkle-Root Inclusion-Proof Verification

Severity

HIGH - Enables unauthorized access via unverified merkle proofs

Description

Detects functions that accept merkle leaf + path but never verify the computed root matches the stored root, or verify after already trusting the leaf value.

Vulnerable Pattern

// ❌ BAD: Computes root but never checks it
pub fn claim_airdrop(env: Env, amount: u64, proof_path: Vec<BytesN<32>>) {
    let leaf = hash_leaf(&env, amount);
    let computed_root = compute_merkle_root(&env, leaf, proof_path);
    
    // ❌ Never compares: computed_root == stored_root
    // Trust the leaf immediately!
    transfer(&env, &env.invoker(), amount);
}

Attack: Attacker provides any amount + fake merkle path, gets funds.

Secure Pattern

// ✅ GOOD: Verify root before trust
pub fn claim_airdrop(env: Env, amount: u64, proof_path: Vec<BytesN<32>>) {
    let leaf = hash_leaf(&env, amount);
    let computed_root = compute_merkle_root(&env, leaf, proof_path);
    let stored_root: BytesN<32> = env.storage().get(&MERKLE_ROOT_KEY).unwrap();
    
    if computed_root != stored_root {
        panic!("Invalid merkle proof");
    }
    
    // Now safe - proof verified
    transfer(&env, &env.invoker(), amount);
}

Why This Matters

  • Authorization bypass: Claim without valid proof
  • Fund theft: Access any amount in merkle tree
  • Airdrop manipulation: Claim multiple times or wrong amounts

Detection Method

  1. Find merkle root computation calls
  2. Check if result compared to stored root
  3. Verify comparison happens BEFORE leaf trusted
  4. Flag if missing or misordered

Dependencies

  • #1192, #1194: ZK infrastructure
  • #1221: Merkle test fixture

Examples

See contracts/fixtures/finding-codes/z014_missing_merkle_inclusion_check.rs