
Abhängigkeitsfreier statischer Analysator für Soundness-Fehler in zk-Schaltkreisen bei o1js/Mina zkApps und Noir-Schaltkreisen
Community-Paket:
o1js-scanist im offiziellen Verzeichnis o1js Community Packages gelistet.
Neueste Version: 0.22.0 — ein lokaler MCP-Server ermöglicht Claude Code, Cursor und anderen KI-Coding-Assistenten, den Scanner während des Schreibens einer zkApp auszuführen:
pip install 'o1js-scan[mcp]'. Er läuft auf deinem Rechner über stdio und lädt nichts hoch. Ein Scan, der keine Dateien analysiert hat, ist ein Fehler, kein sauberes Ergebnis, und ein Ergebnis ohne Befunde besagt, dass es keine Sicherheitsgarantie ist. Der Kern-Scanner hat weiterhin keine Abhängigkeiten. Siehe CHANGELOG.
Ein schneller, abhängigkeitsfreier statischer Analyzer für zk-Schaltkreis-Soundness-Bugs in:
.ts / .js) — Kimchi-Schaltkreise aus @method-Bodies.nr) — Aztecs Rust-ähnliche ZK-DSL (einschließlich aztec-nr-förmiger Muster)Die sicherheitskritischen Bugs stecken meist nicht im Proving-System — sie stecken in den
eigenen Constraints der Anwendung: Witnesses, die der Prover kontrolliert, aber der Schaltkreis
nie bindet. o1js-scan ist der Under-Constrained-Signal-Scanner für die Cousins von Circom in den
Mina- und Noir-Ökosystemen.
Siehe auch: gnark-safety (gnark- Schaltkreise), vk-guard (Verification-Key-Regression).
pip install o1js-scan
# or: pipx install o1js-scan
# or: npm install -D o1js-scan
o1js-scan path/to/zkapp # o1js + Noir (auto)
noir-scan path/to/circuits # same binary — Noir-friendly alias
noir-scan . --lang noir --fail-on high --sarif noir.sarif
Gegeben sei ein Vault, dessen withdraw-Betrag ein vom Prover kontrollierter Witness ist, der
niemals an den On-Chain-Zustand gebunden wird:
$ o1js-scan examples/vulnerable_vault.ts --include-examples
LOW O1JS_UNCONSTRAINED_RECIPIENT vulnerable_vault.ts:23 fn=withdraw Recipient `to` is prover-chosen in `withdraw`
HIGH O1JS_UNCONSTRAINED_WITNESS vulnerable_vault.ts:23 fn=withdraw Unconstrained witness `amount` flows to send_amount in `withdraw`
o1js-scan: 2 finding(s) [1 high, 1 low] in 1 of 1 file(s) — fails (--fail-on high)
$ echo $?
1
--include-examples wird hier nur benötigt, weil die Demo-Datei unter
examples/ liegt, das der Pfad-Klassifizierer standardmäßig herabstuft, damit
der Beispielcode eines Repos seinen eigenen Build nicht fehlschlagen lässt. Derselbe Vertrag in deinem src/ meldet
HIGH ohne Flag.
Der HIGH-Fund ist der ausnutzbare Bug. Der korrigierte Vertrag
(examples/safe_vault.ts) verwirft ihn und beendet mit 0, wobei nur das informative
LOW beim vom Prover gewählten Empfänger erhalten bleibt:
$ o1js-scan examples/safe_vault.ts --include-examples
LOW O1JS_UNCONSTRAINED_RECIPIENT safe_vault.ts:23 fn=withdraw Recipient `to` is prover-chosen in `withdraw`
o1js-scan: 1 finding(s) [1 low] in 1 of 1 file(s) — passes (--fail-on high)
$ echo $?
0
Siehe examples/ für die o1js- und Noir-Paare aus verwundbaren und korrigierten Versionen.
pip install o1js-scan
Für eine isolierte globale CLI-Installation verwenden Sie pipx:
pipx install o1js-scan
Für Node/npm-basierte Noir-, Aztec- oder o1js-App-Repositories installieren Sie den npm-Wrapper:
npm install -D o1js-scan
npx noir-scan . --lang noir --fail-on high
Das npm-Paket ist ein dünner Wrapper um denselben Python-Analysator und erfordert
Python 3.8+ im PATH (python3 oder python). Setze O1JS_SCAN_PYTHON, um einen
bestimmten Interpreter auszuwählen.
Oder aus dem Quellcode:
git clone https://github.com/auditinfra-io/o1js-scan
cd o1js-scan
pip install -e .
Keine Python-Abhängigkeiten von Drittanbietern. Python 3.8+. Das Konsolenskript noir-scan wird
zusammen mit o1js-scan installiert (gleicher Einstiegspunkt), auch über den npm-
Wrapper.
# scan a directory (recursively; skips node_modules, target/, .git, …)
o1js-scan path/to/project
# Noir-only / o1js-only
noir-scan circuits --lang noir
o1js-scan src --lang o1js
# scan a single file
o1js-scan src/MyContract.ts
noir-scan src/main.nr
# machine-readable output for CI
o1js-scan src --json
# SARIF 2.1.0 for GitHub code scanning (writes o1js-scan.sarif by default)
o1js-scan src --sarif
noir-scan . --lang noir --sarif noir.sarif
# choose which severity fails CI (critical|high|medium|low|none; default high)
o1js-scan src --fail-on medium
# progressive/power-user gate (equivalent to --fail-on medium)
o1js-scan src --strict
# test code is excluded by default (both backends); opt back in
o1js-scan src --include-tests
# example code is downgraded to LOW by default; keep original severity
o1js-scan src --include-examples
# a path with no o1js / Noir source exits 2; opt out where that is expected
o1js-scan packages/ --allow-empty
o1js-scan --version
Der Exit-Code ist 1, wenn ein Finding auf oder über der --fail-on-Stufe (Standard
high) vorliegt, und andernfalls 0 — du kannst ihn also direkt in CI einbinden.
Mit dem Standard lässt ein Low-/Medium-Finding (einschließlich der unten
beschriebenen informativen Recipient-Regel) den Build nicht fehlschlagen; verwende --fail-on none, um nur zu
berichten, oder --strict (eine Kurzform für --fail-on medium), um strenger zu gaten und
Low-Severity-Findings weiterhin als Hinweis zu behandeln. Die beiden Optionen schließen sich gegenseitig
aus, damit die CI-Konfiguration nicht mehrdeutig sein kann. Ein fehlender Scan-Pfad beendet den Prozess mit 2
und einer Fehlermeldung auf stderr, sodass ein Tippfehler nicht stillschweigend als sauberer Lauf durch die CI gehen kann. Ebenso verhält es sich mit
einem Pfad, der existiert, aber keinen o1js- oder Noir-Quellcode enthält, den der Analyzer lesen kann (zum
Beispiel --lang noir, gerichtet auf ein o1js-Projekt); übergib --allow-empty, wo
das legitim ist. Jeder Lauf
gibt eine einzeilige Zusammenfassung (Anzahl nach Severity und das Gate-Urteil) auf stderr aus.
Testcode ist standardmäßig ausgeschlossen — bei beiden Backends. Tests bauen absichtlich ungültige Werte und fehlerhafte Transaktionen, um zu beweisen, dass die Asserts sie ablehnen, ein Finding dort ist also der Sinn des Tests und kein Circuit-Bug. Eine Datei zählt als Testcode, wenn: