A set of exercises and introduction to Noir circuit security. Each challenge is a deliberately broken Noir circuit, and your goal is to exploit the bug by producing a valid proof for a statement that should be impossible by crafting a malicious Prover.toml.
Inspired by the Oak Security CosmWasm CTF.
This CTF is pinned to a specific toolchain: nargo 1.0.0-beta.22 and bb 5.0.0-nightly.20260522. Other versions are known to crash (e.g., nargo check panics, bb write_vk aborts) and cause unexpected behavior with the challenges in this repo.
nargov1.0.0-beta.22: installnoirup, thennoirup --version 1.0.0-beta.22.bb(Barretenberg) v5.0.0-nightly.20260522: install via noir's owninstall_bb.sh.
Run the environment check script to verify your install:
bash scripts/check-env.shIf everything is set up correctly, you should see Installation check passed.
noir-ctf/
├── challenges/
│ ├── 01-missing-constraint/
│ ├── 02-missing-blinding-factor/
│ ├── 03-field-wraparound/
│ ├── 04-range-check/
│ ├── 05-nullifier-malleability/
│ ├── 06-unconstrained-division/
│ ├── 07-boundedvec-residual/
│ ├── 08-comptime-bit-decomp/
│ ├── 09-selector-spacing/
│ └── 10-noncanonical-encoding/
├── solutions/ # one folder per challenge (spoilers!)
├── scripts/
│ └── check-env.sh # environment check
├── LICENSE
└── README.md
cd challenges/01-missing-constraint
cat README.md # read the scenario & objective
cp Prover.toml.example Prover.toml # start from the example inputs
# edit Prover.toml to craft your exploit
./verify.sh # compile, prove, and verifyEach challenge includes a verify.sh script that compiles the circuit, generates a proof, and verifies it. If the script prints SOLVED, you've completed the challenge.
Tip
Run ./verify.sh with the unmodified Prover.toml.example values first to confirm your setup works before crafting the exploit.
Roughly ordered easiest → hardest.
| # | Challenge | Topic |
|---|---|---|
| 01 | Missing Constraint | Under-constrained circuit |
| 02 | Missing Blinding Factor | Commitment without a hiding salt |
| 03 | Field Wraparound | Field arithmetic underflow |
| 04 | Range Check Omission | Truncation on Field-to-integer cast |
| 05 | Nullifier Malleability | Free witness in nullifier derivation |
| 06 | Unconstrained Division | Unconstrained function trust |
| 07 | BoundedVec Residual | Capacity-vs-length: un-notarized buffer residual |
| 08 | Comptime Range Gadget | Quote/unquote accumulation bug in a generated range check |
| 09 | Selector Spacing Bypass | Quote token-padding mismatch in compile-time selector strings |
| 10 | Non-Canonical Encoding | Foreign-field validate_in_range vs validate_in_field |
MIT.
Challenges are intentionally broken. Do not copy them into production.
If you're building with Noir or zero-knowledge circuits and need a security audit, reach out to Oak Security.