20 亿次周下载的包被劫持:9 月 npm 供应链攻击全回顾
chalk、debug 等多个流行 npm 包被钓鱼攻击拿下,超 20 亿次周下载受影响。本文梳理攻击过程、检测方法和防御建议。
攻击是怎么发生的
2025 年 9 月 8 日,npm 生态遭遇了有史以来最大规模的供应链攻击。攻击者通过钓鱼邮件假冒 npm 官方,以「9 月 10 日前必须更新 2FA」为借口,诱导多个知名包维护者登录钓鱼域名 npmjs.help。成功拿到账号后,攻击者在 chalk、debug、ansi-styles 等 18 个包中植入了恶意代码。
这些包的总周下载量超过 20 亿次,影响范围几乎覆盖了所有 Node.js 项目——只要你在项目里用过彩色的终端输出,或者用过调试打印,几乎肯定躺枪。
恶意代码会在用户安装或更新这些包时激活,专门针对安装了 MetaMask 浏览器插件的用户,通过流量拦截尝试盗取加密货币钱包私钥。
9 月中下旬:第二波更狠
你以为修完就完了?9 月 15 日,npm 生态又迎来第二波攻击——代号「Shai-Hulud」的自复制蠕虫。这次攻击者直接在恶意包内写入自传播代码,感染后会主动尝试感染项目中的其他依赖,自动化扩散能力远超普通供应链攻击。
新加坡网络安全局(CSA)随后发布紧急通报,警告这类自传播载荷可能影响整个 npm 生态。
如何检测自己是否中招
检查本地安装的恶意包版本:npm ls debug chalk ansi-styles supports-color
用安全工具全量扫描:npx audit-package --all
推荐用 Socket.dev 等第三方监控服务,能实时告警包行为异常(网络请求、文件写入等)。
如果发现使用了被污染的版本,立即删除 node_modules 和 package-lock.json,然后 npm install 重新安装干净版本,并检查团队成员是否有人中招了钓鱼邮件。
为什么 npm 包这么容易被拿下
npm 的发布机制长期缺乏强制安全门槛:默认只需邮箱密码,2FA 不是强制的;发布门槛极低,一个账号可以发布任意数量的包;没有包签名机制,无法验证包的发布者身份;依赖层级深,你信任的包可能间接依赖被污染的包。
这次攻击能成,核心原因是维护者的账号被钓鱼了,而不是 npm 平台本身有漏洞。所以个人账号安全才是第一道防线。
GitHub 公布的整改路线图
事件之后,GitHub 发布了 npm 供应链安全整改路线图,主要措施包括:
强制 2FA:未来将强制维护者开启双因素认证,尤其是高下载量包的作者
精细化 Token:Token 有效期限制为 7 天,缩小泄露后的影响范围
可信发布(Trusted Publishing):包发布时验证 CI/CD 环境身份,不再依赖长期有效的 npm 账号密码
包签名:计划引入加密签名,让用户能验证包的真实来源
开发者自保建议
所有 npm 账号强制开启 2FA,防止账号被钓鱼拿下。用 npm ci 替代 npm install,使用锁文件避免自动拉取最新版。定期 npm audit 及时发现已知漏洞。接入 Socket.dev 或 Snyk 监控实时检测包行为异常。最小化依赖,不用的包及时清理减少攻击面。
写在最后
npm 供应链攻击不是新鲜事,但这次影响范围(20 亿次周下载)和攻击手法(自复制蠕虫)都创了纪录。随着 AI 编程工具越来越普及,项目的依赖数量只多不少,供应链安全会变得越来越重要。
作为开发者,最实际的做法是把账号安全当成开发流程的一部分,不要觉得个人开发者就不会被攻击。攻击者可不管你是谁,看的是下载量。