
Analisador estático sem dependências para bugs de solidez em circuitos zk em zkApps o1js/Mina e circuitos Noir
Pacote da comunidade:
o1js-scanestá listado no diretório oficial o1js Community Packages.
Mais recente: 0.22.0 — um servidor MCP local permite que Claude Code, Cursor e outros assistentes de codificação com IA executem o scanner enquanto você escreve um zkApp:
pip install 'o1js-scan[mcp]'. Ele roda na sua máquina via stdio e não envia nada. Uma varredura que não analisou nenhum arquivo é um erro, não um resultado limpo, e um resultado sem achados afirma que não é uma garantia de segurança. O scanner principal continua sem dependências. Veja CHANGELOG.
Um analisador estático rápido e sem dependências para bugs de solidez de circuitos zk em:
.ts / .js) — circuitos Kimchi a partir de corpos de @method.nr) — DSL ZK de estilo Rust da Aztec (incluindo padrões no formato aztec-nr)Os bugs críticos de segurança geralmente não estão no sistema de prova — eles estão nas
restrições da própria aplicação: witnesses que o provador controla mas o circuito
nunca vincula. o1js-scan é o scanner de sinais sub-restritos para os primos do Circom
nos ecossistemas Mina e Noir.
Veja também: gnark-safety (circuitos gnark), vk-guard (regressão de chave de verificação).
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
Dado um cofre cujo valor de withdraw é uma testemunha controlada pelo provador que
nunca é vinculada ao estado on-chain:
$ 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 é necessário aqui apenas porque o arquivo de demonstração está em
examples/, que o classificador de caminhos rebaixa por padrão para que o
próprio código de exemplo de um repositório não possa falhar a sua build. O mesmo contrato em seu src/ reporta
HIGH sem nenhuma flag.
O achado HIGH é o bug drenável. O contrato corrigido
(examples/safe_vault.ts) o descarta e sai com 0, mantendo apenas o LOW informativo
sobre o destinatário escolhido pelo provador:
$ 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
Consulte examples/ para os pares vulneráveis/corrigidos de o1js e Noir.
pip install o1js-scan
Para uma instalação global isolada da CLI, use pipx:
pipx install o1js-scan
Para repositórios de aplicações Noir, Aztec ou o1js baseados em Node/npm, instale o wrapper npm:
npm install -D o1js-scan
npx noir-scan . --lang noir --fail-on high
O pacote npm é um wrapper fino em torno do mesmo analisador Python e requer
Python 3.8+ no PATH (python3 ou python). Defina O1JS_SCAN_PYTHON para escolher um
interpretador específico.
Ou a partir do código-fonte:
git clone https://github.com/auditinfra-io/o1js-scan
cd o1js-scan
pip install -e .
Sem dependências Python de terceiros. Python 3.8+. O script de consola noir-scan é
instalado juntamente com o1js-scan (mesmo ponto de entrada), incluindo através do wrapper
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
O código de saída é 1 quando um achado no nível --fail-on ou superior (padrão
high) está presente e 0 caso contrário — assim você pode inseri-lo diretamente no CI.
Com o padrão, um achado de baixa/média severidade (incluindo a regra informativa de
destinatário abaixo) não reprova a build; use --fail-on none para apenas reportar,
ou --strict (um atalho para --fail-on medium) para restringir mais rigorosamente enquanto
ainda trata achados de baixa severidade como informativos. As duas opções são mutuamente
exclusivas para que a configuração do CI não possa ser ambígua. Um caminho de varredura ausente sai com 2
e um erro em stderr, para que um erro de digitação não passe silenciosamente no CI como uma execução limpa. O mesmo acontece com
um caminho que existe mas não contém nenhum código-fonte o1js ou Noir que o analisador consiga ler (por
exemplo, --lang noir apontado para um projeto o1js); passe --allow-empty onde
isso for legítimo. Toda execução
imprime um resumo de uma linha (contagens por severidade e o veredito do gate) em stderr.
O código de teste é excluído por padrão — em ambos os backends. Os testes constroem deliberadamente valores inválidos e transações ruins para provar que as asserções os rejeitam, então um achado ali é o objetivo do teste e não um bug do circuito. Um arquivo é considerado código de teste quando: