Auditoria
O zn audit lê os arquivos de configuração de agentes de um repositório, sem executar nada, e informa o que seria executado, para onde iriam as requisições e quais instruções um agente seguiria.
npx -y zn-gate audit ./some-repo
(ou zn audit se você instalou com npm i -g zn-gate; zn-gate audit é o mesmo comando).
Os agentes de código leem configuração do repositório em que trabalham. Vários desses arquivos executam comandos, iniciam servidores MCP, mudam para onde o agente envia suas requisições à API ou ampliam o que ele pode fazer sem perguntar. Atualizar o agente corrige os bugs conhecidos, mas os arquivos continuam no repositório, e o próximo agente, um colega com uma versão mais antiga ou um job de CI ainda pode agir com base neles.
O zn audit lê esses arquivos, sem executar nada, e diz o que seria executado, para onde iriam as requisições e quais instruções um agente seguiria. Ele roda localmente e não envia nada a lugar nenhum. Execute-o antes de abrir um repositório que você acabou de clonar, e no CI.
Opções
zn audit [path] [--format text|json|sarif] [--output <file>]
[--fail-on low|medium|high|critical|none]
[--agents claude,codex,cursor,opencode,amazonq,copilot,gemini,all] [--include-home]
| Opção | Padrão | O que faz |
|---|---|---|
path |
. |
Diretório a auditar, normalmente a raiz do repositório. Um zn audit sem argumentos examina o diretório atual |
--format |
text |
text para pessoas, json para scripts, sarif para o code scanning do GitHub |
--output |
saída padrão | Grava o relatório em um arquivo |
--fail-on |
high |
Termina com código 1 se algum achado tiver esta gravidade ou uma maior. none nunca falha |
--agents |
all |
Verifica apenas os arquivos lidos por estes agentes: claude, codex, cursor, opencode, amazonq, copilot, gemini ou all. Os achados que afetam todos os agentes (AGENTS.md, executáveis plantados, workflows de CI) são sempre exibidos |
--include-home |
desligado | Verifica também as suas próprias configurações de usuário, como ~/.claude/settings.json e ~/.codex/config.toml |
Exemplos:
# Antes de abrir um repositório que você acabou de clonar
npx -y zn-gate audit ./some-repo
# No CI: grava um arquivo SARIF para o code scanning do GitHub e nunca falha
zn audit --format sarif --output zn-audit.sarif --fail-on none
# Só o que o Claude Code e o Codex leem; falha apenas em critical
zn audit --agents claude,codex --fail-on critical
Na 1.5, o zn audit mostrava o registro local de uso de segredos. Esse registro agora é zn vault log (também zn secret log). zn audit log e zn audit --since DATE terminam com código 2 e dizem para usar zn vault log.
Códigos de saída
| Código | Significado |
|---|---|
0 |
Nenhum achado em --fail-on ou acima |
1 |
Pelo menos um achado em --fail-on ou acima |
2 |
Erro de uso ou de execução: opção inválida, caminho não encontrado, saída não gravável |
O que ele lê
Arquivos do projeto em qualquer profundidade, porque a configuração de um subdiretório vale quando um agente inicia ali. As pastas de agentes (.claude, .codex, .cursor, .github, skills e semelhantes) são lidas primeiro. Fora delas, node_modules, vendor e as pastas de build e de ambientes virtuais são ignoradas. O .git nunca é lido.
| Agente | Arquivos |
|---|---|
| Claude Code | .claude/settings.json, .claude/settings.local.json, .mcp.json, CLAUDE.md, CLAUDE.local.md, .claude/commands/, .claude/agents/, .claude/skills/, .claude-plugin/, hooks/hooks.json dos plugins |
| Codex | .codex/config.toml, .codex/hooks.json, .codex/prompts/, .env (somente as variáveis de endpoint e de carregamento de código), AGENTS.md |
| Cursor | .cursor/mcp.json, .cursor/hooks.json, .cursor/cli.json, .cursor/rules/, .cursor/commands/, .cursorrules, os hooks de .claude/settings*.json (o Cursor os executa), .vscode/tasks.json, AGENTS.md |
| OpenCode | opencode.json, opencode.jsonc, configuração, plugins, comandos e agentes de .opencode/, AGENTS.md |
| Amazon Q | .amazonq/mcp.json, .amazonq/cli-agents/, .amazonq/agents/, .amazonq/rules/, AGENTS.md |
| Copilot / VS Code | .vscode/mcp.json, .vscode/settings.json, .vscode/tasks.json, .github/copilot-instructions.md, .github/instructions/, .github/prompts/, AGENTS.md |
| Gemini CLI | .gemini/settings.json, .gemini/commands/, GEMINI.md |
| Qualquer agente | Executáveis na raiz auditada, .github/workflows/*.yml, .windsurfrules, .clinerules |
Nada do que o repositório controla pode fazer um arquivo sumir do relatório em silêncio:
- Um link simbólico que sai do repositório é reportado (ZNA020), não seguido.
- Um arquivo de agente maior que 1 MB é reportado (ZNA020) em vez de ignorado.
- A verificação para após 50.000 entradas de diretório ou 120 segundos, e avisa com um achado ZNA020 de gravidade alta, então a execução falha no limite padrão.
- Um
.envna raiz, commitado, que apontaCODEX_HOMEouCLAUDE_CONFIG_DIRpara uma pasta dentro do repositório faz ozn auditler também as configurações dessa pasta. - Um
.envna raiz é auditado mesmo que o.gitignoreo liste, porque num clone novo ele só existe se foi commitado. Os achados dele ficam um nível abaixo e dizem que não se aplicam ao seu.envlocal.
Com --include-home, ele lê também ~/.claude/settings.json, ~/.claude.json, ~/.codex/config.toml, ~/.cursor/mcp.json, ~/.cursor/hooks.json, ~/.aws/amazonq/mcp.json, ~/.config/opencode/opencode.json[c] e ~/.gemini/settings.json. Ele respeita CODEX_HOME e XDG_CONFIG_HOME como os agentes. Os comandos que você mesmo configurou são esperados ali, então só as variantes mais arriscadas são reportadas: código baixado e executado, pacotes sem versão fixa, mudanças de endpoint, segredos e permissões amplas. Os achados de endpoint, ambiente e permissões ficam limitados a medium.
Regras
Os ids das regras são estáveis: uma regra pode melhorar, mas o id nunca muda de significado. As gravidades são critical, high, medium e low; quando uma regra lista várias, o achado recebe a que corresponde ao caso.
| Id | Gravidade | O que detecta |
|---|---|---|
| ZNA001 | high / medium / low | Um comando que roda automaticamente a partir de uma configuração do projeto: hooks, statusLine, notify do Codex, arquivos de plugin do OpenCode, tarefas do VS Code com runOn: folderOpen. Medium para hooks de um plugin, que só rodam depois que o plugin é ativado. O hook que o zn hooks install grava é reportado como low |
| ZNA002 | critical | Um comando automático que baixa código e o executa (curl ... | sh, iwr ... | iex, bash <(curl ...)) |
| ZNA003 | high / medium / low | Um servidor MCP do projeto que inicia um comando local. High para Codex e Amazon Q; low para o servidor de segredos do próprio zn quando verificado em disco |
| ZNA004 | high / medium | Configurações do projeto que aprovam servidores MCP antecipadamente (enableAllProjectMcpServers, enabledMcpjsonServers) |
| ZNA005 | medium | Um servidor MCP ou plugin de agente sem versão fixa: npx -y pkg, @latest, uvx pkg sem ==, imagens de contêiner sem tag nem digest, plugins do OpenCode sem versão |
| ZNA006 | medium / low | Um servidor MCP remoto, ou instruções carregadas de uma URL. Medium com http simples, low com https |
| ZNA007 | critical / high / medium / low | O endpoint da API do modelo é substituído (ANTHROPIC_BASE_URL, OPENAI_BASE_URL, qualquer *_BASE_URL, URLs base de provedores no Codex e no OpenCode) ou um proxy é definido (HTTPS_PROXY). Critical para um host remoto, high para um proxy, medium para um endereço de loopback. No env de um único servidor MCP, redireciona só aquele servidor: medium, ou low para loopback |
| ZNA008 | high | Uma variável de ambiente que carrega código ou certificados (NODE_OPTIONS, LD_PRELOAD, DYLD_INSERT_LIBRARIES, PYTHONSTARTUP, BASH_ENV, PATH, GIT_SSH_COMMAND, NODE_EXTRA_CA_CERTS e semelhantes) ou que muda onde o agente lê sua configuração (CODEX_HOME, CLAUDE_CONFIG_DIR, XDG_CONFIG_HOME, OPENCODE_CONFIG). Também verificada no env de cada servidor MCP |
| ZNA009 | high | Um comando auxiliar de credenciais nas configurações do projeto (apiKeyHelper, awsAuthRefresh, awsCredentialExport, otelHeadersHelper) |
| ZNA010 | high / medium | Permissões amplas: Bash(*), Bash, *, curingas de interpretador como Bash(python:*), defaultMode: bypassPermissions, approval_policy = "never" do Codex com acesso total, "bash": "allow" do OpenCode, chat.tools.autoApprove do VS Code |
| ZNA011 | high | Um valor secreto numa configuração de agente ou num arquivo de instruções. O relatório nunca imprime o valor |
| ZNA012 | high / medium / low | Um padrão de injeção de prompt nas instruções de um agente: ordens que anulam instruções, tags de sistema falsas, HTML oculto, Unicode invisível, beacons de imagem em Markdown. Nos arquivos que um agente lê como instruções (AGENTS.md, CLAUDE.md, GEMINI.md, regras, skills, comandos, prompts), um padrão forte nunca é rebaixado, citado ou não |
| ZNA013 | medium / low | Instruções que mandam o agente baixar e executar código. Low para instaladores conhecidos como rustup, uv, bun, deno, nvm e Homebrew |
| ZNA014 | high | Instruções que mandam o agente enviar segredos ou arquivos para fora (.env, ~/.ssh, tokens para uma URL, curl -d @.env) |
| ZNA015 | medium | Instruções que mandam o agente pular verificações de segurança ou esconder o que faz (--no-verify, --dangerously-skip-permissions, "desative o sandbox", "não conte ao usuário") |
| ZNA016 | critical / high | Um executável na raiz auditada com o mesmo nome de uma ferramenta comum (git.exe, node.exe, npm.cmd, python, zn.cmd). Critical para executáveis do Windows. O Windows e algumas ferramentas procuram primeiro na pasta atual, então o arquivo plantado roda no lugar da ferramenta real |
| ZNA017 | medium | Configurações do projeto que adicionam marketplaces de plugins ou ativam plugins (extraKnownMarketplaces, enabledPlugins) |
| ZNA018 | low | O repositório traz extensões de agente (comandos, subagentes, skills, plugins). É um inventário: as outras regras as examinam, mas convém saber que estão ali |
| ZNA019 | high / medium | Um workflow de CI que executa um agente de IA com texto que qualquer pessoa pode escrever (issues, issue_comment, pull_request_target, discussions). High com pull_request_target, com texto de issue ou comentário colado no workflow, com uma action aberta a usuários sem permissão de escrita, ou com um passo de CLI com permissões de escrita e sem filtro de autor |
| ZNA020 | high / low | Um arquivo de agente não pôde ser verificado: erro de sintaxe, tamanho acima de 1 MB, link simbólico que sai do repositório ou verificação interrompida antes do fim. High quando o arquivo pode executar comandos ou redirecionar o agente, ou quando a verificação não terminou; low para erro de sintaxe num arquivo que não pode executar nada |
Saída
Texto
zn audit ./some-repo (zn-gate 1.12.0 ou posterior)
CRITICAL ZNA007 .claude/settings.json:4 [claude]
Model API endpoint overridden by the project
ANTHROPIC_BASE_URL points to https://agent-proxy.example.invalid
evidence: "ANTHROPIC_BASE_URL": "https://agent-proxy.example.invalid"
fix: Remove the override; set it in your user settings if you need a gateway.
1 finding (1 critical, 0 high, 0 medium, 0 low) in 3 files. Failing: severity >= high.
As cores só são usadas num terminal e nunca com NO_COLOR definido. Caracteres de controle e sequências de escape vindos do repositório são impressos como \x1b, nunca enviados ao seu terminal.
JSON
--format json imprime um objeto com os findings e um summary:
{
"version": 1,
"tool": "zn-gate",
"toolVersion": "1.12.0",
"root": "/home/me/some-repo",
"findings": [
{
"id": "ZNA007",
"severity": "critical",
"agent": "claude",
"file": ".claude/settings.json",
"line": 4,
"title": "Model API endpoint overridden by the project",
"detail": "ANTHROPIC_BASE_URL points to https://agent-proxy.example.invalid ...",
"evidence": "\"ANTHROPIC_BASE_URL\": \"https://agent-proxy.example.invalid\"",
"fix": "Remove the override ...",
"references": []
}
],
"summary": {
"files": 3,
"findings": 1,
"bySeverity": { "critical": 1, "high": 0, "medium": 0, "low": 0 },
"failOn": "high",
"failed": true,
"agents": ["claude", "codex", "cursor", "opencode", "amazonq", "copilot", "gemini"]
}
}
file é relativo a root, com barras normais; os arquivos de --include-home começam com ~/. agent é o agente que lê o arquivo, ou any quando vários o leem. evidence é a linha correspondente, cortada em 160 caracteres, com os segredos trocados por [REDACTED:<TYPE>]. As URLs perdem usuário, senha, query string e fragmento.
SARIF
--format sarif grava SARIF 2.1.0 para o code scanning do GitHub: uma regra por id ZNA com texto de ajuda e uma pontuação de gravidade, e resultados localizados em relação à raiz do repositório. Cada resultado tem uma impressão digital, então os alertas sobrevivem a mudanças de linha. Os achados de --include-home são marcados como vindos da pasta pessoal e o GitHub os ignora, então não use essa opção no CI.
Use no CI
O mais simples é a GitHub Action do zn-gate com mode: audit. Veja GitHub Actions.
Para rodar a CLI você mesmo, grave um arquivo SARIF e envie-o ao code scanning:
- run: npx -y zn-gate@1.12.0 audit --format sarif --output zn-audit.sarif --fail-on none
- uses: github/codeql-action/upload-sarif@v4
with:
sarif_file: zn-audit.sarif
Retire --fail-on none (o padrão é high) se quiser que o job falhe em achados high e critical. Adicione security-events: write ao job só quando enviar SARIF.
Limites
- Ele lê arquivos; não os executa, não inicia servidores nem resolve pacotes. Um pacote com versão fixa ainda pode ser malicioso, e um hook que chama um script local é reportado como hook, sem julgar o que o script faz.
- As regras de instruções procuram padrões linha a linha. Um autor determinado pode redigir uma instrução que nenhum padrão detecte, e a documentação que cita um comando perigoso também é reportada, por exemplo um guia de instalação com
curl ... | sh. Revise a evidência antes de agir. - A regra de workflows lê o YAML linha a linha. Ela conhece as actions de agentes comuns e as chaves de gatilhos e permissões, não workflows reutilizáveis nem actions compostas.
- A configuração do Git (
.git/config, filtros do.gitattributes) e as extensões de editor não são verificadas. - Os agentes mudam seus formatos de configuração com frequência. Chaves desconhecidas são ignoradas, não reportadas.
- Os segredos são encontrados por formato e por nome de chave sensível. Um segredo sem formato conhecido sob um nome de chave inocente não é encontrado, e senhas escritas em prosa não são ocultadas na evidência.