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亿次。受影响的包包括开发者耳熟能详的keyv、flat-cache、cache-manager、file-entry-cache等缓存工具以及来自Deliveroo、Picsart、Qlik、ServiceTitan等知名企业的关联包。⚠️关键数字1300被感染包 | 1381个恶意版本 | 20亿月下载量 | 4小时内从444包扩散到1300包二、攻击者视角ChainDrop是怎么做到的⚠️ 以下内容仅供安全研究和防御学习请勿用于非法用途图2ChainDrop攻击链路图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_开头的token2.GitHub令牌ghp_、gho_、ghs_开头3.AWS凭证Access Key Secret Key4.Kubernetes Secret5.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. 下载最新版本的tarball3. 注入恶意代码4. 递增patch版本号5. 重新发布到npm就这样你的包变成了攻击者的武器继续感染你的用户。这是一个典型的蠕虫传播模式一个受害者变成多个指数级扩散。Step 5AI幻觉攻击——蹲点抢注包名图4AI幻觉包名抢注攻击更离谱的是攻击者还会利用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年 ChainDrop1300包被感染月下载20亿次自传播蠕虫AI幻觉包名抢注。四、防御方案你能做的三件事第1件事锁定依赖版本1.使用lockfile确保package-lock.json提交到Git锁定每个依赖的精确版本2.禁用preinstall脚本npm install --ignore-scripts 或在.npmrc中设置 ignore-scriptstrue3.使用npm audit每次安装前运行npm audit检查已知漏洞4.定期审查依赖用npm outdated检查过期包删除不用的依赖第2件事隔离构建环境1.CI/CD环境最小权限不要在构建环境中存储长期凭证2.使用OIDC短期令牌替代长期npm/GitHub token3.网络隔离构建环境不应能访问生产数据库和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 本文由紫禁玄科原创转载请注明出处 关注紫禁玄科获取更多网络安全深度分析