一场从卡死笔记本开始的供应链惊魂:LiteLLM 恶意包如何在两小时内被揪出

安全 2026年3月27日
这不是一篇普通的安全事故复盘,而是一场“人类怀疑 + AI协查”共同完成的实战记录:开发者起初以为只是 Cursor、Claude Code 和 Python 进程失控,最终却挖出了一起 LiteLLM 的 PyPI 供应链投毒。真正值得行业警惕的,不只是恶意包本身,而是 AI 正在同时加速攻击和防御——谁先适应这种节奏,谁才有未来。

一台突然卡死的 Mac,撕开了 AI 开发生态最脆弱的一角

故事的开头很像很多程序员都经历过的那种“日常灾难”:风扇狂转,机器变慢,htop 里满屏的 Python 进程,数量多到离谱,足足冲到了 1.1 万个。命令看起来也很眼熟:python -c "exec(base64.b64decode(...))"。如果你平时用过各种 AI 编程工具、自动化脚本或者 Python 工具链,第一反应大概率和当事人一样——这八成又是什么插件、代理、IDE 扩展抽风了。

起初,AI 助手给出的判断也相当“工程师思维”:这可能不是恶意软件,而是 Claude Code、Cursor、uv、MCP server 之类工具在异常状态下触发了进程风暴。老实说,这个推断并不荒唐。今天的开发环境本来就像一锅沸腾的火锅:编辑器里有扩展宿主、语言服务器、Python 虚拟环境、Node 桥接进程、MCP 连接器,再加上会自动更新、自动拉包、自动重连的现代工具链,谁看日志谁头大。

但这次真正让人后背发凉的地方在于:表面上看像“软件抽风”,骨子里却是一次货真价实的供应链攻击。随着调查推进,攻击源头被指向 PyPI 上的 litellm 包,版本号是 1.82.8。这个版本中被植入了一个 .pth 文件——对 Python 开发者来说,这种文件平时低调得像空气,可它偏偏拥有一个极其危险的能力:在 Python 启动时自动执行代码。也就是说,只要你运行 Python,恶意逻辑就有机会跟着醒过来。

真正可怕的不是 fork bomb,而是“每次启动都中招”

这起事件最抓人的细节,是它并不是那种传统意义上“啪一下弹窗勒索”的攻击,而是一种更阴、更像现代软件生态里会发生的事:它藏在开发者每天都在使用的依赖链里,借着工具自动安装、自动缓存、自动调用的流程悄悄落地。根据披露内容,这个恶意 .pth 文件会在每次 Python 启动时触发,试图搜集 SSH 密钥、云平台凭证、Kubernetes 配置、.env 文件、Shell 历史记录等敏感信息,并向可疑域名回传。

至于为什么机器会被 1.1 万个 Python 进程拖死,也不是攻击者写了个传统 fork bomb 那么简单,而是一个更符合“供应链污染”语境的连锁反应:恶意脚本会拉起新的 Python 子进程,而每个新进程启动时又会再次执行这个 .pth 文件,于是递归套递归,最后整个系统像踩进流沙一样越陷越深。你以为自己看到的是“CPU 爆了”,其实那只是攻击留下的烟雾。

更惊险的是,恶意程序还试图建立持久化机制。调查显示,攻击过程里曾创建 ~/.config/sysmon/sysmon.py 这样的路径,只是因为用户在 11:09 强制关机,文件最终只写成了 0 字节。这个细节很像电影里“歹徒刚把门撬开一条缝,就被屋主一脚踹回去”。只不过现实没有配乐,只有一台烫得发昏的笔记本和一个差点被掏空的开发环境。

这次复盘最有意思的地方,是 AI 既误判,也立功

如果只把这件事写成“某个包被投毒,开发者赶紧换密钥”,那就太浅了。真正值得科技行业反复咂摸的,是这次响应过程本身。按原文披露,这场调查几乎是沿着一段 Claude Code 对话一步步推进的:先从 journalctl、进程树、缓存目录和日志文件入手,再定位到 uv 缓存中的恶意文件,最后完成公开披露。整件事从发现异常到对外发布,只用了不到两小时。

这很说明问题。过去,安全应急之所以慢,往往不是因为没人想查,而是因为查不动:你得懂操作系统日志、包管理缓存、容器复现、恶意样本提取、威胁情报上报,还得知道该联系谁。现在,AI 把其中大量“机械但专业门槛极高”的步骤压缩掉了。不会看 macOS 关机日志?AI 帮你梳理。忘了 Python 包缓存路径?AI 帮你找。想从一段 Base64 命令追溯真实载荷?AI 可以边拆边解释。

但这次事件也暴露出另一个更微妙的问题:AI 一开始并没有立刻意识到这是恶意攻击。它先给出了更“正常世界”的解释——进程泄漏、更新冲突、扩展清理失败。这个误判并不丢人,甚至很像经验丰富的工程师会做出的保守判断,因为“自己正好撞上尚未公开的供应链攻击”本来就是小概率事件。问题在于,未来这种小概率事件可能会越来越常见。那时,模型如果总是倾向于把异常当成普通 bug,防守方就会失去宝贵的前几分钟。

说得更直接一点:AI 编程助手今天已经非常懂“如何把代码跑起来”,但它还没有同等程度地理解“哪些迹象意味着你可能已经被打了”。这会是接下来模型能力进化里非常关键的一课。不是让模型变成黑客,而是让它在工程语境下具备更强的安全直觉。

PyPI、npm、xz:供应链攻击为什么越来越像日常天气

这件事之所以让人不安,是因为它不是孤例,而是趋势的一部分。过去几年,开源生态里的供应链安全已经被反复敲打:event-stream 事件让 npm 社区见识过维护权转移后的暗箭,ctxcolourama 的恶意包投递让 PyPI 用户意识到“拼写相似”有多危险,去年的 xz 后门事件更是把“关键基础组件险些被长期渗透”摆到了全球工程师面前。

LiteLLM 这次遭遇的投毒,放到这个背景里看,就不只是某个热门 AI 代理工具不幸中枪,而是整个 AI 开发生态在高速扩张时暴露出的旧病新患。今天的 AI 开发工具比传统软件栈还要复杂,因为它们天然依赖更多第三方包、更多云 API、更多本地凭证,还常常运行在拥有高权限的开发环境里。换句话说,开发者电脑已经不是简单的代码终端,而是连着 GitHub、云服务、数据库、集群和生产秘钥的总控制台。攻击者盯上这里,性价比极高。

更麻烦的是,AI 工具普遍追求“无感体验”:自动发现环境、自动安装依赖、自动连接模型、自动更新插件。用户越省心,链路越长,黑箱就越多。Cursor 自动更新、扩展宿主重启、MCP 重连、uvx 临时拉取依赖——这些设计平时带来的是丝滑,出事时带来的就是排查地狱。人类越来越习惯把“它自己会处理好”当作默认前提,而攻击者恰恰喜欢钻这种前提。

对开发者来说,真正的教训不是“别用 AI”,而是别再把本机当净土

我不认为这起事件会把开发者吓回到手工管理依赖、拒绝 AI 助手的时代。相反,AI 编程和代理化开发只会更普及,MCP、CLI 助手、自动化工作流也会越来越常见。问题不是“用不用”,而是“你是不是还在用十年前对待本地开发机的方式,去面对一个已经接近生产控制台的环境”。

一台开发者笔记本上同时放着 SSH key、云账号、数据库连接串、Kube 配置和各种 .env,这本来就像把办公室钥匙、保险箱密码和公司章都塞进同一个抽屉。过去大家这么干,是因为麻烦比风险更真实;现在继续这么干,就有点侥幸了。更现实的做法,是把密钥轮换、最小权限、短期凭证、缓存隔离、依赖锁定、包源审计,变成日常卫生,而不是事故后的补救动作。

厂商也该补课。像 Cursor、Claude Code、各类 Python/JS 包管理器,未来都应该更积极地提供“可疑依赖预警”“首次执行高风险钩子提醒”“异常进程风暴熔断”“自动更新中的高危回滚”等能力。今天很多工具都在拼谁更像一个贴身助理,但贴身助理不能只会帮你写代码,也得会在有人摸你钱包时第一时间大喊。

这次事件里有一个很值得玩味的问题:前沿模型公司是不是应该专门训练模型识别供应链攻击和开发环境异常?我的答案偏向肯定。因为下一代安全告警,很可能不再来自传统杀毒软件,而是来自那个最懂你工作流的 AI 助手。它知道你什么时候在正常装包,什么时候这个包的行为已经明显越界。谁先把这种能力做出来,谁就可能重新定义“开发者安全工具”的边界。

一场事故,也是一张时代剖面图

如果把这起 LiteLLM 恶意包事件当成单纯的安全新闻,它当然已经足够严重:凭证可能被窃取,持久化险些完成,开发者机器被拖入进程风暴,PyPI 供应链再次亮起红灯。但从更大的视角看,它还是一张非常典型的时代剖面图。

我们正在进入一个奇怪的新阶段:AI 让攻击更快,也让防守更快;软件越来越自动化,故障和入侵也越来越难从表面区分;开发者工具越来越像操作系统,而操作系统级的安全责任却还没真正跟上。以前出了事,人们会问“是不是我点了不该点的东西”;以后更常见的问题可能是,“到底是哪个我信任的自动化环节,在替我打开后门?”

这件事让我最有感触的,不是那 1.1 万个 Python 进程,而是最初那几分钟里的犹豫:它像 bug,像更新事故,像扩展冲突,像任何一件现代软件世界里习以为常的破事。也正因此,它才危险。因为真正高明的攻击,从来不是长得像怪物,而是长得像日常。

Summary: 我倾向于把这次 LiteLLM 事件看成一个分水岭:AI 开发工具正式进入“既是生产力引擎,也是高风险入口”的阶段。未来一年,我们会看到更多围绕包管理、插件更新、代理执行链的安全加固,模型厂商也会被迫补上“安全感知”这门课。谁还把开发机当成单纯写代码的地方,谁就可能在下一次自动更新或自动装包时,交出比代码更贵的东西。
供应链攻击LiteLLMPyPI恶意包投毒PythonAI开发工具CursorClaude Codebase64