用开源 Agent 套件 ECC 扫一遍你的 Agent 配置:提示词、钩子与 MCP

2026-07-29

本文基于 ECC 仓库 commit 591ab5c(2026-07-29)梳理,该项目仍在高频迭代,具体行为以仓库 https://github.com/affaan-m/ECC 最新代码与文档为准。

你项目里的 .claude/ 目录不是文档,是执行面。 里面的权限清单决定模型能碰哪些路径,hooks 决定每次 Bash 之前会跑什么脚本,mcp.json 决定哪些外部进程能挂进会话,CLAUDE.md 里写的每一句话都会被当成指令读进上下文。这些文件通常跟着仓库一起被 clone,没人 review,也不在任何代码扫描器的关注范围里。ECC 这套开源增强件里有一条专门针对这层的扫描链路,叫 security-scan——它扫的就是这些「不像代码的代码」。

先说清楚这篇和站内几篇的分工:AI 代码安全审计讲的是业务代码本身怎么审,MCP 的安全边界讲的是协议层该划哪些线,Agent 提示注入防御讲的是防注入的通用方法论。那三篇给的是判断框架,这篇给的是一个具体开源项目把这些框架落成命令、技能、agent 定义和 CI 门禁之后长什么样,以及你把它跑起来会看到什么、该怎么处理。

一、它盯的是配置面,而不是你的业务代码

ECC 仓库根目录有一篇 the-security-guide.md,是这条扫描链路的问题陈述。里面讲的核心事实是:项目配置、hooks、MCP 设置和环境变量,现在已经是执行面的一部分。Check Point Research 披露的两个 Claude Code 问题就是这个判断的实证——CVE-2025-59536 让项目内的代码可以在用户点下信任对话框之前执行;CVE-2026-21852 让被攻击者控制的项目可以覆盖 ANTHROPIC_BASE_URL,把 API 流量导走并在信任确认之前泄露 key。指南里还提到第三类:仓库自带的 MCP 配置与设置可以让项目级 MCP server 在用户真正信任这个目录之前就被自动批准。

这三件事的共同点是,触发条件只是「你 clone 了一个仓库,然后打开了工具」。你没写一行代码,没批准一次操作。

指南里那句话值得抄下来当判断基准:一切进入上下文窗口的文本都是可执行上下文,「数据」和「指令」的区分在模型这里并不成立。所以配置文件里的一段说明文字、MCP 工具描述里的一句 schema 注释、记忆文件里存了半年的一条约定,全都要按「可能被当成指令」来对待。

skills/security-scan/SKILL.md 里有一张表,把扫描目标拆成五类文件,每类各查什么:CLAUDE.md 查硬编码密钥、自动执行指令、提示注入模式;settings.json 查过宽的 allow 列表、缺失的 deny 列表、危险的绕过开关;mcp.json 查高风险 MCP server、环境变量里的硬编码密钥、npx 供应链风险;hooks 目录查插值造成的命令注入、数据外泄、静默吞错;agents 下的 md 文件查无限制的工具访问、提示注入暴露面、缺失的模型声明。

注意最后一类。agent 定义是 markdown,读起来像人写给人看的说明,但它的 frontmatter 里那行 tools 决定这个角色能调什么。ECC 自己的 agents/security-reviewer.md 里写的是 tools: Read, Grep, Glob, Bash——它带 Bash。扫描器会把「agent 拥有不必要的 Bash 访问」列成 high。这不是自相矛盾,是提醒你:这类文件的权限含义得逐个判断,不能因为它是 markdown 就跳过。

二、这条链路由哪几块拼起来

跑之前先弄清楚你在调用什么。ECC 的 agents 目录有 67 个 agent、skills 目录有 281 个技能、commands 目录有 94 个命令,security-scan 只是其中一条竖线,但它把这几种资产类型都串上了。

组成部分它负责什么仓库位置你什么时候会碰到它
/security-scan 斜杠命令编排:跑扫描器,再把输出整理成排好序的修复计划commands/security-scan.md你在会话里主动敲的时候
security-scan 技能说明书:什么时机该扫、各个参数怎么用、结果怎么读skills/security-scan/SKILL.md你刚改完配置文件、技能被带出来的时候
security-reviewer 这个 agent执行角色,命令的 frontmatter 里用 agent: 指定了它,并且标了 subtask: trueagents/security-reviewer.md命令派活的时候,你一般不直接调
AgentShield 扫描器确定性检测引擎,命令里把它称为唯一事实来源独立仓库,npm 包名 ecc-agentshield每一次实际扫描
GitHub Action 形态CI 门禁,两份文档里都给了同一段 YAML片段写在 commands/security-scan.mdskills/security-scan/SKILL.md你要把它接进流水线的时候
安全指南长文威胁模型、手工排查手法、最低标准清单the-security-guide.md你想搞懂它为什么这么扫的时候

这里有个容易混的点:ECC 的 skills 目录下还有一个 security-review(没有 scan),那个是代码层的,管的是认证、用户输入、密钥管理、支付这些常规 OWASP 面。security-scan 管的是配置层。两个名字只差一个词,用途完全不同,别搭错。

命令文件里那句约束写得很直白:不要编造发现,把扫描器输出当作事实来源,并且把扫描器给出的事实和后续的人为判断分开陈述。这句话是给执行这条命令的模型看的,但它同时也是给你的读法提示——报告里哪部分是工具查到的、哪部分是模型的推断,你得自己分得清。

三、实操:从检查安装到接进 CI

技能文件给的第一步是确认扫描器在不在:

# Check if installed
npx ecc-agentshield --version

# Install globally (recommended)
npm install -g ecc-agentshield

然后是最基础的三种跑法,分别是扫当前项目、扫指定路径、按最低严重级别过滤:

# Scan current project
npx ecc-agentshield scan

# Scan a specific path
npx ecc-agentshield scan --path /path/to/.claude

# Scan with minimum severity filter
npx ecc-agentshield scan --min-severity medium

命令文件里给的是带默认值的写法,适合塞进脚本:

npx ecc-agentshield scan --path "${TARGET_PATH:-.}" --format text

输出有四种格式:终端彩色报告是默认,json 给 CI 用,markdown 用于交接,html 会生成一份自带样式的独立报告文件,重定向出去就能单独发给别人看。--format 这个参数在命令的 usage 行里写得很完整,四个取值一个不多一个不少。

--fix 是唯一会改你文件的参数。技能文件里明确了它的三条行为:把硬编码密钥替换成环境变量引用,把通配符权限收紧成有范围的替代写法,绝不动那些标为「只能手工处理」的建议。命令文件在这一点上追加了一条流程要求——请求 --fix 时,要先把计划中的编辑说清楚再动手,改完重新扫一遍并报出前后分数对比。

深度分析是另一条路径。技能文件里写的是一条对抗式三角色流水线:Attacker 走红队找攻击路径,Defender 走蓝队给加固建议,Auditor 综合两边出最终结论。它需要 ANTHROPIC_API_KEY 环境变量,也就是说这条路会把你的配置内容送去模型服务商。各家服务商的数据处理规则不同且会调整,以官方最新说明为准,但机制上你要清楚:这一步的输入正是你刚才怀疑藏着密钥的那批文件。

还有一条反方向的入口:扫描器带 init 子命令,可以从零脚手架一份配置,生成的是带范围限定权限和 deny 列表的 settings.json、一份写了安全实践的 CLAUDE.md,以及一个 mcp.json 占位。新仓库开工时用这个,比事后扫出一堆 high 再回头补要省事。

接进 CI 用的是同一套东西的 Action 形态:

- uses: affaan-m/agentshield@v1
  with:
    path: "."
    min-severity: "medium"
    fail-on-findings: true

fail-on-findings 打开就是硬门禁。第一次接的时候建议先把 min-severity 调高、fail-on-findings 关掉跑几轮,摸清你这个仓库的基线噪声量,再往下收。

四、报出来的东西怎么排先后

命令文件里定义了一份输出契约,六项内容:安全等级与分数、按严重度和运行时置信度分的计数、critical 与 high 条目及其确切路径、低置信度条目单独分组、修复顺序、以及跑了哪些命令、这次扫描是本地跑的还是 CI 跑的还是走 npx。最后那项别当废话——它决定了这份报告能不能复现。

真正决定你先修哪条的,是两个正交的维度。

第一个维度是严重度。 技能文件把四档的典型条目都列了。critical 是立刻要停下来处理的:配置文件里的硬编码 API key 或 token、allow 列表里出现 Bash(*) 这种不设限的 shell 访问、hooks 里通过 ${file} 插值造成的命令注入、以及会拉起 shell 的 MCP server。high 是上生产之前必须处理的:CLAUDE.md 里的自动执行指令(这是典型的提示注入落点)、权限里缺 deny 列表、agent 拿了不必要的 Bash。medium 属于建议处理:hooks 里的 2>/dev/null|| true 这类静默吞错、缺少 PreToolUse 安全钩子、MCP 配置里用 npx -y 自动安装。info 只是让你知道有这么回事,比如 MCP server 缺描述,或者某条禁止性指令被正确识别成了好实践。

2>/dev/null 被列进 medium 这件事值得多说一句。钩子里吞掉错误不是风格问题——一个本该拦下危险命令的钩子,如果它自己崩了却被 || true 兜住,行为上就等于这个钩子不存在,而你还以为它在守着。关于钩子这层机制本身怎么运作,可以看钩子机制那篇。

第二个维度是运行时置信度。 这是命令文件里单独拎出来的一列,也是这套设计里最实用的地方。它要求先识别活跃的运行时发现——硬编码密钥、过宽权限、可执行的 hooks、带 shell 或文件系统或远程传输或未固定版本 npx 的 MCP server、处理不可信内容却没有防御的 agent 提示词;然后把另一类单独分组:文档里的示例、模板目录里的示例、插件清单、项目本地的可选设置。

这两类在扫描器眼里长得一模一样,但价值天差地别。一段写在 README 里演示「不要这样写」的错误配置,和一段真的挂在你 PreToolUse 上的钩子,前者改了没有任何安全收益,后者不改就是敞着门。任何一个内容型仓库跑完这个扫描,第二类的数量都会远超第一类。分不清这两类,你会花整个下午去修文档。

命令文件对每条 critical 和 high 要求返回六个字段:文件路径、严重度、运行时置信度、为什么重要、确切的修复动作、以及这条能不能安全地自动修。拿到报告先看第六个字段,能自动修的攒一批走 --fix,不能自动修的按第五个字段逐条手工处理。

最后是等级和分数。评级从 A 到 F 五档,SKILL.md 里给了每档对应的分数区间。这个分数是启发式的相对刻度,用来看趋势——修完一批再扫一次,分数该往上走。别把它当合规结论,也别当成对外承诺的指标。

五、边界与代价:它明确不管什么

这套东西的取向很清楚,代价也很清楚。

它不看你的业务代码。 扫描面就是那五类配置文件。你的 SQL 拼接、你的鉴权中间件、你的依赖漏洞,它一个都不查。那部分在 ECC 里是另外的资产(skills/security-review/SKILL.md 和 security-reviewer 那份 OWASP 清单)。所以扫出 A 不代表这个仓库安全,只代表这个仓库的 Agent 配置面没查出明显问题。

它不看运行时。 扫的是静态文件。会话里模型实际读进了什么外部内容、调了哪些工具、试图连哪个地址,它一概不知道。指南自己也承认这一点,所以另起了一节讲可观测性:至少要记工具名、输入摘要、碰过的文件、审批决定、网络尝试、会话或任务 id。静态扫描和运行时日志是两件事,缺一个就是半套。

它不进 MCP server 内部。 它看的是配置层——这个 server 用什么传输方式、要不要 shell、有没有把密钥写死在 env 里、npx 有没有固定版本。至于这个 server 的代码里干了什么、它返回的工具描述有没有被投毒,配置扫描看不到。

深度分析是有条件的。 那条三角色对抗流水线要 API key,要把配置内容发出去,还要额外的时间。确定性引擎才是默认路径,模式匹配意味着它对新型手法和语义层面的问题天然滞后。

装它本身就是在扩大执行面。 这条得说得直白些。ECC 的 hooks/hooks.json 里配了一整排 PreToolUse 钩子,Bash、Write、Edit 之前都会去跑 node 脚本,另有几条 matcher 写成通配的钩子,对每一次工具调用做观测采集与配置保护。这类设计在功能上很有用,但它的形态恰恰是扫描器教你警惕的那种形态——往你机器里写文件、在每次工具调用前插入执行、把执行路径解析交给一段内联脚本。项目是 MIT 许可、代码公开,你可以自己看,但「可以看」不等于「你看过」。装任何一套 harness 增强件之前,先按它自己教的那套方法扫一遍它,是合理的做法。

权限收紧这件事,工具只能给你起点。 指南里给的那份 deny 基线(禁读 ~/.ssh/**~/.aws/****/.env*,禁掉 curl * | bashsshscpnc 这类外传命令)作者自己就标注了「这不是完整策略,是个还算扎实的底线」。真正要做的是按任务给权限:只需要读仓库跑测试的流程,就别让它读你的 home 目录。这套判断可以配合最小权限设计那篇一起看。

六、上手清单:会踩什么,怎么绕开

用 npx 跑扫描器,本身是一次不受控的包解析。 会踩是因为顺手——文档里 npx 的写法最短。但指南把未固定版本的 npx 列为供应链风险,扫描器也会把 MCP 配置里的 npx -y 报成 medium,你用同一种方式去跑安全工具,逻辑上不太站得住。怎么避:日常用全局安装的固定版本,需要一次性验证时在容器里跑。

在仓库根目录扫,会被示例淹没。 会踩是因为默认路径就是当前项目,而任何带文档的仓库里都有大量演示用的配置片段。怎么避:先用 --path 指到 .claude/ 把真实运行时配置扫干净,再扫仓库根,并且严格按运行时置信度分组读结果。

--fix 直接开跑。 会踩是因为它被描述成「只应用安全的修复」,听起来无害。但它动的是 settings.json 这类文件,改的是你的权限模型——把通配符收紧成有范围的写法,很可能顺手把某个你真的需要的路径关掉,然后你在下一次会话里对着莫名其妙的拒绝调半天。怎么避:先跑一次不带 --fix 的扫描看清单,确认工作区 git 干净,改完逐行看 diff,再跑一次确认分数变化。

把文档里的示例当漏洞去修。 会踩是因为分数被这些条目拉低,看着刺眼。但改文档换不来任何安全收益,还可能把一段本来在教人「别这么写」的反例改成了正例。怎么避:文档示例、模板目录、插件清单、项目本地可选设置这四类,明确归到低置信度那组,只登记不修。

为了找密钥,先把密钥发出去。 会踩是因为深度分析看起来更彻底,很多人第一次就想开满。但那条链路的输入正是你怀疑藏着密钥的那些文件。怎么避:顺序反过来——先跑确定性扫描,把硬编码密钥清干净、把已经暴露过的凭证轮换掉,再考虑要不要做深度分析。

扫完就当自己安全了。 会踩是因为一个 A 等级看着很有说服力。但它覆盖的是配置面的一个切片。怎么避:把扫描当成清单里的一项,而不是清单本身。指南末尾那份最低标准清单里,还有身份隔离、短时效凭证、容器隔离、默认拒绝出网、审批边界、日志、进程组级别的终止手段、记忆窄化——扫描器一条都替你做不了。

每次改完配置忘了重扫。 会踩是因为这类改动通常是顺手的:加个 MCP server、放宽一条权限、贴一个别人推荐的钩子。技能文件里列的激活时机很明确,改完 settings.json、CLAUDE.md 或 MCP 配置之后、提交配置改动之前、接手一个已有配置的新仓库时,都该扫。怎么避:把它挂进 pre-commit 或 CI,别靠记性。

收束

这条链路真正有价值的设计,不是它能查出多少条问题,而是它把「运行时活跃的发现」和「静态语料里的示例」分成了两组。安全工具最常见的失败方式不是漏报,是报得太多、太平均,导致人不再看——这个分组是对抗噪声的关键动作,你自己写检查脚本时也值得照搬。

接下来读什么:先读 the-security-guide.md,搞清楚威胁模型和最低标准清单,再回头看 skills/security-scan/SKILL.md 的严重度分档,你会发现每一档背后都对应指南里的一个具体攻击路径。想知道命令实际怎么编排,看 commands/security-scan.md 的 Review Checklist 和 Output Contract 两节。

一份三分钟的自检,不装任何工具也能做:打开你项目的 .claude/settings.json,看 allow 列表里有没有通配到底的条目、有没有 deny 列表;打开 CLAUDE.md,找有没有让 Agent 自动执行某些操作的句子;打开 MCP 配置,看每个 server 的传输方式、有没有写死的密钥、npx 有没有固定版本;最后翻一遍 hooks,看有没有把外部变量直接插进 shell 命令的地方,以及有没有 || true。这四步查出来的东西,往往就是扫描器会标红的那批。

本文属于 ECC 开源 Agent 套件专题(共 40 篇,从选择性安装一直拆到内部机制)。同一批还写了另一种取向的项目——不给你资产、只给你纪律的 superpowers 方法论专题

想系统学会用 AI?报名体系课或加入会员,照着学、照着用。