Auditoría
zn audit lee los archivos de configuración de agentes de un repositorio, sin ejecutar nada, e indica qué se ejecutaría, adónde irían las peticiones y qué instrucciones seguiría un agente.
npx -y zn-gate audit ./some-repo
(o zn audit si lo instalaste con npm i -g zn-gate; zn-gate audit es el mismo comando).
Los agentes de código leen configuración del repositorio en el que trabajan. Varios de esos archivos ejecutan comandos, arrancan servidores MCP, cambian adónde envía el agente sus peticiones a la API o amplían lo que puede hacer sin preguntar. Actualizar el agente corrige los fallos conocidos, pero los archivos siguen en el repositorio, y el siguiente agente, un compañero con una versión antigua o un trabajo de CI pueden seguir haciéndoles caso.
zn audit lee esos archivos, sin ejecutar nada, y te dice qué se ejecutaría, adónde irían las peticiones y qué instrucciones seguiría un agente. Funciona en local y no envía nada a ningún sitio. Ejecútalo antes de abrir un repositorio que acabas de clonar, y en CI.
Opciones
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]
| Opción | Por defecto | Qué hace |
|---|---|---|
path |
. |
Directorio que se audita, normalmente la raíz del repositorio. Un zn audit sin argumentos revisa el directorio actual |
--format |
text |
text para personas, json para scripts, sarif para el code scanning de GitHub |
--output |
salida estándar | Escribe el informe en un archivo |
--fail-on |
high |
Termina con código 1 si algún hallazgo tiene esta gravedad o una mayor. none nunca falla |
--agents |
all |
Revisa solo los archivos que leen estos agentes: claude, codex, cursor, opencode, amazonq, copilot, gemini o all. Los hallazgos que afectan a todos los agentes (AGENTS.md, ejecutables plantados, flujos de CI) se muestran siempre |
--include-home |
desactivado | Revisa también tus propias configuraciones de usuario, como ~/.claude/settings.json y ~/.codex/config.toml |
Ejemplos:
# Antes de abrir un repositorio que acabas de clonar
npx -y zn-gate audit ./some-repo
# En CI: escribe un archivo SARIF para el code scanning de GitHub y no falla nunca
zn audit --format sarif --output zn-audit.sarif --fail-on none
# Solo lo que leen Claude Code y Codex; falla solo con critical
zn audit --agents claude,codex --fail-on critical
En la 1.5, zn audit mostraba el registro local de uso de secretos. Ese registro es ahora zn vault log (también zn secret log). zn audit log y zn audit --since DATE terminan con código 2 y te indican que uses zn vault log.
Códigos de salida
| Código | Significado |
|---|---|
0 |
Ningún hallazgo en --fail-on o por encima |
1 |
Al menos un hallazgo en --fail-on o por encima |
2 |
Error de uso o de ejecución: opción incorrecta, ruta que no existe, salida no escribible |
Qué lee
Archivos del proyecto a cualquier profundidad, porque la configuración de un subdirectorio se aplica cuando un agente arranca allí. Las carpetas de agentes (.claude, .codex, .cursor, .github, skills y similares) se leen primero. Fuera de ellas se omiten node_modules, vendor y las carpetas de compilación y de entornos virtuales. .git no se lee nunca.
| Agente | Archivos |
|---|---|
| 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 de los plugins |
| Codex | .codex/config.toml, .codex/hooks.json, .codex/prompts/, .env (solo las variables de endpoint y de carga de código), AGENTS.md |
| Cursor | .cursor/mcp.json, .cursor/hooks.json, .cursor/cli.json, .cursor/rules/, .cursor/commands/, .cursorrules, los hooks de .claude/settings*.json (Cursor los ejecuta), .vscode/tasks.json, AGENTS.md |
| OpenCode | opencode.json, opencode.jsonc, configuración, plugins, comandos y 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 |
| Cualquier agente | Ejecutables en la raíz auditada, .github/workflows/*.yml, .windsurfrules, .clinerules |
Nada de lo que controla el repositorio puede hacer que un archivo desaparezca del informe en silencio:
- Un enlace simbólico que sale del repositorio se notifica (ZNA020) y no se sigue.
- Un archivo de agente de más de 1 MB se notifica (ZNA020) en lugar de omitirse.
- El análisis se detiene tras 50.000 entradas de directorio o 120 segundos, y lo indica con un hallazgo ZNA020 de gravedad alta, así que la ejecución falla con el umbral por defecto.
- Un
.envde la raíz incluido en el repositorio que apuntaCODEX_HOMEoCLAUDE_CONFIG_DIRa una carpeta dentro del repositorio hace quezn auditlea también las configuraciones de esa carpeta. - Un
.envde la raíz se audita aunque.gitignorelo liste, porque en un clon nuevo solo existe si se subió al repositorio. Sus hallazgos bajan un nivel e indican que no se aplican a tu.envlocal.
Con --include-home lee además ~/.claude/settings.json, ~/.claude.json, ~/.codex/config.toml, ~/.cursor/mcp.json, ~/.cursor/hooks.json, ~/.aws/amazonq/mcp.json, ~/.config/opencode/opencode.json[c] y ~/.gemini/settings.json. Respeta CODEX_HOME y XDG_CONFIG_HOME igual que los agentes. Los comandos que configuraste tú son lo esperable ahí, así que solo se notifican las variantes más arriesgadas: código descargado y ejecutado, paquetes sin fijar, cambios de endpoint, secretos y permisos amplios. Los hallazgos de endpoint, entorno y permisos se limitan a medium.
Reglas
Los ids de las reglas son estables: una regla puede mejorar, pero su id nunca cambia de significado. Las gravedades son critical, high, medium y low; cuando una regla lista varias, el hallazgo recibe la que corresponde al caso.
| Id | Gravedad | Qué detecta |
|---|---|---|
| ZNA001 | high / medium / low | Un comando que se ejecuta automáticamente desde una configuración del proyecto: hooks, statusLine, notify de Codex, archivos de plugins de OpenCode, tareas de VS Code con runOn: folderOpen. Medium para los hooks de un plugin, que solo se ejecutan cuando el plugin está activado. El hook que escribe zn hooks install se notifica como low |
| ZNA002 | critical | Un comando automático que descarga código y lo ejecuta (curl ... | sh, iwr ... | iex, bash <(curl ...)) |
| ZNA003 | high / medium / low | Un servidor MCP del proyecto que arranca un comando local. High para Codex y Amazon Q; low para el servidor de secretos de zn cuando se verifica en disco |
| ZNA004 | high / medium | Una configuración del proyecto que aprueba servidores MCP por adelantado (enableAllProjectMcpServers, enabledMcpjsonServers) |
| ZNA005 | medium | Un servidor MCP o plugin de agente sin versión fijada: npx -y pkg, @latest, uvx pkg sin ==, imágenes de contenedor sin etiqueta ni digest, plugins de OpenCode sin versión |
| ZNA006 | medium / low | Un servidor MCP remoto, o instrucciones cargadas desde una URL. Medium con http sin cifrar, low con https |
| ZNA007 | critical / high / medium / low | Se cambia el endpoint de la API del modelo (ANTHROPIC_BASE_URL, OPENAI_BASE_URL, cualquier *_BASE_URL, URLs base de proveedores en Codex y OpenCode) o se define un proxy (HTTPS_PROXY). Critical para un host remoto, high para un proxy, medium para una dirección de loopback. Dentro del env de un solo servidor MCP solo redirige ese servidor: medium, o low para loopback |
| ZNA008 | high | Una variable de entorno que carga código o certificados (NODE_OPTIONS, LD_PRELOAD, DYLD_INSERT_LIBRARIES, PYTHONSTARTUP, BASH_ENV, PATH, GIT_SSH_COMMAND, NODE_EXTRA_CA_CERTS y similares) o que cambia dónde lee el agente su configuración (CODEX_HOME, CLAUDE_CONFIG_DIR, XDG_CONFIG_HOME, OPENCODE_CONFIG). También se revisa en el env de cada servidor MCP |
| ZNA009 | high | Un comando auxiliar de credenciales en la configuración del proyecto (apiKeyHelper, awsAuthRefresh, awsCredentialExport, otelHeadersHelper) |
| ZNA010 | high / medium | Permisos amplios: Bash(*), Bash, *, comodines de intérprete como Bash(python:*), defaultMode: bypassPermissions, approval_policy = "never" de Codex con acceso total, "bash": "allow" de OpenCode, chat.tools.autoApprove de VS Code |
| ZNA011 | high | Un valor secreto en una configuración de agente o en un archivo de instrucciones. El informe nunca imprime el valor |
| ZNA012 | high / medium / low | Un patrón de inyección de prompts en las instrucciones de un agente: órdenes que anulan instrucciones, etiquetas de sistema falsas, HTML oculto, Unicode invisible, balizas de imagen en Markdown. En los archivos que un agente lee como instrucciones (AGENTS.md, CLAUDE.md, GEMINI.md, reglas, skills, comandos, prompts) un patrón fuerte nunca se rebaja, esté citado o no |
| ZNA013 | medium / low | Instrucciones que le dicen al agente que descargue y ejecute código. Low para instaladores muy conocidos como rustup, uv, bun, deno, nvm y Homebrew |
| ZNA014 | high | Instrucciones que le dicen al agente que envíe secretos o archivos al exterior (.env, ~/.ssh, tokens a una URL, curl -d @.env) |
| ZNA015 | medium | Instrucciones que le dicen al agente que se salte las comprobaciones de seguridad o que oculte lo que hace (--no-verify, --dangerously-skip-permissions, "desactiva el sandbox", "no se lo digas al usuario") |
| ZNA016 | critical / high | Un ejecutable en la raíz auditada con el mismo nombre que una herramienta común (git.exe, node.exe, npm.cmd, python, zn.cmd). Critical para ejecutables de Windows. Windows y algunas herramientas buscan primero en la carpeta actual, así que el archivo plantado se ejecuta en lugar de la herramienta real |
| ZNA017 | medium | Una configuración del proyecto que añade marketplaces de plugins o activa plugins (extraKnownMarketplaces, enabledPlugins) |
| ZNA018 | low | El repositorio incluye extensiones de agente (comandos, subagentes, skills, plugins). Es un inventario: las demás reglas las revisan, pero conviene saber que están ahí |
| ZNA019 | high / medium | Un flujo de CI que ejecuta un agente de IA con texto que puede escribir cualquiera (issues, issue_comment, pull_request_target, discussions). High con pull_request_target, con texto de una issue o comentario pegado en el flujo, con una acción abierta a usuarios sin permiso de escritura, o con un paso de CLI con permisos de escritura y sin filtro de autor |
| ZNA020 | high / low | No se pudo revisar un archivo de agente: error de sintaxis, tamaño superior a 1 MB, enlace simbólico que sale del repositorio o análisis detenido antes de terminar. High cuando el archivo puede ejecutar comandos o redirigir al agente, o cuando el análisis no terminó; low para un error de sintaxis en un archivo que no puede ejecutar nada |
Salida
Texto
zn audit ./some-repo (zn-gate 1.12.0 o 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.
Los colores solo se usan en un terminal y nunca con NO_COLOR definido. Los caracteres de control y las secuencias de escape que vienen del repositorio se imprimen como \x1b, nunca se envían a tu terminal.
JSON
--format json imprime un objeto con los findings y 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 es relativo a root y usa barras normales; los archivos de --include-home empiezan por ~/. agent es el agente que lee el archivo, o any cuando lo leen varios. evidence es la línea que coincide, cortada a 160 caracteres, con los secretos sustituidos por [REDACTED:<TYPE>]. A las URL se les quitan el usuario, la contraseña, la query y el fragmento.
SARIF
--format sarif escribe SARIF 2.1.0 para el code scanning de GitHub: una regla por cada id ZNA con texto de ayuda y una puntuación de gravedad, y resultados ubicados respecto a la raíz del repositorio. Cada resultado lleva una huella, así que las alertas sobreviven a los cambios de línea. Los hallazgos de --include-home se marcan como procedentes de la carpeta personal y GitHub los ignora, así que no uses esa opción en CI.
Úsalo en CI
Lo más sencillo es la GitHub Action de zn-gate con mode: audit. Consulta GitHub Actions.
Para ejecutar la CLI tú mismo, escribe un archivo SARIF y súbelo al 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
Quita --fail-on none (el valor por defecto es high) si quieres que el trabajo falle con hallazgos high y critical. Añade security-events: write al trabajo solo cuando subas SARIF.
Límites
- Lee archivos; no los ejecuta, no arranca servidores ni resuelve paquetes. Un paquete con versión fijada puede seguir siendo malicioso, y un hook que llama a un script local se notifica como hook, sin juzgar lo que hace el script.
- Las reglas de instrucciones buscan patrones línea a línea. Un autor decidido puede redactar una instrucción que ningún patrón detecte, y la documentación que cita un comando peligroso también se notifica, por ejemplo una guía de instalación con
curl ... | sh. Revisa la evidencia antes de actuar. - La regla de flujos lee el YAML línea a línea. Conoce las acciones de agentes habituales y las claves de disparadores y permisos, no los flujos reutilizables ni las acciones compuestas.
- No se revisan la configuración de Git (
.git/config, filtros de.gitattributes) ni las extensiones de editor. - Los agentes cambian a menudo sus formatos de configuración. Las claves desconocidas se ignoran, no se notifican.
- Los secretos se detectan por formato y por nombre de clave sensible. Un secreto sin formato conocido bajo un nombre de clave inocente no se detecta, y las contraseñas escritas en prosa no se ocultan en la evidencia.