文章总结: 文章深入分析了2025年9月Shai-Hulud蠕虫事件后npm供应链攻击的新常态,揭示了攻击者采用蠕虫式传播、基础设施持久化和多阶段载荷等高级技术。以Bitwarden仿冒包为例详细解析了攻击链,包括双触发机制、多层混淆技术和全面凭据窃取手段。针对企业开发者提供了从紧急响应(阻断C2、密钥轮换)到长期防御(禁用脚本、私有注册表、SBOM生成)的八项具体应对策略,强调供应链安全已成为必须主动管理的系统性风险。 综合评分: 87 文章分类: 供应链安全,恶意软件,解决方案,安全运营,漏洞预警
npm 攻击新常态:威胁全景与生存指南
幻泉之洲
2026年4月28日 09:27 北京
在小说阅读器读本章
去阅读
2025年9月的Shai-Hulud蠕虫彻底改变了npm攻击的局面,自此,供应链攻击成为一种高风险的、系统性的威胁。本文将深度剖析最新的重大攻击事件(如针对Bitwarden的仿冒包),揭示攻击者的技术演进,包括蠕虫式传播、基础设施持久化和复杂的规避检测策略,并为企业开发者提供一套从立即响应到长期防御的行动指南。
一个时代的终结:从骚扰到灾难
2025年9月,npm生态系统的安全形势迎来了一个决定性的转折点。一个代号为“Shai-Hulud”的自传播蠕虫,自动化实现了恶意包的入侵和再分发。这不是一次孤立的入侵,它标志着npm“小打小闹”式攻击时代的终结,一个高风险的威胁新纪元已经到来。
从那之后,我们看到供应链被入侵的频率和技术深度都在急剧加速。攻击不再是零散的打字错误抢注,而是演变成多个威胁行为者有组织、有系统的战役,目标直指现代软件开发所依赖的信任基石。
整个游戏规则变了。
攻击的新基线
Shai-Hulud案例证明,npm注册表可以成为恶意软件分发的“力量倍增器”。在后续几个月的观察中,我们确认了攻击者战术、技术和过程(TTPs)的三个核心转变。
- 蠕虫式传播:现在的恶意负载优先窃取npm令牌和GitHub个人访问令牌。有了这些凭证,它们就能像2026年3月的Axios攻击那样,自动感染并重新发布合法包,实现指数级扩散。
- 基础设施级持久化:攻击者不再满足于偷点数据。他们开始嵌入持续集成/持续交付管道,以获得对企业环境长期、难以察觉的访问权限。他们不再只是“客人”,他们想成为“管家”。
- 多阶段载荷:模仿2025年9月的攻击模板,当前攻击经常部署处于休眠状态的“潜伏”依赖项。这些“卧底”只在特定环境条件下才被激活,以此逃避自动化扫描器的检测。
这些转变意味着什么?意味着防御者必须从“事件响应”的被动姿态,转向“主动威胁搜寻”的常态。一次普通的npm install,可能就是你整个CI/CD系统沦陷的开始。
解剖一次典型的“新常态”攻击
我们以2026年4月发现的@bitwarden/cli仿冒包为例(版本2026.4.0),它伪装成知名的Bitwarden密码管理器命令行工具。这个包是代号TeamPCP的团伙发起的更大规模供应链攻击的一部分。
攻击入口与引导
这个包的恶意性首先体现在package.json里。它设定了两条触发路径:常规的preinstall生命周期脚本,以及将恶意脚本bw_setup.js注册为bw命令。就算你在安装时用--ignore-scripts禁用了脚本,下次你或你的脚本一运行bw,恶意代码照样启动。这是一道双保险。
多层次的混淆与隐匿
恶意代码玩了很多花招来躲开分析。
- 字符串转盘:敏感字符串被切碎成十六进制索引,存到一个大数组里,分析时再动态还原。你想静态分析抓字符串?门都没有。
- 定制的ASCII洗牌密码:用12345作为种子,通过线性同余算法打乱一个128字符的ASCII表,域名、文件路径等关键信息被编码成一串数字索引。比如,攻击者的命令与控制(C2)域名
audit.checkmarx[.]cx,在代码里看起来就是一堆[0x42, 0x6e, 0x36...]的数字。 - 高度丑化的代码:整个约10MB的主载荷文件是一行没有格式的JavaScript,展开有28.5万行。所有变量函数名都变成了
_0x3865d8这种毫无意义的十六进制字符串。
说实话,这种级别的混淆,光靠人眼看,基本等于大海捞针。
全面收割:没有安全的角落
一旦激活,载荷就像一只贪婪的八爪鱼,向所有可能的凭据来源伸出触手。它分门别类地使用了不同的“供应商类”来执行任务。
- 文件系统供应商:按操作系统扫描敏感文件路径,比如
~/.npmrc、~/.ssh/id_*、.env、甚至AI工具Claude和Kiro的配置文件。 - Shell供应商:直接执行
gh auth token命令来窃取GitHub CLI的活跃令牌,并读取整个process.env环境块。 - CI/CD供应商:如果在GitHub Actions环境中运行,就直接解析运行器上下文,提取所有配置的机密信息。
- 云服务供应商:使用捆绑的AWS、Azure、GCP官方SDK,去查询这些云平台的参数存储、密钥保管库等服务,把能访问的密钥全读一遍。
这种针对性设计,让开发者工作站和构建环境里那些本该被严格保护的秘密,变得一览无余。
双重渗透与蠕虫传播
窃取到数据后,攻击者用两个渠道传出去:第一层通过HTTPS加密发送到C2服务器;第二层更狡猾,用偷来的GitHub令牌创建一个公开仓库,把加密后的数据存进去。这意味着就算C2域名被查封,数据依然能通过公共GitHub这个“死信投递箱”传到攻击者手里。
更可怕的是它的“蠕虫”能力。一旦它拿到一个有发布权限的npm令牌,就会自动执行一系列操作:
- 验证这个令牌能用来发布包。
- 枚举该用户/组织下所有可写的包。
- 下载每个包的最新版本。
- 篡改
package.json,清空旧脚本,插入"preinstall": "node setup.mjs",然后给小版本号打补丁(比如1.2.3变成1.2.4)。 - 将整个蠕虫载荷写入
setup.mjs。 - 用偷来的令牌发布新的恶意版本。
于是,任何一个安装了这个被感染包的开发者,他的环境又会被入侵,他有权发布的包又会被感染和重新发布。这种链式反应,就是软件供应链里的“僵尸病毒”。
用GitHub做备用通讯
这个攻击的另一个聪明之处在于它的C2恢复机制。如果主C2服务器连不上,恶意代码会去GitHub公共搜索API里,找包含特定关键词“beautifulcastle”的提交。它从一个预置的仓库的一个旧提交里,解析出Base64编码的新C2域名和RSA数字签名。验证签名后,代码就切换到新的域名上。
这意味着攻击者可以在任何时候,通过在任何公共GitHub仓库做一个新的签名提交,就完成整个C2基础设施的切换,根本不需要自己维护活跃的服务器。
如何生存下来?紧急与长期对策
如果你发现自己可能已经中招,请立即执行以下操作。
先说紧急应对措施:
- 立即阻断:在网络边界阻断文中提到的C2域名(如
audit.checkmarx[.]cx)和IP地址。 - 全面密钥轮换:把所有可能暴露的凭据都换了:npm令牌、GitHub PAT、三大云的密钥、SSH密钥、CI/CD里所有机密。别抱侥幸心理。
- 代码审计:检查你维护的npm包,看有没有未经授权的版本更新或者新的preinstall/postinstall钩子。
- GitHub大扫除:搜索全组织,找有无未经授权的仓库创建、奇怪的workflow文件(特别是叫
format-check.yml的)、以及format-results这个工件下载记录。 - 主机排查:在所有开发机和CI runner上,排查有没有异常的bun进程运行,以及到相关C2的出站连接。
光止血不够,还得改变生病的土壤。以下是对组织长期防御的建议,这八条每一条都值得写进你的安全基准里。
1. 强制执行“冷静期”
通过私有注册表或代理(比如Artifactory),设置一条策略:禁止安装过去24到72小时内发布的任何包版本。绝大多数恶意包都是在这个时间窗口内被识别并下架的。这个方法能帮你躲开绝大部分“新鲜出炉”的毒药。
2. 禁用生命周期脚本
很多攻击靠的就是preinstall/postinstall钩子来执行恶意代码。在你的全局或项目.npmrc里加一行:ignore-scripts=true。这能解决一大半基于脚本触发的攻击,但可能会影响某些需要构建原生模块的包。
3. 版本锁定与 ci 命令
严格使用package-lock.json,并且确保你的CI/CD管道使用npm ci而不是npm install。npm ci严格按照锁文件安装,不会在构建时给你来个依赖的“隐形更新”。
4. 私有注册表代理所有流量
绝不允许开发机或CI runner直接跟registry.npmjs.org对话。所有流量都必须经过一个可控的私有注册表。这样做不仅能做缓存、访问控制,也给了你一个审查和阻断的关口。
5. 使用作用域包,防止“依赖混淆”
攻击者常常在公共注册表发布与你内部库同名的包。解决方案是:永远使用作用域包,比如@mycompany/ourlib。然后配置你的私有注册表,让它只从内部解析这个作用域。
6. 验证软件来源
许多主流包现在提供“来源证明”,证明代码是在特定的GitHub/GitLab runner上构建的。使用像slsa-verifier这样的工具在构建时检查这些证明。多一层验身步骤,就少一分风险。
7. 严管CI/CD的出站网络
大多数npm相关的恶意软件,最终目的都是把偷到的.npmrc令牌或.ssh密钥发出去。给你的CI runner套上严格的外出网络策略,只允许它们连接到你的私有注册表和已知的部署目标。
8. 生成软件物料清单(SBOM)
为每个生产版本自动生成一份SBOM。这样,当有新的零日漏洞被公布时,你的安全团队可以立刻进行影响分析,几分钟内就知道自己是否受影响,而不是手忙脚乱好几天。
最后:这不是演习
Shai-Hulud事件之后的格局变化,证明高风险的供应链攻击不是暂时的峰值,而是一种新常态。在一个代码以前所未有速度被共享的生态里,一个被攻陷的依赖可能会像多米诺骨牌一样,引发全球性的连锁反应。
问题的核心,还是开发者社区对“信任”的过度使用。我们默认依赖的包是善意的,默认安装脚本是无害的,默认“一小块代码”不会掀起大风浪。但现在看来,这些默认假设都过于天真了。
指望注册表运营方或某个单一工具解决所有问题是不现实的。真正的防线,最终还在于每个团队、每个开发者对自己软件供应链的持续审视和验证。从每一次npm install开始,多问一个为什么。
这听起来有点累?没错。但比起处理一次全局性的安全事件,这点累真的不算什么。供应链正成为新的主要攻击目标,但这并不意味着它必须成为我们的主要弱点。
参考资料
[1] https://unit42.paloaltonetworks.com/monitoring-npm-supply-chain-attacks/
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:幻泉之洲 《npm 攻击新常态:威胁全景与生存指南》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。











评论