1300个npm包被投毒,月下载20亿次:ChainDrop供应链攻击深度拆解
2026/8/13 21:11:07 网站建设 项目流程

📦 1300个npm包被投毒,月下载20亿次:ChainDrop供应链攻击深度拆解

紫禁玄科 | 2026年08月10日 | 阅读约10分钟

#供应链安全 #npm投毒 #ChainDrop #开发安全


📌 导读:就在昨天,1300多个npm包被植入恶意代码,月下载量20亿次。攻击者不仅能偷你的凭证,还用你的账号继续传播。更离谱的是,有人专门蹲点抢注AI"幻觉"出来的包名,等着开发者安装。这篇文章讲清楚了供应链攻击为什么防不住,以及你能做的三件事。

图1:供应链攻击概念图

一、发生了什么?ChainDrop攻击事件回顾

2026年8月4日,安全公司Aikido发现了一个名为ChainDrop的自传播蠕虫正在npm仓库中大规模扩散。截至发稿,已有超过1300个npm包被感染,涉及1381个恶意版本,这些包的月下载量合计超过20亿次

受影响的包包括开发者耳熟能详的:keyvflat-cachecache-managerfile-entry-cache等缓存工具,以及来自Deliveroo、Picsart、Qlik、ServiceTitan等知名企业的关联包。

⚠️关键数字:1300+被感染包 | 1381个恶意版本 | 20亿月下载量 | 4小时内从444包扩散到1300+包

二、攻击者视角:ChainDrop是怎么做到的?

⚠️ 以下内容仅供安全研究和防御学习,请勿用于非法用途

图2:ChainDrop攻击链路图

Step 1:初始入侵——窃取维护者凭证

作为攻击者,我会首先瞄准npm热门包的维护者。通过钓鱼邮件、凭证填充、或从暗网购买泄露的GitHub令牌,获取维护者的npm发布权限。这次攻击的突破口就是keyv维护者的GitHub账号。

Step 2:植入恶意代码

拿到权限后,我会在包中植入两个文件:setup.mjs(恶意加载器)和Math_Symbol.js(信息窃取器)。关键一步是在package.json中添加:

{ "scripts": { "preinstall": "node setup.mjs" // ← 这行是关键! } }

这意味着只要开发者执行npm install,恶意代码就会在安装完成前自动执行。而且因为是通过合法的GitHub Actions工作流发布的,这些恶意版本还带有有效的来源证明(provenance),看起来完全合法。

Step 3:窃取凭证——比你想象的更贪婪

图3:凭证窃取流程

恶意脚本会搜索并窃取以下凭证:

1.npm令牌(npm_开头的token)

2.GitHub令牌(ghp_、gho_、ghs_开头)

3.AWS凭证(Access Key + Secret Key)

4.Kubernetes Secret

5.HashiCorp Vault令牌

6.数据库密码、SSH密钥、Stripe/Slack/Azure/GCP凭证

7.GitHub Actions运行时Secret

更可怕的是,每个token在窃取前都会先到registry.npmjs.org/-/whoami验证有效性。偷到的凭证经过AES-256-GCM加密后,发送到攻击者控制的npm-cache.com域名,备用通道是创建公开GitHub仓库提交。

Step 4:自传播——用你的账号继续投毒

这是ChainDrop最可怕的地方。拿到你的npm令牌后,它会:

1. 枚举你名下所有可发布的npm包

2. 下载最新版本的tarball

3. 注入恶意代码

4. 递增patch版本号

5. 重新发布到npm

就这样,你的包变成了攻击者的武器,继续感染你的用户。这是一个典型的蠕虫传播模式:一个受害者变成多个,指数级扩散。

Step 5:AI幻觉攻击——蹲点抢注包名

图4:AI幻觉包名抢注攻击

更离谱的是,攻击者还会利用AI的"幻觉"(Hallucination)来传播恶意包。当开发者让AI推荐npm包时,AI可能会"编造"一个不存在的包名。攻击者就蹲守在npm仓库,一旦发现AI频繁推荐某个未注册的包名,就抢先注册并植入恶意代码。

这意味着:你问AI"用什么包好",AI给你的建议可能是陷阱。

三、真实案例:WannaCry与NotPetya的前车之鉴

图5:开发者工作站面临的安全威胁

供应链攻击并不是新鲜事。回顾历史:

📅 2017年 WannaCry:利用NSA泄露的EternalBlue漏洞,感染20万台电脑,损失40-80亿美元。NHS医院系统瘫痪,手术被迫取消。

📅 2017年 NotPetya:通过乌克兰会计软件MeDoc更新投毒,造成100亿美元损失。Maersk航运被迫重装4.5万台服务器。

📅 2020年 SolarWinds:攻击者入侵SolarWinds Orion更新服务器,1.8万家企业被感染,包括美国财政部、国土安全部。

📅 2021年 ua-parser-js:流行npm包被劫持,周下载量800万次,植入加密货币挖矿和密码窃取。

📅 2026年 ChainDrop:1300+包被感染,月下载20亿次,自传播蠕虫,AI幻觉包名抢注。

四、防御方案:你能做的三件事

第1件事:锁定依赖版本

1.使用lockfile:确保package-lock.json提交到Git,锁定每个依赖的精确版本

2.禁用preinstall脚本:npm install --ignore-scripts 或在.npmrc中设置 ignore-scripts=true

3.使用npm audit:每次安装前运行npm audit检查已知漏洞

4.定期审查依赖:用npm outdated检查过期包,删除不用的依赖

第2件事:隔离构建环境

1.CI/CD环境最小权限:不要在构建环境中存储长期凭证

2.使用OIDC短期令牌:替代长期npm/GitHub token

3.网络隔离:构建环境不应能访问生产数据库和Secret管理器

4.容器化构建:每次构建在干净的容器中进行

第3件事:启用来源验证

1.检查npm provenance:验证包是否来自可信的CI/CD工作流

2.使用Socket.dev:实时检测npm包的异常行为

3.订阅安全通告:关注Aikido、StepSecurity、Wiz的供应链安全报告

4.不要盲目信任AI推荐的包名:安装前先去npmjs.com验证包是否存在、维护者是谁、下载量是否合理

五、实战代码:检测你的项目是否受影响

#!/usr/bin/env python3 """ChainDrop供应链攻击检测脚本 - 紫禁玄科""" import json import os import re # 已知被感染的包名(部分列表) INFECTED_PACKAGES = [ "keyv", "flat-cache", "file-entry-cache", "cache-manager", "cacheable", "flatted", "citty", "consola", "defu", "destr", "dotenv", "git-url-parse", "is-plain-obj", "mlly", "node-fetch", "ohmyfetch", "pathe", "pkg-types", "radix3", "scule", "semver", "ufo", "unctx", "unenv", "unimport", "unstorage", "untyped" ] def check_package_json(project_path): """检查项目的package.json是否引用了被感染的包""" pkg_path = os.path.join(project_path, "package.json") if not os.path.exists(pkg_path): print(f"❌ 未找到 {pkg_path}") return [] with open(pkg_path, 'r') as f: pkg = json.load(f) all_deps = {} all_deps.update(pkg.get("dependencies", {})) all_deps.update(pkg.get("devDependencies", {})) found = [] for dep in all_deps: if dep in INFECTED_PACKAGES: found.append({ "name": dep, "version": all_deps[dep] }) return found def check_preinstall_hook(project_path): """检查是否存在可疑的preinstall钩子""" pkg_path = os.path.join(project_path, "package.json") if not os.path.exists(pkg_path): return False with open(pkg_path, 'r') as f: pkg = json.load(f) scripts = pkg.get("scripts", {}) preinstall = scripts.get("preinstall", "") if "setup.mjs" in preinstall or "Math_Symbol" in preinstall: return True return False def check_suspicious_files(project_path): """检查是否存在恶意文件""" suspicious = ["setup.mjs", "Math_Symbol.js", "math_init.js"] found = [] node_modules = os.path.join(project_path, "node_modules") if not os.path.exists(node_modules): return found for root, dirs, files in os.walk(node_modules): for f in files: if f in suspicious: found.append(os.path.join(root, f)) # 只检查前3层 depth = root.replace(node_modules, '').count(os.sep) if depth >= 3: dirs.clear() return found def main(): import sys project = sys.argv[1] if len(sys.argv) > 1 else "." print("🔍 ChainDrop供应链攻击检测") print("=" * 50) # 检查依赖 infected = check_package_json(project) if infected: print(f"\n⚠️ 发现 {len(infected)} 个被感染包的引用:") for pkg in infected: print(f" - {pkg['name']} @ {pkg['version']}") else: print("\n✅ 未发现已知被感染包的引用") # 检查preinstall钩子 if check_preinstall_hook(project): print("\n🔴 发现可疑的preinstall钩子!") else: print("✅ preinstall钩子正常") # 检查恶意文件 files = check_suspicious_files(project) if files: print(f"\n🔴 发现 {len(files)} 个可疑文件:") for f in files: print(f" - {f}") else: print("✅ 未发现可疑文件") print("\n" + "=" * 50) if infected or files: print("⚠️ 建议立即:") print(" 1. 删除 node_modules 并重新安装") print(" 2. 运行 npm audit") print(" 3. 轮换所有npm/GitHub token") else: print("✅ 你的项目目前安全") if __name__ == "__main__": main()

六、总结:供应链安全,刻不容缓

🔑 核心要点

1.ChainDrop是自传播蠕虫:偷到你的npm令牌后,用你的账号继续投毒,指数级扩散

2.preinstall钩子是关键攻击面:npm install时恶意代码自动执行,你根本来不及反应

3.AI幻觉包名是新威胁:不要盲目安装AI推荐的包,先验证再使用

4.锁定版本+禁用脚本+来源验证:三道防线缺一不可

5.凭证轮换是底线:如果安装过受影响版本,立即轮换所有token

⚠️重要提醒:如果你的项目安装过keyv、flat-cache等受影响包,请立即轮换npm、GitHub、AWS等所有凭证,并检查CI/CD环境是否被入侵。


📰 参考来源:BleepingComputer、Microsoft Security Blog、Aikido Security 🔒 本文由紫禁玄科原创,转载请注明出处 关注紫禁玄科,获取更多网络安全深度分析

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询