2026年4月30日,PyPI上最流行的深度学习框架之一——lightning(PyTorch Lightning)更新了两个版本:2.6.2和2.6.3。
开发者们习惯性地敲下 pip install lightning,继续训练他们的图像分类器、微调大语言模型、跑扩散模型。他们不知道的是,这一行命令,足以让攻击者偷走他们所有的密钥、污染他们的代码库、甚至把恶意软件传播给每一个使用他们项目的人。
这场攻击的代号,来自《沙丘》:Shai-Hulud。
Shai-Hulud:沙漠之下的沙虫
取这个名字的攻击者,显然对自己很满意。他们在恶意代码中留下了大量《沙丘》彩蛋:创建的公开仓库叫 "EveryBoiWeBuildIsaWormBoi",描述信息是 "A Mini Shai-Hulud has Appeared"。
在GitHub上搜索这个句子,已经出现了2200多个仓库——全部是24小时内创建的,全是攻击者的数据外泄通道。
更嚣张的是,攻击者用 commit message 来传递数据。格式是 EveryBoiWeBuildIsAWormyBoi:<双重base64编码的令牌>,明晃晃地躺在GitHub的搜索结果里。这是炫耀。
安全研究人员确定,这是同一伙攻击者继 "mini Shai-Hulud" 行动后的卷土重来。上一次他们直接从npm下手,这次换了个玩法:从PyPI的Python包入口,载荷依然是JavaScript,通过npm实现蠕虫式传播。
你的开发机,正在被掏空
一旦你安装了受感染的 lightning@2.6.2 或 2.6.3,攻击就悄无声息地开始了。
恶意包里的 _runtime 目录包含一个Python加载器和一个14.8MB的JavaScript有效载荷。只要你的代码里 import lightning,载荷就会自动执行——不需要任何额外操作,不需要你点击什么,不需要你运行什么脚本。然后,它开始疯狂窃取。
本地文件: 扫描80多个可能的凭证文件路径,读取 ghp_、gho_、npm_ 开头的令牌,单个文件最大5MB。
环境变量: 直接运行 gh auth token,把整个 process.env 全部打包带走。
GitHub Actions: 在Linux CI机器上,它用嵌入式Pythondump Runner.Worker进程的内存,提取所有标记为 isSecret:true 的密钥。
AWS: 尝试环境变量、~/.aws/credentials、IMDSv2元数据服务、ECS容器元数据,调用 sts:GetCallerIdentity 确认身份,然后枚举并拉取所有 Secrets Manager 和 SSM 参数。
Azure: 用 DefaultAzureCredential 枚举订阅,访问 Key Vault 里的所有密钥。
GCP: 通过 GoogleAuth 认证,枚举并获取 Secret Manager里的所有秘密。
四条平行通道同时外传数据——即使其中一条被阻断,其他三条也能把数据送出去。简单说:只要你的机器在这两个版本发布期间导入过这个包,就当它已经被完全攻破了吧。
它不仅偷,还让你成为帮凶
偷只是第一步。更狠的是,如果恶意软件在你的机器上发现了npm发布凭证,它会做一件很脏的事情:找到你有权发布的每一个npm包,注入 setup.mjs 加载器和 router_runtime.js 恶意脚本,把 scripts.preinstall 设为执行这个加载器,然后自动提升patch版本、重新发布。
任何下游开发者安装了这些被污染的包,就会重复整个流程:被偷凭证、被污染、再传播。一人失手,百人遭殃。这就是供应链攻击的恐怖之处:它不是点对点的入侵,而是链式裂变的感染。
开发者工具,成了最佳后门
攻击者深谙一个道理:开发者信任自己的工具。所以他们把持久化钩子直接埋进了开发者日常使用的两个工具里:Claude Code 和 VS Code。
如果你在感染后的仓库里打开Claude Code,它会自动执行 .claude/settings.json 里注册的 SessionStart 钩子——匹配规则是 "*",意思是无论你做什么,只要打开Claude Code就会触发。指向的是 node .vscode/setup.mjs。
如果你用VS Code,只要打开项目文件夹,tasks.json 里的 runOn: folderOpen 任务就会自动运行 node .claude/setup.mjs。
两个钩子都指向同一个文件:setup.mjs。这玩意儿是个自包含的Bun运行时引导程序。如果目标机器没装Bun,它会默默从GitHub Releases下载对应版本的Bun(支持Linux x64/arm64/musl、macOS x64/arm64、Windows x64/arm64),然后执行那个14.8MB的恶意载荷,最后清理掉所有痕迹。
它甚至会趁你有GitHub写入权限时,直接推一个名为 "Formatter" 的GitHub Actions工作流。这个工作流会在每次push时,用 ${{ toJSON(secrets) }} 导出所有仓库密钥,上传为可下载的Actions artifact。整个过程,你毫不知情。
“沙虫”
写下这篇报道的时候,GitHub上已经有2200多个仓库名字叫 "A Mini Shai-Hulud has Appeared"。攻击者用commit message和外泄仓库的命名,毫不掩饰地展示着自己的身份识别。这不是疏漏,这是挑衅。
而更讽刺的是,这场攻击的入口,是AI开发者最习以为常的一行命令:pip install lightning。ML生态的依赖复杂度,远超Web开发。一个普通的深度学习项目,可能涉及上百个直接和间接依赖。每一个依赖都是一个潜在的攻击面。
评论区里有人说:“我现在让我女儿学编程,只用原生JS和HTML。双摆、流体模拟,都能跑。不用几百个依赖。”也有人说:“我现在的pip安装,基本都是Claude Code建议我打的,我直接回车。模型是几个月前训练的,根本不知道这周哪个包被黑了。我们构建了一个最糟糕的过滤器——‘这包现在安全吗?’”话糙理不糙。
官方建议:先退回2.6.1
PyTorch Lightning团队在GitHub上确认了问题,建议所有用户立即降级到2.6.4之前的版本(也就是2.6.1)。
如果你在这两周内用过2.6.2或2.6.3:
- 查一下
.claude/ 和 .vscode/ 目录里有没有奇怪的文件
- 搜一下 commit message 里有没有
EveryBoiWeBuildIsAWormyBoi 这个前缀
- 旋转你所有的GitHub令牌、API密钥、云端凭证
- 当作你的整个开发环境已经被入侵过
没有侥幸。
【锐评】:当攻击者开始用《沙丘》梗给自己的恶意软件命名、用commit message传数据、用开发者的信任当后门时,这场攻防战早就超越了技术层面。
云栈社区的安全研究员们正持续跟进此事。
参考链接:
https://semgrep.dev/blog/2026/malicious-dependency-in-pytorch-lightning-used-for-ai-training/