← 返回博客

LiteLLM 被投毒了。这暴露了 AI 工具供应链的什么问题。

一个安全扫描工具被攻陷,窃取了 PyPI 凭证,投毒了月下载量 9500 万的库。哈希验证通过了。恶意代码在官方 wheel 中。为什么沙箱化是唯一真正的防线。

LiteLLM 被投毒了。这暴露了 AI 工具供应链的什么问题。

昨天,LiteLLM——统一各家 LLM API 调用的 Python 库——被投毒了。GitHub 4 万星。月下载量 9500 万次。2000+ 个依赖包,包括 DSPy、MLflow 和 Open Interpreter。

版本 1.82.7 和 1.82.8 包含凭证收割器。一行 pip install 就足够了。

这不是一个包被黑的故事。这是关于整个 Python 包生态的信任模型为何在 AI Agent 基础设施面前从根本上失效——以及真正的防御长什么样。


发生了什么

攻击是一个四步级联供应链攻击:

第 1 步(3 月 19 日): Trivy v0.69.4 被投毒。Trivy 是 Aqua Security 的开源漏洞扫描工具——一个保护你的工具。攻击组织 TeamPCP 在其中植入了凭证窃取器。

第 2 步(3 月 23 日): LiteLLM 的 CI 流水线运行被投毒的 Trivy 来扫描自己的代码。在这次”安全扫描”中,Trivy 静默窃取了维护者的 PYPI_PUBLISH_PASSWORD

第 3 步(3 月 24 日上午): TeamPCP 用窃取的凭证将 litellm 1.82.7 发布到 PyPI。恶意代码隐藏在 litellm/proxy/proxy_server.py 中,当开发者导入该模块时执行。

第 4 步(3 月 24 日数小时后): TeamPCP 发布 litellm 1.82.8——升级版。这个版本添加了 litellm_init.pth 文件,在每次 Python 启动时自动执行。无需 import。无需函数调用。只要 Python 运行,恶意代码就运行。

安全工具变成了攻击入口。


.pth 攻击向量

这是技术上最有趣的部分。Python 的 .pth 文件是路径配置文件,由 site 模块在解释器启动时处理。如果某行以 import 开头,会被直接 exec() 执行——这是 Python 的文档行为,不是漏洞。

攻击者利用了这一机制:

import os, subprocess, sys; subprocess.Popen([sys.executable, "-c",
"import base64; exec(base64.b64decode('...'))"],
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)

这意味着:

没有任何用户可感知的动作。完全静默。载荷使用三层 base64 嵌套规避静态分析。


三层载荷架构

第 1 层——凭证收割器: 系统性搜刮 /home/opt/srv/var/www/app/data/tmp 下的 SSH 密钥、AWS/GCP/Azure 凭证、K8s Secrets、加密货币钱包、.env 文件、数据库密码、Shell 历史。用随机 32 字节 AES 会话密钥加密,再用 RSA-OAEP 包装 AES 密钥(4096 位公钥内嵌载荷中)。外传至 models.litellm.cloud——一个高度逼真的仿冒域名。

第 2 层——K8s 横向移动: 检测到 K8s 服务账号令牌后,在每个集群节点部署特权 Pod,安装持久化 dropper。

第 3 层——持久化后门:~/.config/sysmon/sysmon.py 注册为 systemd 用户服务。每 50 分钟轮询 checkmarx.zone 获取新载荷。下载到 /tmp/pglog 执行。启动有 5 分钟延迟规避沙箱分析。卸载 litellm 后仍然存活。


现有防御为何全部失效

pip install --require-hashes 无效。恶意文件正常列入 wheel 的 RECORD,哈希完全匹配。因为包是用窃取的合法 PyPI 凭证发布的,一切在技术上都是”真实的”。

包签名? 同样的问题。凭证是真的。签名是有效的。

安全扫描? 这次攻击起始于攻陷安全扫描工具。Trivy 本应保护 LiteLLM,结果它变成了入口。

社区报告? Issue 提交后,攻击者用 73 个被盗账号在 102 秒内发送 88 条垃圾评论淹没讨论,然后用被盗的维护者账号关闭 issue。

攻击被发现的唯一原因:攻击者自己的代码有 bug。.pth 文件生成的子进程在初始化时再次触发同一个 .pth,导致指数级递归——fork bomb 撑爆了一位 Cursor IDE 用户的内存。Karpathy 评论:如果攻击者代码写得再好一点,这件事可能几周都不会被发现。


真正的问题:隐式执行

根本问题不是 LiteLLM。而是 Python 包生态有多条路径让代码在没有显式调用的情况下执行:

执行钩子何时运行用户感知度
setup.pypip install
.pth 文件每次 Python 启动几乎为零
__init__.py首次 import 时
Entry point 脚本CLI 调用时

AI Agent 基础设施通常组合数十个包,每个都有自己的依赖树。每个依赖都是一个信任决策,而大多数开发者是无意识做出的。LiteLLM 攻击表明,即使你从未直接安装的包(传递性依赖)也能静默收割你的凭证。


沙箱化实际上阻止了什么

在 Rotifer Protocol 中,我们将 Agent 能力(称为 Gene)编译为 WebAssembly,在 wasmtime 沙箱中执行。这不是理论上的防御——它是一个根本不同的执行模型,从结构上消除了 LiteLLM 被攻击所利用的攻击面。

无文件系统访问。 沙箱中的 Gene 无法读取 ~/.ssh/~/.aws/credentials 或任何 .env 文件。WASM 沙箱没有文件系统 API,除非被显式授予。

无子进程生成。 subprocess.Popenchild_process.execos.system——在 WASM 执行环境中都不存在。.pth 攻击链(Popen → base64 → exec)在结构上不可能发生。

无隐式执行钩子。 WASM 中没有 .pth 的等价物。代码只在运行时显式调用时运行,而不是在解释器启动时。

声明式网络边界。 需要网络访问的 Gene 必须在其 Phenotype 中声明 allowedDomains——一份机器可读的能力清单。未声明的 POST 到 models.litellm.cloud 会在请求离开沙箱之前被拒绝。

二进制级执行。 这些限制不是可被绕过的策略规则——它们由 wasmtime 运行时在系统调用层面执行。编译为 WASM 的 Gene 在物理上无法发出读取文件或生成进程所需的系统调用,无论其源代码试图做什么。

在 v0.8 中,我们运行了 22 个专门设计来突破沙箱边界的对抗测试:内存越界攻击、无限循环、递归栈溢出、文件系统访问尝试、未授权网络调用。在修补测试中发现的两个关键漏洞后,零次逃逸成功。


V(g):精准检测这些模式

我们在 v0.7.9 发布的 V(g) 安全扫描器 检测的正是 LiteLLM 攻击中使用的模式:

V(g) 检测规则LiteLLM 攻击模式
动态代码执行(evalexecexec(base64.b64decode(...))
子进程生成(child_processsubprocesssubprocess.Popen(...)
混淆载荷三层 base64 编码
未授权网络调用POST 到 models.litellm.cloud

V(g) 对源码进行静态扫描——无 ML,无启发式,只对重要的东西做模式匹配。评分从 A 到 D,并生成 shields.io 兼容徽章,任何开发者都可以嵌入 README。

当我们用 V(g) 扫描 ClawHub 最热门 50 个 Skill 时,100% 触发了至少一项发现。零个 A 级结果。14% 包含动态代码执行——与 LiteLLM 载荷完全相同的技术。


令人不安的结论

LiteLLM 事件不是个例。它是一个生态系统的逻辑后果,在这个生态中:

  1. 信任是传递性的且不可见的。 你信任 litellm,litellm 信任 Trivy,而 Trivy 被攻陷了。你从未对 Trivy 做过任何决策。
  2. 执行是隐式的。 代码运行不是因为你调用了它,而是因为解释器启动了。
  3. 认证 ≠ 授权。 有效凭证不等于有效意图。哈希验证和包签名是认证措施——它们告诉你发布了包,而不是这个包做了什么

防御不在于更好地扫描 Python 包(虽然这有帮助)。防御在于一个执行模型,其中不受信任的代码在物理上无法访问它想窃取的资源。

编译为 WASM。在沙箱中运行。显式声明网络边界。让默认值是”无访问”而不是”完全访问”。

这就是我们正在构建的。


如果你受影响了怎么办

如果你安装了 litellm 1.82.7 或 1.82.8:

  1. 假设所有凭证已泄露。 轮换一切:SSH 密钥、云凭证、API Token、数据库密码。
  2. 检查持久化后门: ls ~/.config/sysmon/ls /tmp/pglog。如果存在,你的系统有后门。
  3. 检查 .pth 文件: 在 Python site-packages 中搜索 litellm_init.pth,找到就删除。
  4. 固定安全版本: pip install litellm==1.82.6
  5. 运行社区自查脚本: gist.github.com/sorrycc/30a765…

安全版本:litellm <= 1.82.6。版本 1.82.7 和 1.82.8 已被投毒,已从 PyPI 移除。