安装 Agent 前,先核验版本与权限证据
文章建议为待安装的 Agent 建立绑定具体版本的核验档案,记录制品身份、凭据需求、数据流向、隔离方式、更新控制及卸载机制。根据证据完整程度,选择受限使用、隔离试点或阻止安装。
AI 深度解读
Agent 商店里的「已验证」、星标和成功案例,能帮你筛选产品,却不能证明装进工作区的具体版本会执行什么、能访问哪些数据,以及明天会不会悄悄增加权限。作者提出了一份「包护照」:安装前,把版本、权限、数据流、更新和退出机制与证据绑在一起,再决定放行、试点还是阻止。
这套方法值得程序员借鉴,因为 skill、MCP server、连接器都可能成为项目的执行入口。真正要审查的,是具体安装物和运行环境共同形成的权限边界。
商店验证过,为什么安装前还要再查
商店回答的是「哪个产品可能完成任务」,部署审查回答的是「这个版本能否进入我的环境」。两者需要的证据不同。
一个 Agent 可能是本地脚本,也可能是托管 API、导入自动化平台的工作流,或者安装后持续变化的远程内容。执行链里还可能接着模型提供商、工具服务器、身份服务和数据存储。只检查商品卡片,很难覆盖这些边界。
作者没有独立核实原商店宣称的用户指标、满意度、部署时间或业务成果。「已验证」也需要继续追问:检查了哪个版本、做了什么测试、何时检查、有什么遗漏?缺少这些信息,徽章无法支撑可复查的安装决定。
权限问题同样如此。原文引用了一位 OpenAI 开发者社区参与者的反馈:只需要读取的用户,可能因为角色分配方式而获得可以修改记录的连接器。这不能证明所有平台都存在同样问题,但提醒买方检查:权限能否按用户和任务收窄,还是只能整包授予?
商店审核可以减少筛选成本,不能替买方确认实际部署权限。
数据放在本地区域也不是安全证明。原文引用的研究使用了 2000–2022 年国家层面的面板数据,在其模型中没有发现数据本地化政策与若干网络事件结果存在统计显著关系。这个结论不能拿来评价某个 Agent,只能用来反驳「地域合适,所以安全」的简单推断。
包护照记录什么,才能形成安装决定
包护照是一份绑定具体版本的决策记录。作者要求覆盖十类信息:归属、安装物身份、能力、凭据、数据去向、隔离、变更审查、运维责任,以及停止和移除方式。
每项都应指向文件、设置、测试结果、合同条款或责任人。供应商口头承诺可以记录,但不能直接算作独立验证;没查清的地方写 unknown,不适用的地方说明原因。
原文示例把安装版本写成 2.4.1,回滚目标写成 2.3.8,检查日期是 2026-11-04,复审到期日是 2026-12-04,数据保留天数为 0。这些都是示例值。关键在于:批准对象应包含版本、权限、数据和期限,不能只有一个产品品牌。
作者把决定分成三类:
go:安装物明确,权限必要且受限,数据去向可接受,操作可观察,停止与恢复已经演练。pilot:不存在必须阻止的缺口,但证据或运维能力尚不完整,可以在专用环境中用合成数据验证,并设定期限、观察人、成功标准和终止条件。block:身份不明、版本无法固定、数据外发未知、必须使用宽泛凭据,或者更新不可审查、无人能够撤销和调查。
这些条件不能靠加权评分互相抵消。供应商口碑再好,也不能补上未知的安装物摘要;测试表现再好,也不能抵消无限权限的 token。
固定 commit 也有边界。它能固定源码,却固定不了远程模型、提示词、API、功能开关和数据保留政策。托管产品没有可供买方计算的包摘要时,应记录版本与发布证据的局限,再用分阶段环境和权限扩展前审批补足,不能编造摘要过检查。
Node 校验器能拦住漏填,安全边界仍要实测
原文提供了一个只用 Node.js 内置模块的校验器,要求 Node.js 20+。它检查护照是否完整,并对部分危险组合默认拒绝。
// passport-check.mjs:Node.js 20+;结构检查,不是安全扫描器
import { readFile } from 'node:fs/promises';
const file = process.argv[2];
if (!file) {
console.error('Usage: node passport-check.mjs passport.json');
process.exit(2);
}
const passport = JSON.parse(await readFile(file, 'utf8'));
const errors = [];
const need = (condition, message) => { if (!condition) errors.push(message); };
const pkg = passport.package ?? {};
const task = passport.task ?? {};
const flow = passport.dataFlow ?? {};
const controls = passport.controls ?? {};
const ops = passport.operations ?? {};
need((pkg.listingUrl ?? '').startsWith('https:') && (pkg.listingUrl ?? '').includes('://'), 'listingUrl must be HTTPS');
need(Boolean(pkg.publisher), 'publisher is missing');
need(Boolean(pkg.version), 'version is missing');
need(/^sha256:[a-f0-9]{64}$/i.test(pkg.artifactDigest ?? ''),
'artifactDigest must be a verified SHA-256 value');
need(Boolean(task.owner && task.purpose), 'task owner and purpose are required');
need(Array.isArray(passport.capabilities) && passport.capabilities.length > 0,
'capabilities must be an explicit non-empty list');
need(Array.isArray(flow.destinations) && flow.destinations.length > 0,
'data destinations must be explicit');
need(typeof controls.autoUpdate === 'boolean', 'autoUpdate must be explicitly true or false');
need(Boolean(controls.rollbackTarget), 'rollback target is missing');
need(controls.credentialRevocableByOwner === true,
'owner-controlled credential revocation is required');
need(Boolean(ops.businessOwner && ops.technicalOwner && ops.expiryDate),
'named owners and review expiry are required');
need(['go', 'pilot', 'block'].includes(ops.decision),
'decision must be go, pilot, or block');
if (controls.autoUpdate === true && ops.decision === 'go') {
errors.push('auto-update requires a separately documented staged review before go');
}
if (!controls.sandbox && (passport.capabilities ?? []).some(x => /write|delete|send|pay/i.test(x))) {
errors.push('write-capable package has no sandbox or compensating boundary');
}
if (errors.length) {
console.error('BLOCK: passport is incomplete');
for (const error of errors) console.error(`- ${error}`);
process.exit(1);
}
console.log(`STRUCTURE OK: ${ops.decision} review recorded for ${pkg.publisher} ${pkg.version}`);
要看清最后输出的 STRUCTURE OK:它只表示结构检查通过。SHA-256 正则只能检查 sha256: 后面有没有 64 位十六进制字符,不能证明摘要真实。原文 JSON 中的占位摘要会失败,必须换成实际不可变安装物的已验证摘要,不能拿商品页面的哈希代替。
实际验证还要进入运行环境。MCP server 要检查工具清单与描述;工作流要检查节点、凭据、触发器和目的地;本地 skill 要检查脚本、shell 命令、文件匹配和网络调用。工具叫 search,也可能读取敏感记录;叫 sync,也可能写入或删除。
随后测试拒绝路径:读取禁止文件、访问未批准端点、尝试写入、凭据撤销后继续执行,以及遇到检索文档里的恶意指令。测试目标不是证明提示词注入永远不会成功,而是确认即使模型受骗,执行层仍能拦住越权动作。
有业务后果的操作,授权也应放在模型之外。用户批准具体目标、金额或字段后,执行器还要在执行时重新检查授权与当前策略。一次允许使用 CRM,不能成为未来所有修改和导出的通行证。
我的判断
我认同作者把「是否准入」与「每次动作是否获准」分开。包护照负责安装和生命周期,执行器负责单次操作授权。它比依赖提示词里的「不要越权」更容易检查,也更容易追责。
但这是一套作者提出的买方协议,原文没有给出落地团队的前后对照数据,不能据此宣称它降低了多少事故。CISA 的材料是通用软件供应链指导,PwC 的讨论是咨询视角,都不是 Agent 商店认证。
示例校验器也只是起点。按能力名称匹配 write|delete|send|pay 会漏掉其他命名方式;sandbox: true 也不能证明隔离有效。护照里的布尔值最终需要平台配置和测试证据支撑。
相比完整企业审计,这份记录更轻;相比只看商店评分,它更贴近实际权限。只处理公开信息的只读工具可以简化审查,连接客户数据、发送消息或操作资金的 Agent 则需要更强控制。原文末尾在讨论停用与撤销时截断,因此不能替作者补上后续结论。
能拿来做什么
- 给项目安装 skill 或 MCP server 前,记录安装来源、不可变版本、脚本与工具清单、网络目的地和责任人,并明确允许它完成哪一个任务。
- 在 Node 工具链里接入护照结构检查,把缺失字段提前暴露;同时保留人工核验摘要、权限和测试证据的步骤。
- 连接工单或 CRM 前,先用专用凭据和合成数据测试越权、外发与撤销路径,确认失败会被执行层阻止,再决定是否扩大访问。
- 把新增工具、OAuth scopes 扩大、模型或端点变化纳入重新审查,并分别演练版本回退、停用计划任务和撤销凭据,确认各自能恢复到什么状态。