扫描的是一个文件,解压却是另一个:adm-zip 重名条目的检查使用分离
一、背景与时间线
官方公告确认:adm-zip的名称查找表保留最后一个同名条目,而同步解压在默认覆盖策略下可写入第一个同名条目。先用getEntry()检查再整体解压的应用可能检查与使用不同内容。受影响版本<=0.6.0,修复为0.6.1。项目9月11日披露,GitHub已审核库9月29日收录;当前公告没有已知CVE,本文不虚构编号。
以上事实依据项目安全公告。这里的披露或数据库收录日期不是攻击发生时间。本次核验的一手来源没有确认在野利用,本文不据此断言不存在攻击。
二、影响范围与版本边界
| 项目 | 核验结果 |
|---|---|
| 公告标识 | GHSA-p634-w6r4-rjp2 |
| 项目公告日期 | 2026-09-11 |
| 受影响版本 | <=0.6.0 |
| 修复版本 | 0.6.1 |
| 事件性质 | 漏洞披露或近期数据库收录,非已确认攻击事件 |
版本信息应结合实际运行环境判断。依赖清单命中仅是第一步,还需要确认调用路径、配置和不可信输入能否到达相应逻辑。发行商回补补丁的情况,应核对其安全公告和构建证据,不能只按上游版本字符串做最终判断。
三、技术原理与工程分析
同一个压缩包可以被两种数据结构表达:列表保留顺序和重复项,字典把名称映射到一个值。如果从列表转换到字典时发生覆盖,再回到列表完成写入,名称已经不足以唯一标识内容。
工程分析:这不是需要线程竞争才能出现的传统竞态。即便完全串行地先扫描后解压,只要两步使用不同的选择规则,校验对象就会漂移。把扫描过程放进事务,也无法自动修复这种解释冲突。
建议在接受不可信归档时建立唯一条目清单,拒绝重名及目标文件系统上会发生碰撞的名称;验证和提取使用同一条目对象,必要时记录内容摘要。大小写、路径分隔符和Unicode规则应按目标平台制定,不能把一种平台的归一化方式无条件推广到所有平台。升级依赖与归档准入策略需要同时执行。
四、防御性安全示例
以下Python 3示例只演示安全不变量,不连接网络、不执行外部程序、不生成真实利用载荷,也不是厂商补丁的逐行复现。运行后应输出检查通过。
entries=[('config.txt',b'FIRST'),('config.txt',b'SECOND')]lookup=dict(entries)written={}forname,contentinentries:written.setdefault(name,content)assertlookup['config.txt']!=written['config.txt']defunique_entries(items):seen=set()result=[]forname,contentinitems:ifnameinseen:raiseValueError('duplicate name')seen.add(name)result.append((name,content))returnresulttry:unique_entries(entries)exceptValueError:passelse:raiseAssertionError('duplicates must be rejected')assertunique_entries([('a.txt',b'OK')])print('archive-policy checks passed')模型测试通过只证明这些固定输入满足预期,不能证明生产部署已经修复。实际回归还需要在目标版本、真实适配层或调用封装中重复验证同一不变量。测试用例应同时覆盖正常输入和拒绝路径,否则“全部拒绝”的错误实现也可能被误当成安全修复。
五、研发与安全团队行动清单
P0:升级adm-zip到0.6.1;检查上传导入、插件安装、配置恢复和制品扫描链路中的“按名检查后整体解压”模式。临时措施是在完整条目列表层拒绝重复名称,而非仅检查字典键。
P1:为不同覆盖模式分别编写回归用例;测试无重复、重复、大小写碰撞和目录文件冲突。提取到隔离目录,在完整验证通过前不交给业务加载器使用。
P2:对扫描报告增加制品摘要和已验条目摘要,避免用文件名作为唯一证据。历史排查优先检查归档清单与落盘摘要差异;发现重复项不等于已经执行恶意代码,后续影响仍取决于应用如何消费内容。
如何形成可复核的修复证据
研发负责提交调用点、配置差异和回归结果;平台团队负责证明新构建已部署到实际实例;安全团队复核前提是否消除,并保留未覆盖环境的清单。完成条件应落在运行中的版本与行为,而非工单状态或补丁合并时间。
建议对每个服务记录:组件实际版本、受影响功能是否启用、输入来源、修复负责人、部署批次及失败回滚方案。无需搜集完整敏感输入;用脱敏样本和配置摘要通常更适合审计。对于无法及时升级的实例,临时措施必须指定复核日期,避免长期漂移为默认设计。
六、总结
这项问题提醒我们:安全约束必须与最终执行语义一致。识别依赖版本、定位真实调用链、验证负向行为、确认部署完成,缺少任何一步都可能让修复停留在纸面。本文的工程建议用于补充系统设计,不应被误读为厂商已确认的额外攻击链。