上一篇我聊了 Agent 身份认证这件事发完之后有读者跟我说“原来 Agent 还能有身份证涨知识了。”我回去又琢磨了一下发现一个问题就算给 Agent 发了身份证事情也没完。之前聊企业不敢让 AI Agent 独自干活第一道坎是 Agent 身份问题。如果系统不知道「谁在操作」后面的授权、审计和追责都没有明确主体。我当时觉得先把身份搞定了其他问题慢慢来。但仔细一想发现有个更隐蔽的口子还没堵上。因为 Agent 真正执行任务时不是只靠模型自己回答而是会调用各种工具和能力查合同、读发票、调 CRM、发通知、创建审批、调用内部 API……这些能力在很多 Agent 系统里被称为Skill。然后我就意识到就算 Agent 本身有了身份证它调用的 Skill 可能还在裸奔。一、Agent 调工具的真实风险先看三个场景。场景 1工具包被替换某个合同查询 Skill 经过审核后正常上线Agent 被配置为允许调用它。后来有人把 Skill 包里的某个文件替换了加入了额外的接口调用。Agent 仍然在调用同一个 Skill但行为已经变了。白名单没有拒绝它因为 Skill 名称没变、版本号没变、白名单配置也没变。场景 2依赖污染Skill 引入了一个第三方依赖包该依赖的新版本被注入了恶意代码。Skill 本身的代码没问题但它依赖的东西有问题。场景 3权限声明漂移Skill 最初声明只读合同数据后续版本加入了写入客户信息的能力但权限配置里的 allowlist 仍然显示它只读。系统没有拦截因为 allowlist 是按 Skill 名称配的不是按实际内容。这些问题的共同点是Agent 的身份没变但它手里的工具变了。如果企业只管「哪个 Agent 可以调用哪个 Skill」但不管「这个 Skill 还是不是当初审核过的那一份」风险就会从 Agent 身份层转移到工具层。二、Skill 和普通 Tool / 插件有什么区别很多人会问这跟 MCP 工具的 allowlist 有什么区别跟浏览器插件有什么区别区别主要在分发方式和信任模型。浏览器插件常见 MCP ToolSkill分发方式插件商店审核上架开发者本地注册或服务端配置Skill 包上传到平台信任来源商店审核 浏览器机制本地环境、服务配置和宿主平台平台扫描 签名 上架记录篡改检测浏览器/商店机制取决于具体实现文件摘要 签名验签运行时校验浏览器强制执行取决于宿主平台安装、加载或关键调用前可验签我这里说的 Skill不只是一个函数描述或一个接口地址而是一个可分发的能力包——里面有SKILL.md、脚本、依赖、参考资料和配置文件。Agent 调用它时拿到的不只是一个工具名而是一整套可以执行业务动作的能力。所以 Skill 的核心问题不是能不能被调用而是它作为一个能力包被上传、扫描、签名、上架、使用之后内容还能不能被验证三、一个可信 Skill 应该经历什么流程我一开始想的流程特别简单上传、扫描、签名、上架。后来研究了几版实现才意识到这不是一个上架流程的问题而是一个信任传递的问题。┌──────────────────────────────────────────┐ │ 1. 上传 │ │ 产出原始 Skill 包文件zip │ └──────────────────┬───────────────────────┘ ▼ ┌──────────────────────────────────────────┐ │ 2. 扫描 │ │ 产出扫描报告 │ │ 说明用户可通过 scanId 查看扫描详情 │ └──────────────────┬───────────────────────┘ ▼ ┌──────────────────────────────────────────┐ │ 3. 签名 │ │ 产出文件清单MF 数字签名P7S │ │ 说明签名结果封装在 zip 包的 META-INF │ │ 目录下 │ └──────────────────┬───────────────────────┘ ▼ ┌──────────────────────────────────────────┐ │ 4. 上架 │ │ 产出上架记录 │ │ 说明记录签名时间、状态等 │ └──────────────────┬───────────────────────┘ ▼ ┌──────────────────────────────────────────┐ │ 5. 使用 │ │ 产出Agent 调用结果 │ │ 说明安装、加载或关键调用前可执行验签 │ └──────────────────────────────────────────┘拆开来看每一步都有自己的信任锚上传锚定的是原始文件扫描锚定的是安全基线回答这份 Skill 的风险水位如何签名锚定的是内容完整性回答文件有没有被改过上架锚定的是发布状态相当于上岗许可证使用锚定的是运行时状态确认当前调用的还是当初通过审核的那份文件这里面最容易被忽视的是签名和验签。很多系统做到 allowlist 就停了但 allowlist 只能说明这个名字被允许不能说明这个包没被改过。四、签名到底在签什么以一个已经签名的 VeriAgent Skill 包为例最终 zip 里面会多出两个文件skill-package.zip ├── SKILL.md ← Skill 定义文件 ├── scripts/ ← 业务代码 ├── references/ ← 参考资料 └── META-INF/ ├── SKILL_VERIFY.MF ← 文件摘要 扫描记录 ID └── SKILL_VERIFY.P7S ← 对 MF 的数字签名SKILL_VERIFY.MF可以理解成这份 Skill 包的文件清单。它会记录每个业务文件的摘要以及这次扫描对应的Scan-Id。一个简化后的内容大概长这样Manifest-Version: 1.0 Created-By: VeriAgent Signing Engine 1.0 Scan-Id: scan-task-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx Sign-Algorithm: SHA-256 Name: scripts/handler.js SHA-256-Digest: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx Name: SKILL.md SHA-256-Digest: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx这里有两个关键点每个文件都有自己的 SHA-256 摘要。文件内容只要变一个字符摘要就会变。MF 本身会再被生成一份数字签名也就是SKILL_VERIFY.P7S。这样别人不能悄悄改 MF 里的摘要。所以签名真正解决的不是这个 Skill 永远安全而是这份 Skill 包当前的内容和当初签名时记录的内容是否一致。五、怎么验签总不能每次都手动解压吧如果每次都让安全同学手动解压、看 MF、算哈希、比对文件肯定不现实。所以更合理的方式是把验签也做成一个 Skill。比如现在 VeriAgent 里就有一个专门的验签 Skill它做的事情可以概括成两步先验证 MF检查META-INF/SKILL_VERIFY.MF和META-INF/SKILL_VERIFY.P7S是否存在并验证 P7S 能否证明 MF 没被改过。再验证文件MF 验证通过后逐个计算 zip 内业务文件的 SHA-256 摘要和 MF 里的记录做对比。最终它不会只返回一句通过或失败而是返回结构化结果verified: true manifestSignatureVerified: true manifestSignatureMessage: P7S 已验证 MF 未被篡改 totalFiles: 7 matchedFiles: 7 mismatchedFiles: [] missingFiles: [] extraFiles: [] metadata.scanId: scan-task-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx metadata.hashType: SHA-256这样一来系统至少能分清几类问题结果含义manifestSignatureVerified: falseMF 本身没有通过 P7S 验证文件清单可能被改过manifestSignatureVerified: true但verified: falseMF 没问题但业务文件和清单不一致verified: true当前包符合这套验签规则内容和签名时一致这就把我相信这个 Skill 没问题变成了我可以验证它是否还是那份 Skill。当然验签也不一定要在每一次普通调用前都完整执行一遍。更实际的做法是在上传、签名、上架、安装、加载或关键调用前强制验签运行中再结合缓存、包摘要和文件监控来降低成本。VeriAgent 目前已经把验签做成了一个可用的 Skill感兴趣的同学可以到 官网 看看完整流程。六、安全扫描和签名不是一回事这里有一个容易混淆的点安全扫描和 Skill 签名解决的是不同问题。安全扫描Skill 签名回答的问题这个 Skill 包有没有明显风险这个 Skill 包是不是经过认证的版本检查什么高危依赖、异常文件、不合规内容文件内容完整性、签名有效性产物扫描报告、风险等级、scanIdMF 文件、P7S 签名、验签结果性质风险识别完整性验证扫描像体检签名像封条。体检能发现当时有没有明显问题封条能证明后来有没有被人拆过。两者都重要但谁也不能替代谁。所以签名不等于证明 Skill 永远安全。更准确地说扫描负责识别风险这个包有没有依赖漏洞、异常文件、不合规内容签名和验签负责保证内容完整性可验证包有没有被改过还是不是当初签名的那个版本平台准入负责做决策扫描是否通过、签名是否有效、当前状态是否允许上架和调用七、这套机制解决什么不解决什么为了避免把可信讲得太玄我觉得需要把边界说清楚。它能解决的是Skill 来源和版本是否可管理Skill 包内容是否被替换签名后的文件是否被改动当前调用的 Skill 是否仍然匹配签名时的文件清单扫描记录是否可以通过scanId追溯它暂时不能单独解决的是Skill 运行时是否一定不会做坏事第三方依赖未来是否会出现新漏洞Agent 是否会在合法工具里做出错误决策所以它不是终点而是 Agent 进入生产系统前的一层基础设施。先让工具包能被扫描、签名、验签后面才谈得上更细的动态权限、运行时熔断和行为审计。八、回到 Agent 落地身份、工具、审计三层当企业评估一个 Agent 是否可以进入生产系统时真正要看的是三层层问题能力身份层这个 Agent 是谁Agent 数字身份工具层它调用的 Skill 是否可信安全扫描 文件签名 验签 Skill审计层它做了什么行为日志 调用记录身份层解决「谁在操作」。工具层解决「它调用的能力是否可信」。审计层解决「事后能不能追溯」。如果只有 Agent 身份没有可信 Skill 准入那么系统只能知道谁在调用但不知道它手里的工具是否被换过。如果只有工具准入没有后续审计那么系统能证明工具没被改却仍然很难解释它到底做了什么。所以这是一个顺序问题先让 Agent 成为可识别的主体再让它调用的 Skill 成为可验证的能力最后才能把关键调用沉淀成可追溯的证据。