
Статический анализатор без зависимостей для поиска ошибок корректности zk-схем в o1js/Mina zkApps и схемах Noir
Пакет сообщества:
o1js-scanуказан в официальном каталоге o1js Community Packages.
Последняя версия: 0.22.0 — локальный MCP-сервер позволяет Claude Code, Cursor и другим AI-ассистентам для программирования запускать сканер прямо во время написания zkApp:
pip install 'o1js-scan[mcp]'. Он работает на вашей машине через stdio и ничего не загружает. Сканирование, не проанализировавшее ни одного файла, — это ошибка, а не чистый результат, а результат без находок означает, что это не гарантия безопасности. У основного сканера по-прежнему нет зависимостей. См. CHANGELOG.
Быстрый статический анализатор без зависимостей для ошибок корректности zk-схем в:
.ts / .js) — схемы Kimchi из тел @method.nr) — Rust-подобный ZK DSL от Aztec (включая шаблоны в стиле aztec-nr)Критичные для безопасности ошибки обычно находятся не в системе доказательства — они в
собственных ограничениях приложения: свидетелях, которые контролирует доказывающий, но схема
их никогда не связывает. o1js-scan — это сканер недостаточно ограниченных сигналов для родственников Circom
в экосистемах Mina и Noir.
См. также: gnark-safety (схемы gnark), vk-guard (регрессия ключа проверки).
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
Дан сейф, у которого сумма withdraw является подконтрольным доказывающему свидетелем, который
никогда не привязывается к состоянию в блокчейне:
$ 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 нужен здесь только потому, что демонстрационный файл находится в
examples/, который классификатор путей по умолчанию понижает в приоритете, чтобы
собственный пример кода репозитория не мог сломать его сборку. Тот же контракт в вашем src/ сообщает
HIGH без флага.
Находка HIGH — это ошибка, позволяющая опустошить контракт. Исправленный контракт
(examples/safe_vault.ts) отбрасывает её и завершается с 0, сохраняя только информационную
LOW о получателе, выбранном доказывающим:
$ 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
См. examples/ для уязвимых/исправленных пар o1js и Noir.
pip install o1js-scan
Для изолированной глобальной установки CLI используйте pipx:
pipx install o1js-scan
Для репозиториев приложений на Node/npm, использующих Noir, Aztec или o1js, установите npm-обёртку:
npm install -D o1js-scan
npx noir-scan . --lang noir --fail-on high
Пакет npm — это тонкая обёртка вокруг того же анализатора на Python и требует
Python 3.8+ в PATH (python3 или python). Задайте O1JS_SCAN_PYTHON, чтобы выбрать
конкретный интерпретатор.
Или из исходного кода:
git clone https://github.com/auditinfra-io/o1js-scan
cd o1js-scan
pip install -e .
Без сторонних зависимостей Python. Python 3.8+. Консольный скрипт noir-scan
устанавливается вместе с o1js-scan (та же точка входа), в том числе через
npm-обёртку.
# 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
Код выхода — 1, когда присутствует находка уровня --fail-on (по умолчанию
high) или выше, и 0 в противном случае — так что его можно напрямую
встроить в CI. При значении по умолчанию находка уровня low/medium (включая
информационное правило о получателе ниже) не приводит к сбою сборки;
используйте --fail-on none, чтобы только сообщать, или --strict (сокращение
для --fail-on medium), чтобы фильтровать строже, по-прежнему считая находки
низкой серьёзности рекомендательными. Эти две опции взаимоисключающие, поэтому
конфигурация CI не может быть неоднозначной. Отсутствующий путь сканирования
завершается с кодом 2 и ошибкой в stderr, так что опечатка не может молча
пройти CI как чистое выполнение. То же самое происходит с путём, который
существует, но не содержит исходников o1js или Noir, которые анализатор может
прочитать (например, --lang noir, указанный на проект o1js); передайте
--allow-empty, когда это допустимо. Каждый запуск
печатает однострочную сводку (количество по уровням серьёзности и вердикт
фильтра) в stderr.
Тестовый код исключается по умолчанию — в обоих бэкендах. Тесты намеренно создают недопустимые значения и плохие транзакции, чтобы доказать, что проверки их отклоняют, поэтому находка там — это суть теста, а не ошибка схемы. Файл считается тестовым кодом, когда: