Audit
zn audit lit les fichiers de configuration d'agents d'un dépôt, sans rien exécuter, et indique ce qui s'exécuterait, où iraient les requêtes et quelles instructions un agent suivrait.
npx -y zn-gate audit ./some-repo
(ou zn audit si vous l'avez installé avec npm i -g zn-gate ; zn-gate audit est la même commande).
Les agents de code lisent la configuration du dépôt dans lequel ils travaillent. Plusieurs de ces fichiers exécutent des commandes, démarrent des serveurs MCP, changent la destination des requêtes d'API de l'agent ou élargissent ce qu'il peut faire sans demander. Mettre l'agent à jour corrige les bogues connus, mais les fichiers restent dans le dépôt, et l'agent suivant, un collègue avec une version plus ancienne ou un job de CI peut encore s'y fier.
zn audit lit ces fichiers, sans rien exécuter, et vous dit ce qui s'exécuterait, où iraient les requêtes et quelles instructions un agent suivrait. Il fonctionne en local et n'envoie rien nulle part. Lancez-le avant d'ouvrir un dépôt que vous venez de cloner, et en CI.
Options
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]
| Option | Par défaut | Ce qu'elle fait |
|---|---|---|
path |
. |
Dossier à auditer, en général la racine du dépôt. Un zn audit sans argument examine le dossier courant |
--format |
text |
text pour les personnes, json pour les scripts, sarif pour le code scanning de GitHub |
--output |
sortie standard | Écrit le rapport dans un fichier |
--fail-on |
high |
Termine avec le code 1 si un résultat a cette gravité ou une gravité supérieure. none n'échoue jamais |
--agents |
all |
Ne vérifie que les fichiers lus par ces agents : claude, codex, cursor, opencode, amazonq, copilot, gemini ou all. Les résultats qui concernent tous les agents (AGENTS.md, exécutables plantés, workflows de CI) sont toujours affichés |
--include-home |
désactivé | Vérifie aussi vos propres configurations utilisateur, comme ~/.claude/settings.json et ~/.codex/config.toml |
Exemples :
# Avant d'ouvrir un dépôt que vous venez de cloner
npx -y zn-gate audit ./some-repo
# En CI : écrit un fichier SARIF pour le code scanning de GitHub et n'échoue jamais
zn audit --format sarif --output zn-audit.sarif --fail-on none
# Seulement ce que lisent Claude Code et Codex ; échoue uniquement sur critical
zn audit --agents claude,codex --fail-on critical
Dans la 1.5, zn audit affichait le journal local d'utilisation des secrets. Ce journal est désormais zn vault log (aussi zn secret log). zn audit log et zn audit --since DATE se terminent avec le code 2 et vous indiquent d'utiliser zn vault log.
Codes de sortie
| Code | Signification |
|---|---|
0 |
Aucun résultat à --fail-on ou au-dessus |
1 |
Au moins un résultat à --fail-on ou au-dessus |
2 |
Erreur d'utilisation ou d'exécution : option invalide, chemin introuvable, sortie non inscriptible |
Ce qu'il lit
Les fichiers du projet à toute profondeur, car la configuration d'un sous-dossier s'applique quand un agent démarre dedans. Les dossiers d'agents (.claude, .codex, .cursor, .github, skills et similaires) sont lus en premier. En dehors, node_modules, vendor et les dossiers de build et d'environnements virtuels sont ignorés. .git n'est jamais lu.
| Agent | Fichiers |
|---|---|
| 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 des plugins |
| Codex | .codex/config.toml, .codex/hooks.json, .codex/prompts/, .env (seulement les variables d'endpoint et de chargement de code), AGENTS.md |
| Cursor | .cursor/mcp.json, .cursor/hooks.json, .cursor/cli.json, .cursor/rules/, .cursor/commands/, .cursorrules, les hooks de .claude/settings*.json (Cursor les exécute), .vscode/tasks.json, AGENTS.md |
| OpenCode | opencode.json, opencode.jsonc, configuration, plugins, commandes et agents 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 |
| Tout agent | Exécutables à la racine auditée, .github/workflows/*.yml, .windsurfrules, .clinerules |
Rien de ce que contrôle le dépôt ne peut faire disparaître un fichier du rapport en silence :
- Un lien symbolique qui sort du dépôt est signalé (ZNA020), pas suivi.
- Un fichier d'agent de plus de 1 Mo est signalé (ZNA020) au lieu d'être ignoré.
- L'analyse s'arrête après 50 000 entrées de dossier ou 120 secondes, et le dit avec un résultat ZNA020 de gravité haute : l'exécution échoue donc au seuil par défaut.
- Un
.envà la racine, commité, qui pointeCODEX_HOMEouCLAUDE_CONFIG_DIRvers un dossier du dépôt fait lire aussi les configurations de ce dossier àzn audit. - Un
.envà la racine est audité même si.gitignorele liste, car dans un clone neuf il n'existe que s'il a été commité. Ses résultats sont d'un niveau plus bas et précisent qu'ils ne s'appliquent pas à votre.envlocal.
Avec --include-home, il lit aussi ~/.claude/settings.json, ~/.claude.json, ~/.codex/config.toml, ~/.cursor/mcp.json, ~/.cursor/hooks.json, ~/.aws/amazonq/mcp.json, ~/.config/opencode/opencode.json[c] et ~/.gemini/settings.json. Il respecte CODEX_HOME et XDG_CONFIG_HOME comme les agents. Les commandes que vous avez configurées vous-même sont normales à cet endroit : seules les variantes plus risquées sont signalées (code téléchargé puis exécuté, paquets non épinglés, changements d'endpoint, secrets et permissions étendues). Les résultats d'endpoint, d'environnement et de permissions sont plafonnés à medium.
Règles
Les identifiants de règles sont stables : une règle peut s'améliorer, mais son identifiant ne change jamais de sens. Les gravités sont critical, high, medium et low ; quand une règle en liste plusieurs, le résultat reçoit celle qui correspond au cas.
| Id | Gravité | Ce qu'elle détecte |
|---|---|---|
| ZNA001 | high / medium / low | Une commande qui s'exécute automatiquement depuis une configuration du projet : hooks, statusLine, notify de Codex, fichiers de plugins OpenCode, tâches VS Code avec runOn: folderOpen. Medium pour les hooks d'un plugin, qui ne s'exécutent qu'une fois le plugin activé. Le hook écrit par zn hooks install est signalé en low |
| ZNA002 | critical | Une commande automatique qui télécharge du code et l'exécute (curl ... | sh, iwr ... | iex, bash <(curl ...)) |
| ZNA003 | high / medium / low | Un serveur MCP du projet qui démarre une commande locale. High pour Codex et Amazon Q ; low pour le serveur de secrets de zn quand il est vérifié sur le disque |
| ZNA004 | high / medium | Des réglages du projet qui approuvent des serveurs MCP à l'avance (enableAllProjectMcpServers, enabledMcpjsonServers) |
| ZNA005 | medium | Un serveur MCP ou un plugin d'agent non épinglé : npx -y pkg, @latest, uvx pkg sans ==, images de conteneur sans tag ni digest, plugins OpenCode sans version |
| ZNA006 | medium / low | Un serveur MCP distant, ou des instructions chargées depuis une URL. Medium en http simple, low en https |
| ZNA007 | critical / high / medium / low | L'endpoint de l'API du modèle est remplacé (ANTHROPIC_BASE_URL, OPENAI_BASE_URL, toute variable *_BASE_URL, URL de base des fournisseurs dans Codex et OpenCode) ou un proxy est défini (HTTPS_PROXY). Critical pour un hôte distant, high pour un proxy, medium pour une adresse de loopback. Dans l'env d'un seul serveur MCP, cela ne redirige que ce serveur : medium, ou low pour le loopback |
| ZNA008 | high | Une variable d'environnement qui charge du code ou des certificats (NODE_OPTIONS, LD_PRELOAD, DYLD_INSERT_LIBRARIES, PYTHONSTARTUP, BASH_ENV, PATH, GIT_SSH_COMMAND, NODE_EXTRA_CA_CERTS et similaires) ou qui déplace l'endroit où l'agent lit sa configuration (CODEX_HOME, CLAUDE_CONFIG_DIR, XDG_CONFIG_HOME, OPENCODE_CONFIG). Vérifiée aussi dans l'env de chaque serveur MCP |
| ZNA009 | high | Une commande d'aide aux identifiants dans les réglages du projet (apiKeyHelper, awsAuthRefresh, awsCredentialExport, otelHeadersHelper) |
| ZNA010 | high / medium | Permissions étendues : Bash(*), Bash, *, jokers d'interpréteur comme Bash(python:*), defaultMode: bypassPermissions, approval_policy = "never" de Codex avec accès complet, "bash": "allow" d'OpenCode, chat.tools.autoApprove de VS Code |
| ZNA011 | high | Une valeur secrète dans une configuration d'agent ou un fichier d'instructions. Le rapport n'affiche jamais la valeur |
| ZNA012 | high / medium / low | Un motif d'injection de prompt dans les instructions d'un agent : ordres qui annulent les instructions, fausses balises système, HTML caché, Unicode invisible, balises d'image Markdown. Dans les fichiers qu'un agent lit comme instructions (AGENTS.md, CLAUDE.md, GEMINI.md, règles, skills, commandes, prompts), un motif fort n'est jamais abaissé, cité ou non |
| ZNA013 | medium / low | Des instructions qui demandent à l'agent de télécharger et d'exécuter du code. Low pour les installateurs bien connus comme rustup, uv, bun, deno, nvm et Homebrew |
| ZNA014 | high | Des instructions qui demandent à l'agent d'envoyer des secrets ou des fichiers à l'extérieur (.env, ~/.ssh, jetons vers une URL, curl -d @.env) |
| ZNA015 | medium | Des instructions qui demandent à l'agent de sauter les contrôles de sécurité ou de cacher ce qu'il fait (--no-verify, --dangerously-skip-permissions, « désactive le sandbox », « ne le dis pas à l'utilisateur ») |
| ZNA016 | critical / high | Un exécutable à la racine auditée qui porte le nom d'un outil courant (git.exe, node.exe, npm.cmd, python, zn.cmd). Critical pour les exécutables Windows. Windows et certains outils cherchent d'abord dans le dossier courant : le fichier planté s'exécute à la place du vrai outil |
| ZNA017 | medium | Des réglages du projet qui ajoutent des marketplaces de plugins ou activent des plugins (extraKnownMarketplaces, enabledPlugins) |
| ZNA018 | low | Le dépôt fournit des extensions d'agent (commandes, sous-agents, skills, plugins). C'est un inventaire : les autres règles les examinent, mais il faut savoir qu'elles sont là |
| ZNA019 | high / medium | Un workflow de CI qui lance un agent d'IA sur un texte que n'importe qui peut écrire (issues, issue_comment, pull_request_target, discussions). High avec pull_request_target, avec du texte d'issue ou de commentaire collé dans le workflow, avec une action ouverte aux utilisateurs sans droit d'écriture, ou avec une étape de CLI ayant des droits d'écriture et aucun filtre d'auteur |
| ZNA020 | high / low | Un fichier d'agent n'a pas pu être vérifié : erreur de syntaxe, taille supérieure à 1 Mo, lien symbolique sortant du dépôt ou analyse arrêtée avant la fin. High quand le fichier peut exécuter des commandes ou rediriger l'agent, ou quand l'analyse n'a pas terminé ; low pour une erreur de syntaxe dans un fichier qui ne peut rien exécuter |
Sortie
Texte
zn audit ./some-repo (zn-gate 1.12.0 ou plus récent)
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.
Les couleurs ne sont utilisées que dans un terminal et jamais quand NO_COLOR est défini. Les caractères de contrôle et les séquences d'échappement venant du dépôt sont affichés sous la forme \x1b, jamais envoyés à votre terminal.
JSON
--format json affiche un objet avec les findings et un 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 est relatif à root, avec des barres obliques ; les fichiers de --include-home commencent par ~/. agent est l'agent qui lit le fichier, ou any quand plusieurs le lisent. evidence est la ligne correspondante, coupée à 160 caractères, avec les secrets remplacés par [REDACTED:<TYPE>]. Les URL perdent leur utilisateur, mot de passe, query string et fragment.
SARIF
--format sarif écrit du SARIF 2.1.0 pour le code scanning de GitHub : une règle par identifiant ZNA avec un texte d'aide et un score de gravité, et des résultats localisés par rapport à la racine du dépôt. Chaque résultat porte une empreinte, donc les alertes survivent aux déplacements de lignes. Les résultats de --include-home sont marqués comme venant du dossier personnel et GitHub les ignore : n'utilisez pas cette option en CI.
L'utiliser en CI
Le plus simple est la GitHub Action de zn-gate avec mode: audit. Voir GitHub Actions.
Pour lancer vous-même la CLI, écrivez un fichier SARIF et envoyez-le au 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
Retirez --fail-on none (la valeur par défaut est high) si vous voulez que le job échoue sur les résultats high et critical. Ajoutez security-events: write au job seulement quand vous envoyez du SARIF.
Limites
- Il lit des fichiers ; il ne les exécute pas, ne démarre pas de serveurs et ne résout pas de paquets. Un paquet épinglé peut quand même être malveillant, et un hook qui appelle un script local est signalé comme hook, sans juger ce que fait le script.
- Les règles d'instructions cherchent des motifs ligne par ligne. Un auteur déterminé peut formuler une instruction qu'aucun motif ne détecte, et une documentation qui cite une commande dangereuse est signalée aussi, par exemple un guide d'installation avec
curl ... | sh. Examinez la preuve avant d'agir. - La règle des workflows lit le YAML ligne par ligne. Elle connaît les actions d'agents courantes et les clés de déclencheurs et de permissions, pas les workflows réutilisables ni les actions composites.
- La configuration Git (
.git/config, filtres.gitattributes) et les extensions d'éditeur ne sont pas vérifiées. - Les agents changent souvent de format de configuration. Les clés inconnues sont ignorées, pas signalées.
- Les secrets sont détectés par format et par nom de clé sensible. Un secret sans format connu sous un nom de clé anodin n'est pas détecté, et les mots de passe écrits en prose ne sont pas masqués dans la preuve.