审计

zn audit 读取仓库中的智能体配置文件,不运行任何内容,并报告会执行什么、请求会发往哪里、智能体会遵循哪些指令。

查看 .md
npx -y zn-gate audit ./some-repo

(如果你用 npm i -g zn-gate 安装了它,也可以直接运行 zn audit;zn-gate audit 是同一个命令。)

编程智能体会读取它所在仓库中的配置。其中不少文件会运行命令、启动 MCP 服务器、改变智能体发送 API 请求的目的地,或者扩大它无需询问就能做的事。更新智能体可以修复已知的漏洞,但这些文件仍留在仓库里,下一个智能体、使用旧版本的同事或某个 CI 任务仍可能照着它们行事。

zn audit 读取这些文件,不运行任何内容,告诉你会执行什么、请求会发往哪里、智能体会遵循哪些指令。它在本地运行,不会向任何地方发送任何内容。请在打开刚克隆的仓库之前运行它,也可以在 CI 中运行。

选项

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]
选项 默认值 作用
path . 要审计的目录,通常是仓库根目录。不带参数的 zn audit 会检查当前目录
--format text text 供人阅读,json 供脚本使用,sarif 供 GitHub 代码扫描使用
--output 标准输出 把报告写入文件
--fail-on high 只要有任何结果达到或高于该严重程度,就以退出码 1 结束。none 永不失败
--agents all 只检查这些智能体会读取的文件:claude、codex、cursor、opencode、amazonq、copilot、gemini 或 all。涉及所有智能体的结果(AGENTS.md、被植入的可执行文件、CI 工作流)始终会显示
--include-home 关闭 同时检查你自己的用户级配置,例如 ~/.claude/settings.json 和 ~/.codex/config.toml

示例:

# 打开刚克隆的仓库之前
npx -y zn-gate audit ./some-repo

# 在 CI 中:为 GitHub 代码扫描写出 SARIF 文件,并且永不让任务失败
zn audit --format sarif --output zn-audit.sarif --fail-on none

# 只检查 Claude Code 和 Codex 会读取的内容;仅在 critical 时失败
zn audit --agents claude,codex --fail-on critical

在 1.5 中,zn audit 显示的是密钥使用的本地日志。该日志现在是 zn vault log(也可用 zn secret log)。zn audit log 和 zn audit --since DATE 会以退出码 2 结束,并提示你改用 zn vault log。

退出码

退出码 含义
0 没有达到或高于 --fail-on 的结果
1 至少有一个结果达到或高于 --fail-on
2 使用或运行错误:选项无效、找不到路径、输出不可写

它读取什么

任意深度的项目文件,因为智能体在子目录中启动时,该子目录的配置会生效。智能体文件夹(.claude、.codex、.cursor、.github、skills 等)会优先读取。在这些文件夹之外,node_modules、vendor 以及构建和虚拟环境文件夹会被跳过。.git 永远不会被读取。

智能体 文件
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
Codex .codex/config.toml、.codex/hooks.json、.codex/prompts/、.env(仅限端点和加载代码相关的变量)、AGENTS.md
Cursor .cursor/mcp.json、.cursor/hooks.json、.cursor/cli.json、.cursor/rules/、.cursor/commands/、.cursorrules、.claude/settings*.json 中的钩子(Cursor 会运行它们)、.vscode/tasks.json、AGENTS.md
OpenCode opencode.json、opencode.jsonc、.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
任何智能体 被审计根目录中的可执行文件、.github/workflows/*.yml、.windsurfrules、.clinerules

仓库所能控制的任何内容,都不能让文件悄悄从报告中消失:

  • 指向仓库之外的符号链接会被报告(ZNA020),而不会被跟随。
  • 超过 1 MB 的智能体文件会被报告(ZNA020),而不是被跳过。
  • 扫描在 50,000 个目录条目或 120 秒后停止,并以 ZNA020 高严重度结果说明这一点,因此运行会在默认阈值下失败。
  • 已提交的根目录 .env 如果把 CODEX_HOME 或 CLAUDE_CONFIG_DIR 设为仓库内的文件夹,zn audit 也会读取那里的配置。
  • 根目录的 .env 即使被 .gitignore 列出也会被审计,因为在新克隆的仓库中,它只有在被提交过的情况下才会存在。它的结果会低一个级别,并说明这些结果不适用于你自己的本地 .env。

使用 --include-home 时,它还会读取 ~/.claude/settings.json、~/.claude.json、~/.codex/config.toml、~/.cursor/mcp.json、~/.cursor/hooks.json、~/.aws/amazonq/mcp.json、~/.config/opencode/opencode.json[c] 和 ~/.gemini/settings.json。它会像智能体一样遵循 CODEX_HOME 和 XDG_CONFIG_HOME。你自己配置的命令在这些文件中是预期之内的,所以只会报告风险更高的情形:下载后运行的代码、未固定版本的包、端点覆盖、密钥和宽泛的权限。端点、环境变量和权限相关的结果在这里最高为 medium。

规则

规则 id 是稳定的:规则可以改进,但它的 id 含义永远不变。严重程度为 critical、high、medium 和 low;当一条规则列出多个级别时,结果会取最符合具体情况的那个。

Id 严重程度 检测内容
ZNA001 high / medium / low 从项目配置自动运行的命令:钩子、statusLine、Codex 的 notify、OpenCode 插件文件、带 runOn: folderOpen 的 VS Code 任务。插件的钩子为 medium,因为它们只有在插件启用后才会运行。zn hooks install 写入的钩子会被报告为 low
ZNA002 critical 自动下载代码并运行的命令(curl ... | sh、iwr ... | iex、bash <(curl ...))
ZNA003 high / medium / low 项目中的 MCP 服务器启动本地命令。Codex 和 Amazon Q 为 high;zn 自带的密钥服务器在磁盘上验证通过时为 low
ZNA004 high / medium 项目设置预先批准 MCP 服务器(enableAllProjectMcpServers、enabledMcpjsonServers)
ZNA005 medium 未固定版本的 MCP 服务器或智能体插件:npx -y pkg、@latest、不带 == 的 uvx pkg、没有标签或摘要的容器镜像、没有版本的 OpenCode 插件
ZNA006 medium / low 远程 MCP 服务器,或从 URL 加载的指令。明文 http 为 medium,https 为 low
ZNA007 critical / high / medium / low 模型 API 端点被覆盖(ANTHROPIC_BASE_URL、OPENAI_BASE_URL、任何 *_BASE_URL、Codex 和 OpenCode 中提供方的基础 URL)或设置了代理(HTTPS_PROXY)。远程主机为 critical,代理为 high,回环地址为 medium。在单个 MCP 服务器的 env 中,只会重定向该服务器:medium,回环地址为 low
ZNA008 high 会加载代码或证书的环境变量(NODE_OPTIONS、LD_PRELOAD、DYLD_INSERT_LIBRARIES、PYTHONSTARTUP、BASH_ENV、PATH、GIT_SSH_COMMAND、NODE_EXTRA_CA_CERTS 等),或改变智能体读取配置位置的变量(CODEX_HOME、CLAUDE_CONFIG_DIR、XDG_CONFIG_HOME、OPENCODE_CONFIG)。每个 MCP 服务器的 env 中也会检查
ZNA009 high 项目设置中的凭据辅助命令(apiKeyHelper、awsAuthRefresh、awsCredentialExport、otelHeadersHelper)
ZNA010 high / medium 宽泛的权限:Bash(*)、Bash、*、Bash(python:*) 这类解释器通配符、defaultMode: bypassPermissions、Codex 在完全访问下的 approval_policy = "never"、OpenCode 的 "bash": "allow"、VS Code 的 chat.tools.autoApprove
ZNA011 high 智能体配置或指令文件中的密钥值。报告绝不会打印该值
ZNA012 high / medium / low 智能体指令中的提示注入模式:覆盖指令、伪造的系统标签、隐藏的 HTML、不可见的 Unicode、Markdown 图片信标。在智能体当作指令读取的文件(AGENTS.md、CLAUDE.md、GEMINI.md、规则、技能、命令、提示)中,强模式无论是否被引用都不会被降级
ZNA013 medium / low 指示智能体下载并运行代码的指令。对 rustup、uv、bun、deno、nvm 和 Homebrew 等知名安装程序为 low
ZNA014 high 指示智能体向外发送密钥或文件的指令(.env、~/.ssh、把令牌发到某个 URL、curl -d @.env)
ZNA015 medium 指示智能体跳过安全检查或隐瞒其行为的指令(--no-verify、--dangerously-skip-permissions、“关闭沙箱”、“不要告诉用户”)
ZNA016 critical / high 被审计根目录中的可执行文件与常见工具同名(git.exe、node.exe、npm.cmd、python、zn.cmd)。Windows 可执行文件为 critical。Windows 和某些工具会先在当前文件夹中查找,因此被植入的文件会取代真正的工具运行
ZNA017 medium 项目设置添加插件市场或启用插件(extraKnownMarketplaces、enabledPlugins)
ZNA018 low 仓库附带智能体扩展(命令、子智能体、技能、插件)。这是一份清单:其他规则会审查它们,但你应该知道它们的存在
ZNA019 high / medium CI 工作流在任何人都能写入的输入(issues、issue_comment、pull_request_target、discussions)上运行 AI 智能体。出现 pull_request_target、工作流中直接粘贴了 issue 或评论文本、某个 action 对没有写权限的用户开放,或者 CLI 步骤具有写权限且没有作者过滤时为 high
ZNA020 high / low 某个智能体文件无法检查:语法错误、大小超过 1 MB、指向仓库之外的符号链接,或扫描提前停止。文件能运行命令或重定向智能体,或扫描未完成时为 high;对无法运行任何内容的文件中的语法错误为 low

输出

文本

zn audit  ./some-repo  (zn-gate 1.12.0 或更高版本)

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.

只有在终端中才会使用颜色,设置了 NO_COLOR 时绝不使用。来自仓库的控制字符和转义序列会以 \x1b 的形式打印,绝不会发送到你的终端。

JSON

--format json 输出一个包含 findings 和 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 相对于 root,使用正斜杠;来自 --include-home 的文件以 ~/ 开头。agent 是读取该文件的智能体,多个智能体都会读取时为 any。evidence 是匹配的那一行,截断为 160 个字符,其中的密钥会被替换为 [REDACTED:<TYPE>]。URL 中的用户名、密码、查询字符串和片段都会被去掉。

SARIF

--format sarif 为 GitHub 代码扫描写出 SARIF 2.1.0:每个 ZNA id 对应一条规则,带有帮助文本和严重度分数,结果的位置相对于仓库根目录。每个结果都带有指纹,因此行号移动后告警依然保留。来自 --include-home 的结果会被标记为来自主目录,GitHub 会忽略它们,所以请在 CI 中不要使用该选项。

在 CI 中使用

最简单的方式是使用 zn-gate 的 GitHub Action,并设置 mode: audit。见 GitHub Actions。

如果想自己运行命令行,请写出 SARIF 文件并上传到代码扫描:

- 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

如果希望任务在出现 high 和 critical 结果时失败,请去掉 --fail-on none(默认值是 high)。只有在上传 SARIF 时,才需要给任务添加 security-events: write。

局限

  • 它只读取文件;不会运行它们、启动服务器或解析包。固定了版本的包仍可能是恶意的,调用本地脚本的钩子只会被报告为钩子,而不会根据脚本的实际行为来判断。
  • 指令规则逐行匹配模式。有决心的作者可以写出任何模式都检测不到的指令,而引用危险命令的文档同样会被报告,例如带有 curl ... | sh 的安装指南。请在采取行动前查看证据。
  • 工作流规则逐行读取 YAML。它了解常见的智能体 action 以及触发器和权限的键,但不了解可复用工作流或组合 action。
  • Git 配置(.git/config、.gitattributes 过滤器)和编辑器扩展不在检查范围内。
  • 智能体经常更改配置格式。未知的键会被忽略,而不会被报告。
  • 密钥是按格式和敏感键名来发现的。没有已知格式、且放在普通键名之下的密钥不会被发现,用文字写出的密码也不会在证据中被隐去。