ARTICLE / 安全
版本号没变不代表代码没变:一次撤回重发版的开源组件安全复测
2026 年 10 月 15 日,NousResearch 的开源智能体框架 Hermes Agent 发布了 v0.22.2。Release note 写得很直白:v0.22.1 从错误的 commit 构建,带进了未发布的网关代码,还导致 Microsoft Store 版卡在"Connecting";0.22.2 才是 0.22.1 本来想发的版本。
这种"同小版本重新打包再发一次"的操作在开源世界里不少见——构建错了、发布流程卡了、tag 打歪了,都可能触发。它给下游安全工程师出的题却是同一道:版本号没变、变更日志看起来只是修复,你要不要重新做安全评估?
我们把这个场景的复测方法整理成文。结论先说:撤回重发版的安全面必须逐项复跑 PoC,不能 diff 版本号了事——因为重新打包的过程本身可能引入差异,而变更日志不会告诉你所有差异。
为什么"重发"值得单独警惕
多数团队的升级流程是按版本号驱动的:语义化版本没动,就当作同一版本处理。撤回重发打破了这个假设——同一个 tag 下线再上线,构建产物变了,但下游的版本比对工具看不出任何异常。
更微妙的是信任传导:重发版的变更日志通常写"修复 X",下游审计者扫一眼日志没看到安全相关字样,就跳过了复测。但构建系统的差异(依赖快照不同、打包脚本版本不同、缓存命中不同)完全可能让"功能等价"的两个包在安全行为上不一致。
这不是理论风险。PyPI 与 npm 生态的供应链事故里,“同名不同物”(依赖混淆、构建缓存投毒、tag 覆盖)都是已被反复利用的模式;OWASP 供应链风险清单也把"构建产物不可重现"列为一级风险。撤回重发正是"不可重现"的高发场景。
复测方法:三条铁律
针对这类版本,我们总结出三条复测铁律,适用于任何带安全审计义务的下游团队。
铁律一:不 diff 版本号,diff 构建产物。 版本号相同不代表产物相同。先对两次发布的分发包做哈希比对(wheel 的 sha256、npm 包的 integrity、Docker 镜像的 digest)——哈希不同就按"新版本"对待,走完整审计流程;哈希相同(真·重传)才能跳过。分发包哈希可以从官方源取:PyPI 的 JSON API(pypi.org/pypi/<pkg>/<ver>/json)带每个文件的 digests 字段,npm 有 integrity 字段,容器镜像有 digest。
铁律二:存量 PoC 逐个复跑,一个不漏。 此前版本积累的漏洞验证脚本(PoC)是最宝贵的回归资产。重发版上全部复跑一遍,成本是一次 CI 的时间,漏掉的成本是一次安全事件。复跑要带时间戳存档证据(命令、输出、环境),这既是内部审计要求,也是后续 CVE 投递的必备材料。
铁律三:把发现整理成 MITRE-ready 投递包。 如果复测发现漏洞仍在,按 MITRE CVE 投递标准整理材料:每个漏洞一份独立报告(受影响产品与版本、漏洞类型 CWE 归类、攻击前提、影响、可复现细节、修复建议),加一份覆盖全部发现的综合报告。材料齐格式的投递包能显著缩短 CVE 编号分配周期——MITRE 对信息不全的投递会来回追问数周。
实战检验:v0.22.2 上的三连复测
以上方法在 Hermes Agent v0.22.2 上做了一次实战检验(在自有环境、授权范围内)。
背景:v0.22.0 发布后,外部审计者报告了三个问题——SSRF(内部回调 URL 可被外部输入指向内网端点)、权限决策的 deny-wins 缺失(deny 与 allow 冲突时 deny 未优先)、代码执行类工具的授权路径可绕过。三者当时都未修。v0.22.1 被撤回,v0.22.2 作为重发版上线。
按铁律一,v0.22.2 是新构建(release note 明说从不同 commit 构建),按新版本对待。按铁律二,三个 PoC 在 v0.22.2 的干净 worktree 里全部复跑。
结果:三个 PoC 全部复现成功,撤回重发版没有修复其中任何一个。 这符合预期——重发版的目的是修正发布内容(去掉误入的网关代码),不是修安全面——但它验证了方法的必要性:如果有人假设"既然重新发了,应该顺手修了",就会在没有证据的情况下放行。
按铁律三,三份英文 MITRE-ready CVE 报告(PENDING-SUBMISSION 状态)与中文综合报告、测试记录已按标准结构归档待投递。
复现环境与取证细节
两条实操经验值得单独说。
用浅取 + worktree 隔离复现。 审计场景不需要完整 git 历史:git fetch <upstream> tag <版本> --depth 1 拿到 tag 快照,git worktree add 建独立目录,避免污染日常工作区。某些项目的深度获取脚本(如 prepare.sh 全量拉取)在大仓库上会挂死,浅取能绕开。
证据必须带时间戳落盘。 CVE 投递要求可复现细节,“我跑过"不算证据。每个 PoC 的输出按时间戳目录归档(Evidence/poc/<时间戳>/),报告里引用的每条结论都能指回具体文件。这也是内部复核的基础——三个月后有人质疑结论时,你能拿出当时的原始输出。
给下游团队的清单
把上面的内容压成一张可执行的清单,升级任何开源组件时过一遍:
- 升级前:比对当前版本与新版本的构建产物哈希(不只是版本号)。撤回重发版、tag 被移动过的版本,一律按新版本处理。
- 升级中:存量 PoC 全量复跑;没有 PoC 库的团队,从这次的三个问题类型起步(SSRF 类、权限决策类、授权绕过类是智能体框架的高发区)。
- 升级后:发现未修漏洞,按 MITRE 格式整理投递包,带时间戳证据。
- 流程固化:把"哈希比对 + PoC 回归"写进升级 SOP,不依赖个人记忆。
版本号是发布者的承诺,哈希才是构建产物的事实。安全复测盯住后者,才不会被"撤回重发"这类操作放出假信号。
本文面向授权安全研究与防御建设,未经授权对任何系统实施文中技术属违法行为。复测均在自有环境、授权范围内完成;涉及的漏洞细节未超出已公开披露范围。版本事实来源:github.com/NousResearch/hermes-agent releases v0.22.2(2026-10-15 核验)。