原文:Your Agent Risk Isn’t in One Plugin. It’s in the Composition. · Vinod Kone · 2026-06-23 · OpenACA
传统软件安全分析以「包」为单位——有 CVE 就修包版本,锁定文件检查通过就认为安全。但在 AI Agent 系统里,这种做法的盲区正在暴露。
一个典型的例子
有个叫 imessage 的 Claude 插件,功能很简单:让 Agent 读取和发送 iMessage。它可以从商店一键安装,做的事情跟你预期完全一致。拆开来看,它由三部分组成:
- 一个本地 MCP 服务器:读取
~/Library/Messages/chat.db(你的完整消息历史),需要 Full Disk Access 权限,通过 AppleScript 代你发送消息 - 一对 skills(
configure和access):持有 Read、Write 和受限 Shell 权限,能修改谁可以控制 Agent 的访问策略 - 91 个 npm 包:底层的 Web 服务依赖
单独看每一部分都没问题。MCP 服务器做它该做的事,skills 声明了需要的权限,npm 包只是普通依赖。用 SCA 扫描只会得到一份整洁的报告:几个 hono 和 path-to-regexp 的中等告警,修完版本后报告转绿。
但你几乎没看到真正的风险。因为风险从来不在任何一个包里——风险在组合方式里。
SCA 看到的是什么,看不到的是什么
软件成分分析(SCA)只回答一个问题:这个依赖树里是否存在已知漏洞的版本?
对 imessage 插件,答案是「有,少数几个」。这就是它所能说的一切。
| 视角 | 它看到的内容 |
|---|---|
| 传统 SCA | path-to-regexp 在 bun.lock 中发现已知漏洞 |
| 组合视角 | 这个包属于一个 Claude 插件,跑着本地 MCP 服务器,能读你的消息历史、代你发消息、并被可改写访问策略的 skills 支配 |
第一行是对的。但决定你是否该装这个东西的是第二行。SCA 产生不了第二行,因为锁定文件不知道自己是 Agent 的一部分。
运行时监控也看不到
另一个常见反应是「在运行时抓」。端点监控和行为分析能捕获运行中的异常行为,但它们只能看到进程在执行时所做的动作,无法告诉你:在你安装和审查时,这个插件的组合方式已经让那些危险动作变得可达。
SCA 看到包,运行时监控看到行为。两者都看不到 Agent 的组合方式——插件 + skill + MCP 服务器 + hook + 权限 + 安装路径组合成的那个整体。
扫描结果:124 个漏洞只来自 4 个插件
OpenACA 用他们的组合扫描器检查了官方 Claude 插件市场——62 个清单文件、530 个组件:38 个插件、27 个 skills、26 条 commands、21 个 agents、16 个 MCP 服务器、8 个 hooks,以及底层的 394 个包。
结果发现了 124 条已知漏洞告警。这不稀奇——npm 依赖的版本总落后于上游修复,这是公开的、普通的、不是谁的 0-day。
有意思的是这一点:全部 124 条告警只来自 4 个插件——discord、telegram、fakechat 和 imessage。四个消息通道插件。
漏洞分布与插件的安全敏感性有精确的因果正相关:漏洞代码和敏感能力正好在同一个组件里——而这正是按包逐项扫描无法表达的关系,因为它从来不知道那些包属于一个能读消息的 Agent。
Agent 组合关系图
OpenACA 提出的解决方案是换一个分析单位。Agent 栈不是扁平的依赖列表——它是一张图:
插件 ──→ skills (声明权限)
├──→ MCP 服务器 (声明能力)
├──→ hooks
└──→ 底层包 (有 CVE)
插件包含 skills、MCP 服务器和 hooks。它们声明能力和权限,引入依赖包。图中既有节点维度的信息(包版本、skill 允许的工具、MCP 传输协议),也有边上的信息——比如「不可信输入」和「私有数据读取」在同一个上下文里。
这张图不是手绘的:组合框架和告警归属直接从扫描得出,能力标签(每个组件能读什么、发什么、改什么)来自读取插件源码。
结论很直接:在 Agent 系统中,安全对象不再是包。而是包 + 插件 + skill + MCP 服务器 + hook + 权限 + 安装路径 + 运行时上下文的组合体。 扁平的 SBOM 列出盒子,但无法告诉你红色盒子(你的扫描器能看到的一切)和不可信输入源、私有数据读取器、出站外发端坐落在同一个上下文里。
除此以外,OpenACA 还在市场上发现了 10 个 MCP 服务器通过可变引用启动(如 npx ...@latest、未固定版本的 uvx git ref、无摘要的 Docker tag),以及 7 个 skills 声明了可执行工具权限。单独看每一条都是脚注,但在图上,「可变启动器 + 可执行能力 + 同一上下文的不可信输入」是一句需要认真读的句子。
OpenACA 能做什么,不能做什么
OpenACA 是一个开源项目,当前可以:
- 盘点完整的 Agent 栈——插件、skills、MCP 服务器、hooks、agents、commands 及底层包
- 将每个包告警归属到引入它的 Agent 组件——这就是为什么能知道 124 个告警只在 4 个插件里
- 标记姿态问题——可变安装、可执行 skill 能力
- 输出 Agent BOM(CycloneDX 格式)——组合关系图,可导出
下一步是图推导的暴露面分析:因为组合关系才触发的规则——「这个上下文同时有不可信输入、私有数据读取和出站外发;需要审查」——以及按是否存在可行的影响路径来给发现排序。
OpenACA 还不能推导暴露路径。盘点、归属和图是让暴露路径分析成为可能的基础,这正是他们在构建的方向。
这不是「我们今天就能检测 Agent 漏洞」的承诺,而是「我们让 Agent 的组合方式变得可见,这是后续一切的前置条件」。
对你的启发
如果你在使用或部署 AI Agent 工具(Claude Code、Codex 等),以下两个问题是值得问的:
- 你的 Agent 栈的组件组合图是什么样的? 不是依赖树,而是哪些插件、skills、MCP 服务器、hooks 组合在一起,它们之间有什么数据流和权限关系?
- 安装或审查一个 Agent 插件时,你有没有看过它的「组合暴露面」? 即这个插件是否在一个上下文里同时引入了不可信输入、敏感数据读取和外发能力?
OpenACA 提供了一个 30 秒的验证方法:
uvx --from openaca openaca scan
先用传统 SCA 扫描你的 Agent 插件仓库,然后问它一个问题:能不能告诉你,哪个有漏洞的依赖是通过一个能外发本地文件的 Claude skill、lifecycle hook 或 MCP 服务器可达的? 如果不能,那你没看到你的 Agent——你只看到了它的锁定文件。
项目地址:https://github.com/openaca/openaca 原文链接:https://openaca.dev/blog/your-agent-risk-is-in-the-composition/
本文基于原文内容编写,未实际运行 OpenACA 工具。分析框架和扫描数据来自原文公开描述。
文档信息
- 本文作者:zhupite
- 本文链接:https://zhupite.com/sec/agent-composition-risk.html
- 版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)