Critical soundness bug in dusk-plonk let a malicious prover forge PLONK proofs, enabling arbitrary DUSK minting and fake shielded Phoenix spends on a ~$60M network.
Key Takeaways
The verifier consumed four selector polynomial evaluations (q_l, q_r, q_c, q_arith) from the proof struct without checking them against verifier key commitments via KZG opening proofs.
Because those scalars were fully attacker-controlled, a forged proof could pass every gate constraint simultaneously, voiding Merkle membership, nullifier, and balance checks at once.
All Phoenix-path transactions are affected: shielded transfers, staking, unstaking, reward withdrawals, and Phoenix-to-Moonlight conversions all route through the broken verify_proof_with_version().
gnark avoids this class of bug by incorporating selector commitments directly into the linearization MSM, never asking the prover for selector evaluations at all.
dusk-plonk is one of the earliest PLONK implementations, predating established patterns; complexity of custom widgets (range, logic, EC ops, fourth wire d) made the verifier harder to audit.