- circomlib_mimc
- semaphore-protocol_semaphore
- zkopru
- uniRep_protocol
- circom-bigint_circomlib
- circom/circom-bigint_circomlib/veridise_underconstrained_points_in_montgomeryAdd
- circom/circom-bigint_circomlib/veridise_underconstrained_outputs_in_bitElementMulAny
- circom/circom-bigint_circomlib/veridise_underconstrained_points_in_montgomeryDouble
- circom/circom-bigint_circomlib/veridise_decoder_accepting_bogus_output_signal
- circom/circom-bigint_circomlib/veridise_underconstrained_outputs_in_windowmulfix
- circom/circom-bigint_circomlib/veridise_underconstrained_outputs_in_window4
- circom/circom-bigint_circomlib/veridise_underconstrained_points_in_edwards2Montgomery
- circom/circom-bigint_circomlib/veridise_missing_range_checks_in_bigmod
- circom/circom-bigint_circomlib/veridise_underconstrained_points_in_montgomery2Edwards
- darkforest_circuits
- reclaimprotocol_circom_chacha
- spartan_ecdsa
- succinctlabs_telepathy-circuits
- circom/succinctlabs_telepathy-circuits/trailofbits_prover_can_lock_user_funds_by_including_ill-formed_bigints_in_public_key_commitment
- circom/succinctlabs_telepathy-circuits/veridise_template_CoreVerifyPubkeyG1_does_not_perform_input_validation_simplified
- circom/succinctlabs_telepathy-circuits/veridise_zero_padding_for_sha256_in_ExpandMessageXMD_is_vulnerable_to_an_overflow
- circom/succinctlabs_telepathy-circuits/trailofbits_prover_can_lock_user_funds_by_supplying_non-reduced_Y_values_to_G1BigIntToSignFlag
- circom/succinctlabs_telepathy-circuits/trailofbits_incorrect_handling_of_point_doubling_can_allow_signature_forgery
- circom/succinctlabs_telepathy-circuits/veridise_arrayxor_is_under_constrained
- maci
- Id: iden3/circomlib/Kobi-Gurkan-MiMC-Hash-Assigned-but-not-Constrained
- Project: https://github.com/iden3/circomlib
- Commit: 324b8bf8cc4a80357354752deb6c2ae5be22e5f5
- Fix Commit: 109cdf40567fce284dca1d535819ce28922653e0
- DSL: Circom
- Vulnerability: Under-Constrained
- Impact: Soundness
- Root Cause: Assigned but Unconstrained
- Reproduced: True
- Location
- Path: circuits/mimcsponge.circom
- Function: MiMCSponge
- Line: 28
- Source: Audit Report
- Source Link: https://github.com/0xPARC/zk-bug-tracker?tab=readme-ov-file#14-mimc-hash-assigned-but-not-constrained
- Bug ID: MiMC Hash: Assigned but not Constrained
- Commands
- Setup Environment:
./zkbugs_setup.sh
- Reproduce:
./zkbugs_exploit.sh
- Compile and Preprocess:
./zkbugs_compile_setup.sh
- Positive Test:
./zkbugs_positive_test.sh
- Find Exploit:
./zkbugs_find_exploit.sh
- Clean:
./zkbugs_clean.sh
- Setup Environment:
In MiMCSponge
template, outs[0]
is assigned but not constrained, so it can be any value. Note that the circuit code is modified from a newer version since the original buggy code couldn't be reproduced in Circom version 2. The bug idea is still the same.
Set ins[0]
and k
to any random field element. Generate a correct witness first then modify the 2nd entry to a number as you wish. You can see that outs[0]
can be any number.
Use <==
instead of <--
to add a constraint to outs[0]
.
- reclaimprotocol_circom_chacha/zksecurity_unsound_left_rotation
- spartan_ecdsa/yacademy_input_signal_s_is_not_constrained_in_eff_ecdsa_circom
- Id: semaphore-protocol/semaphore/veridise-V-SEM-VUL-001
- Project: https://github.com/semaphore-protocol/semaphore
- Commit: 27320f17233b18de477a74919084fba76513470f
- Fix Commit:
- DSL: Circom
- Vulnerability: Under-Constrained
- Impact: Soundness
- Root Cause: Missing Input Constraints
- Reproduced: True
- Location
- Path: circuits/semaphore.circom
- Function: Semaphore
- Line: 47-88
- Source: Audit Report
- Source Link: https://veridise.com/wp-content/uploads/2023/01/VAR-Semaphore.pdf
- Bug ID: V-SEM-VUL-001: No Zero Value Validation
- Commands
- Setup Environment:
./zkbugs_setup.sh
- Reproduce:
./zkbugs_exploit.sh
- Compile and Preprocess:
./zkbugs_compile_setup.sh
- Positive Test:
./zkbugs_positive_test.sh
- Find Exploit:
./zkbugs_find_exploit.sh
- Clean:
./zkbugs_clean.sh
- Setup Environment:
The bug in the Semaphore protocol involves the use of a zeroValue in incremental Merkle trees, which acts as an implicit group member. This zeroValue cannot be removed, and its addition does not trigger a MemberAdded event, making it invisible in membership records. This allows the group creator guaranteed access, which can be problematic if the admin changes. Additionally, if common values like 0 are compromised, they could be used to gain unauthorized access to groups.
generateInput.js gives all necessary inputs for the incremental merkle tree. In real-world attack, identityNullifier and identityTrapdoor should be correct values corresponding to zeroValue
membership in the incremental merkle tree. Here we just use 0 to represent them. The actual checks are in the solidity contracts.
Disallow proofs where the leaf corresponds to the zeroValue to ensure only legitimate users are added.
- Id: zkopru-network/zkopru/leastauthority-previously-correct-ownership-proof-disabled-via-code-changes
- Project: https://github.com/zkopru-network/zkopru/releases/tag/audit-v1
- Commit: 1f5c880d47b6913f848861667b8de6b88dcfe10d
- Fix Commit: 6458fe4ef384d2f2198aae00e719a7f94c30f090
- DSL: Circom
- Vulnerability: Under-Constrained
- Impact: Soundness
- Root Cause: Unsafe Reuse of Circuit
- Reproduced: True
- Location
- Path: circuits/ownership_proof.circom
- Function: OwnershipProof
- Line: 14
- Source: Audit Report
- Source Link: https://github.com/nullity00/zk-security-reviews/blob/main/ZKopru/LeastAuthority_Ethereum_Foundation_Zkopru_zk-SNARK_Circuits_Smart_Contracts_Final_Audit_Report.pdf
- Bug ID: Issue C: Previously Correct Ownership Proof Disabled via Code Changes
- Commands
- Setup Environment:
./zkbugs_setup.sh
- Reproduce:
./zkbugs_exploit.sh
- Compile and Preprocess:
./zkbugs_compile_setup.sh
- Positive Test:
./zkbugs_positive_test.sh
- Find Exploit:
./zkbugs_find_exploit.sh
- Clean:
./zkbugs_clean.sh
- Setup Environment:
The circuit integrates with EdDSAPoseidonVerifier
template from circomlib, but the enabled
signal is set to 0, disabling the verification. There is no signature verification in the circuit, so attacker can craft some non-existent signature and still generate a valid proof.
Run zkbugs_js_setup.sh to set up the circomlibjs environment. Do node generateInput.js
to generate the input for the circuit. Here every field besides S
is valid, the signature is hardcoded to 13371337
for demonstrating the bug.
Change the line of code to eddsa.enabled <== 1
.
- Id: Unirep/Unirep/veridise-V-UNI-VUL-002
- Project: https://github.com/Unirep/Unirep
- Commit: 0985a28c38c8b2e7b7a9e80f43e63179fdd08b89
- Fix Commit: f7b0bcd39383d5ec4d17edec2ad91bc01333bf36
- DSL: Circom
- Vulnerability: Under-Constrained
- Impact: Soundness
- Root Cause: Unsafe Reuse of Circuit
- Reproduced: True
- Location
- Path: circuits/epochKeyLite.circom
- Function: EpochKeyLite
- Line: 45-48
- Source: Audit Report
- Source Link: https://f8t2x8b2.rocketcdn.me/wp-content/uploads/2023/08/VAR-Unirep.pdf
- Bug ID: V-UNI-VUL-002: Missing Range Checks on Comparison Circuits
- Commands
- Setup Environment:
./zkbugs_setup.sh
- Reproduce:
./zkbugs_exploit.sh
- Compile and Preprocess:
./zkbugs_compile_setup.sh
- Positive Test:
./zkbugs_positive_test.sh
- Find Exploit:
./zkbugs_find_exploit.sh
- Clean:
./zkbugs_clean.sh
- Setup Environment:
Input of LessThan(8)
is assumed to have <=8 bits, but there is no constraint for it in LessThan
template. Attacker can use large values such as p - 1
to trigger overflow and make something like p - 1 < EPOCH_KEY_NONCE_PER_EPOCH
return true.
Set nonce = -1
in input.json
and other inputs to 0 then generate witness. No need to modify the witness.
Implement range check so that attacker can't exploit overflow in LessThan
.
- darkforest_circuits/daira_hopwood_darkforest_v0_3_missing_bit_length_check
- Id: Unirep/Unirep/veridise-V-UNI-VUL-001
- Project: https://github.com/Unirep/Unirep
- Commit: 0985a28c38c8b2e7b7a9e80f43e63179fdd08b89
- Fix Commit: 3348caa362d5d632d29c532ffa88023d55628eab
- DSL: Circom
- Vulnerability: Under-Constrained
- Impact: Soundness
- Root Cause: Arithmetic Field Errors
- Reproduced: True
- Location
- Path: circuits/bigComparators.circom
- Function: BigLessThan
- Line: 45
- Source: Audit Report
- Source Link: https://f8t2x8b2.rocketcdn.me/wp-content/uploads/2023/08/VAR-Unirep.pdf
- Bug ID: V-UNI-VUL-001: Underconstrained Circuit allows Invalid Comparison
- Commands
- Setup Environment:
./zkbugs_setup.sh
- Reproduce:
./zkbugs_exploit.sh
- Compile and Preprocess:
./zkbugs_compile_setup.sh
- Positive Test:
./zkbugs_positive_test.sh
- Find Exploit:
./zkbugs_find_exploit.sh
- Clean:
./zkbugs_clean.sh
- Setup Environment:
Num2Bits(254)
is used so malicious prover can provide input that is larger than scalar field modulus p
but smaller than 2**254
, exploiting the overflow. That makes some comparison opertions invalid, for example, 1 < p
evaluates to true but in the circuit it is treated as 1 < 0
.
Set in[0]
to 1 and in[1]
to p
, then generate the witness from inputs directly, no need to modify the witness.
Use Num2Bits_strict
rather than Num2Bits(254)
.
- Id: iden3/circomlib/veridise-V-CIRCOMLIB-VUL-004
- Project: https://github.com/iden3/circomlib
- Commit: cff5ab6288b55ef23602221694a6a38a0239dcc0
- Fix Commit:
- DSL: Circom
- Vulnerability: Under-Constrained
- Impact: Soundness
- Root Cause: Missing Input Constraint
- Reproduced: True
- Location
- Path: circuits/montgomery.circom
- Function: MontgomeryAdd
- Line: 16-17
- Source: Audit Report
- Source Link: https://f8t2x8b2.rocketcdn.me/wp-content/uploads/2023/02/VAR-circom-bigint.pdf
- Bug ID: V-CIRCOMLIB-VUL-004: Underconstrained points in MontgomeryAdd
- Commands
- Setup Environment:
./zkbugs_setup.sh
- Reproduce:
./zkbugs_exploit.sh
- Compile and Preprocess:
./zkbugs_compile_setup.sh
- Positive Test:
./zkbugs_positive_test.sh
- Find Exploit:
./zkbugs_find_exploit.sh
- Clean:
./zkbugs_clean.sh
- Setup Environment:
Lambda calculation involves a division but there is no constraint on the divisor to be non-zero. In this case out[1]
is underconstrained and can be set to any value.
Set out[0]
to -168697. out[1]
can be set to any value but it has to satisfy some relative relation with in1[1]
and in2[1]
. Check out detect.sage
to learn more.
Send in2[0] - in1[0]
to isZero
template and let the constraint there do the work.
- circom-bigint_circomlib/veridise_decoder_accepting_bogus_output_signal
- circom-bigint_circomlib/veridise_underconstrained_outputs_in_bitElementMulAny
- circom-bigint_circomlib/veridise_underconstrained_points_in_edwards2Montgomery
- circom-bigint_circomlib/veridise_underconstrained_points_in_montgomery2Edwards
- circom-bigint_circomlib/veridise_underconstrained_points_in_montgomeryDouble
- Id: iden3/circomlib/veridise-V-CIRCOMLIB-VUL-006
- Project: https://github.com/iden3/circomlib
- Commit: cff5ab6288b55ef23602221694a6a38a0239dcc0
- Fix Commit:
- DSL: Circom
- Vulnerability: Under-Constrained
- Impact: Soundness
- Root Cause: Unsafe Reuse of Circuit
- Reproduced: True
- Location
- Path: circuits/escalarmulany.circom
- Function: BitElementMulAny
- Line: 21-22
- Source: Audit Report
- Source Link: https://f8t2x8b2.rocketcdn.me/wp-content/uploads/2023/02/VAR-circom-bigint.pdf
- Bug ID: V-CIRCOMLIB-VUL-006: Underconstrained outputs in BitElementMulAny
- Commands
- Setup Environment:
./zkbugs_setup.sh
- Reproduce:
./zkbugs_exploit.sh
- Compile and Preprocess:
./zkbugs_compile_setup.sh
- Positive Test:
./zkbugs_positive_test.sh
- Find Exploit:
./zkbugs_find_exploit.sh
- Clean:
./zkbugs_clean.sh
- Setup Environment:
BitElementMulAny
template itself is fine, but it uses MontgomeryDouble
and MontgomeryAdd
, which have underconstraint bugs. With the same input.json
, malicious prover can manipulate lambda value in MontgomeryDouble
to let the circuit produce different outputs, making it nondeterministic.
In input.json, just use dummy EC point (1,2) to pass the positive test. Then we exploit the MontgomeryDouble
underconstrained bug, let divisor be 0 and solve for the exploitable witness in sagemath step by step.
Fix underconstraint bugs in MontgomeryDouble
and MontgomeryAdd
.
- circom-bigint_circomlib/veridise_decoder_accepting_bogus_output_signal
- circom-bigint_circomlib/veridise_underconstrained_points_in_edwards2Montgomery
- circom-bigint_circomlib/veridise_underconstrained_points_in_montgomery2Edwards
- circom-bigint_circomlib/veridise_underconstrained_points_in_montgomeryAdd
- circom-bigint_circomlib/veridise_underconstrained_points_in_montgomeryDouble
- Id: iden3/circomlib/veridise-V-CIRCOMLIB-VUL-005
- Project: https://github.com/iden3/circomlib
- Commit: cff5ab6288b55ef23602221694a6a38a0239dcc0
- Fix Commit:
- DSL: Circom
- Vulnerability: Under-Constrained
- Impact: Soundness
- Root Cause: Missing Input Constraints
- Reproduced: True
- Location
- Path: circuits/montgomery.circom
- Function: MontgomeryDouble
- Line: 18-19
- Source: Audit Report
- Source Link: https://f8t2x8b2.rocketcdn.me/wp-content/uploads/2023/02/VAR-circom-bigint.pdf
- Bug ID: V-CIRCOMLIB-VUL-005: Underconstrained points in MontgomeryDouble
- Commands
- Setup Environment:
./zkbugs_setup.sh
- Reproduce:
./zkbugs_exploit.sh
- Compile and Preprocess:
./zkbugs_compile_setup.sh
- Positive Test:
./zkbugs_positive_test.sh
- Find Exploit:
./zkbugs_find_exploit.sh
- Clean:
./zkbugs_clean.sh
- Setup Environment:
Lambda calculation involves a division but there is no constraint on the divisor to be non-zero. In this case lamda
is underconstrained and can be set to any value.
Set in[1]
to 0. Make the assumption that 3*x1_2 + 2*A*in[0] + 1 == 0
and solve for rest of the signals with some sagemath magic.
Send in[1]
to isZero
template and let the constraint there do the work.
- circom-bigint_circomlib/veridise_decoder_accepting_bogus_output_signal
- circom-bigint_circomlib/veridise_underconstrained_outputs_in_bitElementMulAny
- circom-bigint_circomlib/veridise_underconstrained_points_in_edwards2Montgomery
- circom-bigint_circomlib/veridise_underconstrained_points_in_montgomery2Edwards
- circom-bigint_circomlib/veridise_underconstrained_points_in_montgomeryAdd
- Id: iden3/circomlib/veridise-V-CIRCOMLIB-VUL-001
- Project: https://github.com/iden3/circomlib
- Commit: cff5ab6288b55ef23602221694a6a38a0239dcc0
- Fix Commit:
- DSL: Circom
- Vulnerability: Under-Constrained
- Impact: Soundness
- Root Cause: Wrong translation of logic into constraints
- Reproduced: True
- Location
- Path: circuits/multiplexer.circom
- Function: Decoder
- Line: 10-11
- Source: Audit Report
- Source Link: https://f8t2x8b2.rocketcdn.me/wp-content/uploads/2023/02/VAR-circom-bigint.pdf
- Bug ID: V-CIRCOMLIB-VUL-001: Decoder accepting bogus output signal
- Commands
- Setup Environment:
./zkbugs_setup.sh
- Reproduce:
./zkbugs_exploit.sh
- Compile and Preprocess:
./zkbugs_compile_setup.sh
- Positive Test:
./zkbugs_positive_test.sh
- Find Exploit:
./zkbugs_find_exploit.sh
- Clean:
./zkbugs_clean.sh
- Setup Environment:
The circuit does not constrain out
properly, malicious prover can set a bogus out
and set success
to 0, the circuit won't throw error. This makes integration error-prone.
Set out
to be full of zeroes and set success
to 0.
Send inp - i
to isZero
template and let the constraint there do the work.
- circom-bigint_circomlib/veridise_underconstrained_outputs_in_bitElementMulAny
- circom-bigint_circomlib/veridise_underconstrained_points_in_edwards2Montgomery
- circom-bigint_circomlib/veridise_underconstrained_points_in_montgomery2Edwards
- circom-bigint_circomlib/veridise_underconstrained_points_in_montgomeryAdd
- circom-bigint_circomlib/veridise_underconstrained_points_in_montgomeryDouble
- Id: iden3/circomlib/veridise-V-CIRCOMLIB-VUL-008
- Project: https://github.com/iden3/circomlib
- Commit: cff5ab6288b55ef23602221694a6a38a0239dcc0
- Fix Commit:
- DSL: Circom
- Vulnerability: Under-Constrained
- Impact: Soundness
- Root Cause: Unsafe Reuse of Circuit
- Reproduced: True
- Location
- Path: circuits/escalarmulfix.circom
- Function: WindowMulFix
- Line: 70-131
- Source: Audit Report
- Source Link: https://f8t2x8b2.rocketcdn.me/wp-content/uploads/2023/02/VAR-circom-bigint.pdf
- Bug ID: V-CIRCOMLIB-VUL-008: Underconstrained outputs in WindowMulFix
- Commands
- Setup Environment:
./zkbugs_setup.sh
- Reproduce:
./zkbugs_exploit.sh
- Compile and Preprocess:
./zkbugs_compile_setup.sh
- Positive Test:
./zkbugs_positive_test.sh
- Find Exploit:
./zkbugs_find_exploit.sh
- Clean:
./zkbugs_clean.sh
- Setup Environment:
WindowMulFix
template itself is fine, but it uses MontgomeryDouble
and MontgomeryAdd
, which have underconstraint bugs. With the same input.json
, malicious prover can manipulate lambda value in MontgomeryDouble
to let the circuit produce different outputs, making it nondeterministic.
Here we exploit the MontgomeryDouble
underconstrained bug, let divisor be 0 and solve for signals in sagemath step by step. The full witness is provided in veridise report.
Fix underconstraint bugs in MontgomeryDouble
and MontgomeryAdd
.
- Id: iden3/circomlib/veridise-V-CIRCOMLIB-VUL-007
- Project: https://github.com/iden3/circomlib
- Commit: cff5ab6288b55ef23602221694a6a38a0239dcc0
- Fix Commit:
- DSL: Circom
- Vulnerability: Under-Constrained
- Impact: Soundness
- Root Cause: Unsafe Reuse of Circuit
- Reproduced: True
- Location
- Path: circuits/pederson.circom
- Function: Window4
- Line: 47-108
- Source: Audit Report
- Source Link: https://f8t2x8b2.rocketcdn.me/wp-content/uploads/2023/02/VAR-circom-bigint.pdf
- Bug ID: V-CIRCOMLIB-VUL-007: Underconstrained outputs in Window4
- Commands
- Setup Environment:
./zkbugs_setup.sh
- Reproduce:
./zkbugs_exploit.sh
- Compile and Preprocess:
./zkbugs_compile_setup.sh
- Positive Test:
./zkbugs_positive_test.sh
- Find Exploit:
./zkbugs_find_exploit.sh
- Clean:
./zkbugs_clean.sh
- Setup Environment:
Window4
template itself is fine, but it uses MontgomeryDouble
and MontgomeryAdd
, which have underconstraint bugs. With the same input.json
, malicious prover can manipulate lambda value in MontgomeryDouble
to let the circuit produce different outputs, making it nondeterministic.
Here we exploit the MontgomeryDouble
underconstrained bug, let divisor be 0 and solve for signals in sagemath step by step. The full witness is provided in veridise report.
Fix underconstraint bugs in MontgomeryDouble
and MontgomeryAdd
.
- Id: iden3/circomlib/veridise-V-CIRCOMLIB-VUL-002
- Project: https://github.com/iden3/circomlib
- Commit: cff5ab6288b55ef23602221694a6a38a0239dcc0
- Fix Commit:
- DSL: Circom
- Vulnerability: Under-Constrained
- Impact: Soundness
- Root Cause: Missing Input Constraints
- Reproduced: True
- Location
- Path: circuits/montgomery.circom
- Function: Edwards2Montgomery
- Line: 7-8
- Source: Audit Report
- Source Link: https://f8t2x8b2.rocketcdn.me/wp-content/uploads/2023/02/VAR-circom-bigint.pdf
- Bug ID: V-CIRCOMLIB-VUL-002: Underconstrained points in Edwards2Montgomery
- Commands
- Setup Environment:
./zkbugs_setup.sh
- Reproduce:
./zkbugs_exploit.sh
- Compile and Preprocess:
./zkbugs_compile_setup.sh
- Positive Test:
./zkbugs_positive_test.sh
- Find Exploit:
./zkbugs_find_exploit.sh
- Clean:
./zkbugs_clean.sh
- Setup Environment:
The circuit does not implement constraint to avoid division by zero. When setting the divisor to 0, out[1]
is underconstrained and can be set to any value.
Set in[0]
to 0 to trigger division by zero. Set out[1]
to 1337 just to show that it can be set to any value.
Send in[0]
and 1 - in[1]
to isZero
template and let the constraint there do the work.
- circom-bigint_circomlib/veridise_decoder_accepting_bogus_output_signal
- circom-bigint_circomlib/veridise_underconstrained_outputs_in_bitElementMulAny
- circom-bigint_circomlib/veridise_underconstrained_points_in_montgomery2Edwards
- circom-bigint_circomlib/veridise_underconstrained_points_in_montgomeryAdd
- circom-bigint_circomlib/veridise_underconstrained_points_in_montgomeryDouble
- Id: 0xbok/circom-bigint/veridise-V-BIGINT-COD-001
- Project: https://github.com/0xbok/circom-bigint
- Commit: 436665bf01728ae8c581fdb39e8428cb6b835c37
- Fix Commit: d3edd7503f48f98a71b6013c248ef3ad55e19703
- DSL: Circom
- Vulnerability: Under-Constrained
- Impact: Soundness
- Root Cause: Arithmetic Field Errors
- Reproduced: True
- Location
- Path: circuits/bigint.circom
- Function: BigMod
- Line: 363-417
- Source: Audit Report
- Source Link: https://veridise.com/wp-content/uploads/2023/02/VAR-circom-bigint.pdf
- Bug ID: V-BIGINT-COD-001: Missing range checks in BigMod
- Commands
- Setup Environment:
./zkbugs_setup.sh
- Reproduce:
./zkbugs_exploit.sh
- Compile and Preprocess:
./zkbugs_compile_setup.sh
- Positive Test:
./zkbugs_positive_test.sh
- Find Exploit:
./zkbugs_find_exploit.sh
- Clean:
./zkbugs_clean.sh
- Setup Environment:
The bug in the BigMod template arises from missing range checks on the remainder mod[i]
, allowing it to exceed the expected range of 2**n
. This underconstrained error can be exploited by providing inputs that result in a remainder larger than 2^n
, potentially compromising the integrity of the circuit. Proper range checks are applied to the quotient div[i]
, but not to mod[i]
, leaving the system vulnerable to malicious inputs that break the invariant of the modulus operation.
We design a pair of a
and b
such that the remainder after divmod
overflows 2**126
.
Add additional range checking constraints for mod[i]
. This can be done using the Num2Bits template.
- Id: iden3/circomlib/veridise-V-CIRCOMLIB-VUL-003
- Project: https://github.com/iden3/circomlib
- Commit: cff5ab6288b55ef23602221694a6a38a0239dcc0
- Fix Commit:
- DSL: Circom
- Vulnerability: Under-Constrained
- Impact: Soundness
- Root Cause: Missing Input Constraints
- Reproduced: True
- Location
- Path: circuits/montgomery.circom
- Function: Montgomery2Edwards
- Line: 7-8
- Source: Audit Report
- Source Link: https://f8t2x8b2.rocketcdn.me/wp-content/uploads/2023/02/VAR-circom-bigint.pdf
- Bug ID: V-CIRCOMLIB-VUL-003: Underconstrained points in Montgomery2Edwards
- Commands
- Setup Environment:
./zkbugs_setup.sh
- Reproduce:
./zkbugs_exploit.sh
- Compile and Preprocess:
./zkbugs_compile_setup.sh
- Positive Test:
./zkbugs_positive_test.sh
- Find Exploit:
./zkbugs_find_exploit.sh
- Clean:
./zkbugs_clean.sh
- Setup Environment:
The circuit does not implement constraint to avoid division by zero. When setting the divisor to 0, out[0]
is underconstrained and can be set to any value.
Set in[1]
to 0 to trigger division by zero. Set out[0]
to 1337 just to show that it can be set to any value.
Send in[1]
and in[0] + 1
to isZero
template and let the constraint there do the work.
- circom-bigint_circomlib/veridise_decoder_accepting_bogus_output_signal
- circom-bigint_circomlib/veridise_underconstrained_outputs_in_bitElementMulAny
- circom-bigint_circomlib/veridise_underconstrained_points_in_edwards2Montgomery
- circom-bigint_circomlib/veridise_underconstrained_points_in_montgomeryAdd
- circom-bigint_circomlib/veridise_underconstrained_points_in_montgomeryDouble
- Id: darkforest-eth/darkforest-v0.3/Daira-Hopwood-Missing-Bit-Length-Check
- Project: https://github.com/darkforest-eth/darkforest-v0.3
- Commit: 1c83685e22e0463d5481c83e21616745b3204c9c
- Fix Commit: https://github.com/darkforest-eth/circuits/commit/1b5c8440a487614d4a3e6ed523df0aee71a05b6e#diff-440e6bdf86d42398f40d29b9df0b9e6992c6859194d2a7f3c8c68fb46d0f2040
- DSL: Circom
- Vulnerability: Under-Constrained
- Impact: Soundness
- Root Cause: Unsafe Reuse of Circuit
- Reproduced: True
- Location
- Path: circuits/range_proof/circuit.circom
- Function: RangeProof
- Line: 16-22
- Source: Audit Report
- Source Link: https://github.com/0xPARC/zk-bug-tracker?tab=readme-ov-file#1-dark-forest-v03-missing-bit-length-check
- Bug ID: Dark Forest v0.3: Missing Bit Length Check
- Commands
- Setup Environment:
./zkbugs_setup.sh
- Reproduce:
./zkbugs_exploit.sh
- Compile and Preprocess:
./zkbugs_compile_setup.sh
- Positive Test:
./zkbugs_positive_test.sh
- Find Exploit:
./zkbugs_find_exploit.sh
- Clean:
./zkbugs_clean.sh
- Setup Environment:
Input of LessThan(bits)
is assumed to take inputs bounded by 2**(bits-1)
, but there is no constraint for it in LessThan
template. Attacker can use unexpected values outside the range and pass all the constraints, rendering this RangeProof useless. Note: The original circuit does not contain the output out
, it was added to prevent snarkJS 'Scalar size does not match' error.
Set in = -255
then generate witness. No need to modify the witness.
Add constraints to check the range of in
and max_abs_value
. This can be done using the Num2Bits
template.
- uniRep_protocol/veridise_missing_range_checks_on_comparison_circuits
- Id: reclaimprotocol/circom-chacha20/zksecurity-1
- Project: https://github.com/reclaimprotocol/circom-chacha20
- Commit: ef9f5a5ad899d852740a26b30eabe5765673c71f
- Fix Commit: e5e756375fc1fc8dc48667b00cdf38c79a0fdf50
- DSL: Circom
- Vulnerability: Under-Constrained
- Impact: Soundness
- Root Cause: Wrong translation of logic into constraints
- Reproduced: True
- Location
- Path: circuits/generics.circom
- Function: RotateLeft32Bits
- Line: 39-45
- Source: Audit Report
- Source Link: https://www.zksecurity.xyz/blog/2023-reclaim-chacha20.pdf
- Bug ID: #1 Unsound Left Rotation Gadget
- Commands
- Setup Environment:
./zkbugs_setup.sh
- Reproduce:
./zkbugs_exploit.sh
- Compile and Preprocess:
./zkbugs_compile_setup.sh
- Positive Test:
./zkbugs_positive_test.sh
- Find Exploit:
./zkbugs_find_exploit.sh
- Clean:
./zkbugs_clean.sh
- Setup Environment:
The part1
and part2
signals are not sufficiently constrained. One can arbitrarily set a value to part1
or part2
and find a value for the other signal to satisfy the constraint on line 45. This way you can get another out
value for a given in
.
To exploit the vulnerability, one has to simply find a witness that produces a different value for out
rather than the one produced by the witness generator. The sage script demonstrates how to find another witness that satisfies the constraints. Then, you simply need to produce a new proof.
The recommendation to fix this issue was to constrain part1
(resp. part2
) to be (resp. ) bit-sized values. For the concrete mitigation applied, check the commit of the fix.
- circomlib_mimc/kobi_gurkan_mimc_hash_assigned_but_not_constrained
- spartan_ecdsa/yacademy_input_signal_s_is_not_constrained_in_eff_ecdsa_circom
- Id: personaelabs/spartan-ecdsa/yacademy-high-01
- Project: https://github.com/personaelabs/spartan-ecdsa
- Commit: 3386b30d9b5b62d8a60735cbeab42bfe42e80429
- Fix Commit:
- DSL: Circom
- Vulnerability: Under-Constrained
- Impact: Soundness
- Root Cause: Missing Input Constraints
- Reproduced: True
- Location
- Path: circuits/eff_ecdsa.circom
- Function: EfficientECDSA
- Line: 25-28
- Source: Audit Report
- Source Link: https://github.com/zBlock-1/spartan-ecdsa-audit-report
- Bug ID: Input signal s is not constrained in eff_ecdsa.circom
- Commands
- Setup Environment:
./zkbugs_setup.sh
- Reproduce:
./zkbugs_exploit.sh
- Compile and Preprocess:
./zkbugs_compile_setup.sh
- Positive Test:
./zkbugs_positive_test.sh
- Find Exploit:
./zkbugs_find_exploit.sh
- Clean:
./zkbugs_clean.sh
- Setup Environment:
The circuit computes pubKey = s * T + U
but s
isn't constrained. If we set s = 0
and (Ux, Uy) = pubKey
, then (Tx, Ty)
can be any pair of values.
Set s = 0
and rest of the inputs can be any number.
Add constraint to s
so that s * T
can't be skipped in the computation.
- circomlib_mimc/kobi_gurkan_mimc_hash_assigned_but_not_constrained
- reclaimprotocol_circom_chacha/zksecurity_unsound_left_rotation
- Id: personaelabs/spartan-ecdsa/yacademy-high-03
- Project: https://github.com/personaelabs/spartan-ecdsa
- Commit: 3386b30d9b5b62d8a60735cbeab42bfe42e80429
- Fix Commit:
- DSL: Circom
- Vulnerability: Under-Constrained
- Impact: Soundness
- Root Cause: Assigned but Unconstrained
- Reproduced: False
- Location
- Path: circuits/mul.circom
- Function: K
- Line: 123-124
- Source: Audit Report
- Source Link: https://github.com/zBlock-1/spartan-ecdsa-audit-report
- Bug ID: Under constrained circuits compromising the soundness of the system
- Commands
- Setup Environment:
./zkbugs_setup.sh
- Reproduce:
./zkbugs_exploit.sh
- Compile and Preprocess:
./zkbugs_compile_setup.sh
- Positive Test:
./zkbugs_positive_test.sh
- Find Exploit:
./zkbugs_find_exploit.sh
- Clean:
./zkbugs_clean.sh
- Setup Environment:
The signals slo
and shi
are assigned but not constrained
Modify slo
or shi
, then deduce all related intermediate signals and modify the witness.
Use <==
instead of <--
.
circom/succinctlabs_telepathy-circuits/trailofbits_prover_can_lock_user_funds_by_including_ill-formed_bigints_in_public_key_commitment
- Id: succinctlabs/telepathy-circuits/trailofbits-succinct-1
- Project: https://github.com/iden3/circomlib
- Commit: b0c839cef30c3c25ef41d1ad3000081784766934
- Fix Commit: 1a88e657932edc59b51e35095618f1e1a46ceef6
- DSL: Circom
- Vulnerability: Under-Constrained
- Impact: Completeness
- Root Cause: Unsafe Reuse of Circuit
- Reproduced: False
- Location
- Path: circuits/pairing/bls12_381_hash_to_G2
- Function: SubgroupCheckG1WithValidX
- Line: 723-731
- Source: Audit Report
- Source Link: https://github.com/trailofbits/publications/blob/master/reviews/2023-02-succinct-securityreview.pdf
- Bug ID: 1. Prover can lock user funds by including ill-formed BigInts in public key comitment
- Commands
- Setup Environment:
./zkbugs_setup.sh
- Reproduce:
./zkbugs_exploit.sh
- Compile and Preprocess:
./zkbugs_compile_setup.sh
- Positive Test:
./zkbugs_positive_test.sh
- Find Exploit:
./zkbugs_find_exploit.sh
- Clean:
./zkbugs_clean.sh
- Setup Environment:
The Rotate()
template in rotate.circom fails to validate the format of BigInts in public keys. SubgroupCheckG1WithValidX assumes that its input is a properly formed BigInt, with all limbs less than 2**55. This property is not validated anywhere in the Rotate()
template. It allows a malicious prover to manipulate public keys by inserting ill-formed BigInts, specifically by altering the y-coordinate of public keys. This manipulation can lock user funds by preventing future provers from generating valid proofs, as the circuit uses these malformed keys without proper validation. The exploit involves modifying the y coordinate in a public key to create an invalid commitment, which then updates the system's commitment state, potentially leading to incorrect or fraudulent operations.
Subtract one from the most significant limb and add 2**55 to the second-most significant limb.
Use Num2Bits()
template to verify that each limb of the pubkeysBigIntY
, witness value is less than 2**55.
circom/succinctlabs_telepathy-circuits/veridise_template_CoreVerifyPubkeyG1_does_not_perform_input_validation_simplified
- Id: succinctlabs/telepathy-circuits/veridise-V-SUC-VUL-002-simplified
- Project: https://github.com/succinctlabs/telepathy-circuits
- Commit: 9c84fb0f38531718296d9b611f8bd6107f61a9b8
- Fix Commit: b0c839cef30c3c25ef41d1ad3000081784766934
- DSL: Circom
- Vulnerability: Under-Constrained
- Impact: Soundness
- Root Cause: Unsafe Reuse of Circuit
- Reproduced: True
- Location
- Path: circuits/bls_signature.circom
- Function: CoreVerifyPubkeyG1ToyExample
- Line: 77-95
- Source: Audit Report
- Source Link: https://veridise.com/wp-content/uploads/2023/04/VAR-Succinct.pdf
- Bug ID: V-SUC-VUL-002: Template CoreVerifyPubkeyG1 does not perform input validation
- Commands
- Setup Environment:
./zkbugs_setup.sh
- Reproduce:
./zkbugs_exploit.sh
- Compile and Preprocess:
./zkbugs_compile_setup.sh
- Positive Test:
./zkbugs_positive_test.sh
- Find Exploit:
./zkbugs_find_exploit.sh
- Clean:
./zkbugs_clean.sh
- Setup Environment:
This bug is in the circom-pairing BLS signature verification logic. pubkey, signature and hash are divided into 7-entry chunks of 55-bit data, and each entry is checked against according entry in p
. When calling BigLessThan()
, the output isn't verified therefore attacker can manipulate the input so that it overflows p.
The circuit had been simplified to demonstrate the bug, the attack idea is calculating a delta
such that it makes the input overflow but still bounded by 2**55 - 1 to pass the range check inside BigLessThan()
. In reality, attacker would bruteforce a special set of inputs satisfying a list of constraints. The details are explained in the PR comment.
In each iteration of the for loop, add a constraint lt[idx].out === 1
to make sure the input is indeed bounded by p
.
circom/succinctlabs_telepathy-circuits/veridise_zero_padding_for_sha256_in_ExpandMessageXMD_is_vulnerable_to_an_overflow
- Id: succinctlabs/telepathy-circuits/veridise-V-SUC-VUL-003
- Project: https://github.com/succinctlabs/telepathy-circuits/
- Commit: 9c84fb0f38531718296d9b611f8bd6107f61a9b8
- Fix Commit: b0c839cef30c3c25ef41d1ad3000081784766934
- DSL: Circom
- Vulnerability: Under-Constrained
- Impact: Soundness
- Root Cause: Arithmetic Field Errors
- Reproduced: True
- Location
- Path: circuits/hash_to_field.circom
- Function: I2OSP
- Line: 3-23
- Source: Audit Report
- Source Link: https://veridise.com/wp-content/uploads/2023/04/VAR-Succinct.pdf
- Bug ID: V-SUC-VUL-003: Zero Padding for Sha256 in ExpandMessageXMD is vulnerable to an overflow
- Commands
- Setup Environment:
./zkbugs_setup.sh
- Reproduce:
./zkbugs_exploit.sh
- Compile and Preprocess:
./zkbugs_compile_setup.sh
- Positive Test:
./zkbugs_positive_test.sh
- Find Exploit:
./zkbugs_find_exploit.sh
- Clean:
./zkbugs_clean.sh
- Setup Environment:
Template ExpandMessageXMD calls I2OSP(64) with in
set to 0. In template I2OSP, numbers are represented in bigint format, a 64-byte chunk. This representation allows number much larger than scalar field modulus p
, so attacker can compute 0 + k * p
and turn that into bigint representation and still pass the constraints.
Compute 0 + p
and turn that into bigint format. Also keep track of the accumulator acc[64]
.
Add assertion assert(l < 31)
when using template I2OSP(l), so the largest possible number is 31 * 8 = 248 bit, which is less than scalar field modulus p
.
circom/succinctlabs_telepathy-circuits/trailofbits_prover_can_lock_user_funds_by_supplying_non-reduced_Y_values_to_G1BigIntToSignFlag
- Id: succinctlabs/telepathy-circuits/trailofbits-succinct-2
- Project: https://github.com/succinctlabs/telepathy-circuits
- Commit: b0c839cef30c3c25ef41d1ad3000081784766934
- Fix Commit: 1a88e657932edc59b51e35095618f1e1a46ceef6
- DSL: Circom
- Vulnerability: Under-Constrained
- Impact: Completeness
- Root Cause: Unsafe Reuse of Circuit
- Reproduced: True
- Location
- Path: circuits/bls.circom
- Function: G1BigIntToSignFlag
- Line: 198-227
- Source: Audit Report
- Source Link: https://github.com/trailofbits/publications/blob/master/reviews/2023-02-succinct-securityreview.pdf
- Bug ID: 2. Prover can lock user funds by supplying non-reduced Y values to G1BigIntToSignFlag
- Commands
- Setup Environment:
./zkbugs_setup.sh
- Reproduce:
./zkbugs_exploit.sh
- Compile and Preprocess:
./zkbugs_compile_setup.sh
- Positive Test:
./zkbugs_positive_test.sh
- Find Exploit:
./zkbugs_find_exploit.sh
- Clean:
./zkbugs_clean.sh
- Setup Environment:
G1BigIntToSignFlag
fails to check if the y-coordinate is properly reduced mod p. This missing of range check allows malicious prover to lock user funds by supplying a non-reduced y-coordinate, which can be manipulated to have a positive sign when it should be negative. This manipulation can prevent future provers from generating valid proofs, effectively halting the LightClient and trapping user funds in the bridge.
In detect.sage, we grab a 'positive' y-coordinate from a public key and turn it into 'negative' by negating it and mod p. We call this new value y
and it has negative sign. Now we compute 2*p - y
and use it as input. This value is congruent to -y mod p
so it is positive, but the circuit still considers it as negative. This fact can be observed in exploitable_witness.json: the second entry is 0, which represents negative sign.
Constrain the pubkeysBigIntY
values to be less than p
using BigLessThan
template.
circom/succinctlabs_telepathy-circuits/trailofbits_incorrect_handling_of_point_doubling_can_allow_signature_forgery
- Id: succinctlabs/telepathy-contracts
- Project: https://github.com/succinctlabs/telepathy-contracts
- Commit: b0c839cef30c3c25ef41d1ad3000081784766934
- Fix Commit:
- DSL: Circom
- Vulnerability: Under-Constrained
- Impact: Soundness
- Root Cause: Unsafe Reuse of Circuit
- Reproduced: True
- Location
- Path: circuits/curve.circom
- Function: EllipticCurveAddUnequal
- Line: 155-227
- Source: Audit Report
- Source Link: https://github.com/trailofbits/publications/blob/master/reviews/2023-02-succinct-securityreview.pdf
- Bug ID: 3. Incorrect handling of point doubling can allow signature forgery
- Commands
- Setup Environment:
./zkbugs_setup.sh
- Reproduce:
./zkbugs_exploit.sh
- Compile and Preprocess:
./zkbugs_compile_setup.sh
- Positive Test:
./zkbugs_positive_test.sh
- Find Exploit:
./zkbugs_find_exploit.sh
- Clean:
./zkbugs_clean.sh
- Setup Environment:
G1Add
calls EllipticCurveAddUnequal
. The template EllipticCurveAddUnequal
assumes input a
and b
are two unequal public keys but this is not checked. Attacker can use two same public keys to do sophisticated attacks. In such scenario, the constraint on output in EllipticCurveAddUnequal
reduces to 0 = 0 so it is always true. In other words, attacker can do point doubling at a place where it is supposed to do point addition of two unequal EC points.
We generate A = aG
, B = bG
and C = (a+b)G
. We use (a+b)G
for both inputs.
Change G1Add
to use EllipticCurveAdd
, which correctly handles equal inputs by checking and managing point doubling.
- Id: succinctlabs/telepathy-circuits/veridise-V-SUC-VUL-001
- Project: https://github.com/succinctlabs/telepathy-circuits
- Commit: 9c84fb0f38531718296d9b611f8bd6107f61a9b8
- Fix Commit: b0c839cef30c3c25ef41d1ad3000081784766934
- DSL: Circom
- Vulnerability: Under-Constrained
- Impact: Soundness
- Root Cause: Assigned but Unconstrained
- Reproduced: True
- Location
- Path: circuits/hash_to_field.circom
- Function: ArrayXOR
- Line: 9
- Source: Audit Report
- Source Link: https://veridise.com/wp-content/uploads/2023/04/VAR-Succinct.pdf
- Bug ID: V-SUC-VUL-001: ArrayXOR is under constrained
- Commands
- Setup Environment:
./zkbugs_setup.sh
- Reproduce:
./zkbugs_exploit.sh
- Compile and Preprocess:
./zkbugs_compile_setup.sh
- Positive Test:
./zkbugs_positive_test.sh
- Find Exploit:
./zkbugs_find_exploit.sh
- Clean:
./zkbugs_clean.sh
- Setup Environment:
out[i]is assigned with
<--but not constrained with
<==`, so it can be set to any value.
Generate a correct witness first, then modify entry 2 to 5 to any field element.
Change the code to out[i] <== a[i] ^ b[i]
.
- Id: privacy-scaling-explorations/maci/hashcloak_initial_conditions_are_not_properly_enforced
- Project: https://github.com/privacy-scaling-explorations/maci
- Commit: 2db5f625b67a6b810bd851950d7a42c26189088b
- Fix Commit: d0792d1e532fd0a7fead4a21cb8f54af6022c4c4
- DSL: Circom
- Vulnerability: Under-Constrained
- Impact: Soundness
- Root Cause: Wrong translation of logic into constraints
- Reproduced: False
- Location
- Path: circuits/tallyVotes.circom
- Function: ResultCommitmentVerifier
- Line: 89-92
- Source: Audit Report
- Source Link: https://github.com/nullity00/zk-security-reviews/blob/main/MACI/20210922%20Hashcloak%20audit%20report.pdf
- Bug ID: Initial Conditions Are Not Properly Enforced
- Commands
- Setup Environment:
./zkbugs_setup.sh
- Reproduce:
./zkbugs_exploit.sh
- Compile and Preprocess:
./zkbugs_compile_setup.sh
- Positive Test:
./zkbugs_positive_test.sh
- Find Exploit:
./zkbugs_find_exploit.sh
- Clean:
./zkbugs_clean.sh
- Setup Environment:
If the batch is the first batch, iz.out
will be 0, and hz
will be 0, so the constraint hz <== iz.out * currentTallyCommitmentHasher.hash
will always hold true. There is no checks confirming that the current tally is actually the initial tally in such a case.
Use some random values as tally data and set current_tally_commitment = 0.
In 2023 the protocol was refactored, as explained here: privacy-scaling-explorations/maci#279.