For a decade, zero-knowledge proofs came with one core promise: you don't have to trust the team. Just check the math. That promise broke in production this month โ€” not from a cryptographic flaw, but from one skipped CLI command.

The Setup

Two protocols fell to the same mistake. Around February 20, Veil Cash, a small Tornado Cash fork on Base, was drained of 2.9 ETH in a single transaction. An attacker fabricated nullifier hashes โ€” 0xdead0000 through 0xdead001c โ€” and withdrew funds they had never deposited. The verifier accepted every one.

The root cause: the Groth16 proof system requires a trusted setup ceremony that generates unique gamma and delta parameters. Skip the ceremony, and both values stay pinned to the BN254 G2 generator โ€” snarkjs's default placeholder. Veil Cash shipped with the defaults. Nobody noticed until the drain.

The attacker returned the funds. A security researcher published a full proof-of-concept on GitHub. Days later, FoomCash lost $2.26 million to the identical flaw.

Not Isolated

A week after FoomCash's post-mortem, OtterSec researchers published "Unfaithful Claims," disclosing Fiat-Shamir binding bugs across six independent ZK virtual machine implementations: Jolt (a16z), Nexus, Cairo-M, Ceno, Expander, and Binius64. Different teams, different codebases, same pattern โ€” prover-controlled values fed into verification equations without being hashed into the transcript first. In each case, the fix was one or two lines of code.

What It Means

The ZK ecosystem long assumed its code was too arcane for attackers to target. OtterSec's paper and the live exploits show that assumption no longer holds. Once a PoC is on GitHub, the knowledge gap closes fast.

ZK infrastructure underpins rollups, privacy protocols, and identity systems holding billions in user assets. Teams should treat trusted setup verification as a deployment blocker, not an afterthought.