ONCALL://19
INC-06 · LiteLLM

LiteLLM 1.107.0 发布流水线被劫持

攻击者用 3 个失窃的 GitHub CLI 令牌改写 LiteLLM 的私有发布流程,从仿冒仓库 Berri-AI/litellm 构建并发布了 1.107.0。恶意代码在任何 Python 启动时运行,窃取凭据,并安装每小时轮询一次的远程代码加载器。

INC-06严重直接命中供应链投毒P0立即披露 2026-10-21
段子原句“CI 昨晚刚从 PyPI 拉了新包并推送到了生产环境,现在全公司电脑都装上了这套 Harness”
编号
无 CVE 或 GHSA 编号
严重度
无 CVE;已确认的恶意版本
利用状态
恶意版本已发布恶意版本已发布:恶意代码已确认。PyPI 上架约 1 小时 44 分钟,Docker 标签被劫持约 2 小时 33 分钟。
对段子公司
CI 如果在 10-21 19:39 至 21:23(北京时间)拉取未固定版本,拿到的就是恶意包。生产环境和全员电脑都要按失陷处理。
影响范围
LiteLLM 每周下载约 2,300 万次。受影响的是 10-21 11:39 至 13:23 UTC 的 pip 安装,以及 11:46 至 14:20 UTC 启动的 latest 等镜像。实际下载量和受害组织数未公布。这是 2026 年第二次投毒,3 月的 1.82.7 和 1.82.8 被下载超过 119,000 次。
修复版本
  • →固定到 litellm==1.106.2
  • →恶意版本已从 PyPI、Docker Hub、GHCR 移除
处置清单见处置顺序 · P0

结论

2026-10-21,攻击者劫持 LiteLLM 的私有发布流水线,向 PyPI 和 Docker 镜像仓库发布了带恶意代码的 litellm==1.107.0。[1] [2]PyPI 上的恶意版本在 11:39 至 13:23 UTC 可下载,约 1 小时 44 分钟。[1]Docker Hub 的 v1.107.0、latest、main-latest、main-stable 标签在 11:46 至 14:20 UTC 指向恶意镜像。[1]恶意代码会在任何 Python 进程启动时运行,窃取云、开发、AI 工具、浏览器和 LiteLLM 代理数据库中的凭据。[2] [3]这是 LiteLLM 在 2026 年第二次被投毒。第一次是 3 月 24 日的 1.82.7 和 1.82.8。[2] [5]

事件经过

LiteLLM 在 3 月事故后加固了发布流程。它把发布移到私有仓库,使用 Trusted Publishers,并对 Docker 镜像签名。[1]10 月 20 日(周一),LiteLLM 临时扩大了发布权限,让两名内部工程师每天发布补丁回移版本。[1]攻击者持有 3 名开发者的 GitHub CLI OAuth 令牌。其中一个令牌属于 GitHub 组织所有者。[1]攻击者用所有者令牌关闭分支保护,强推了一个修改后的发布工作流。[1]

修改后的工作流从仿冒仓库 Berri-AI/litellm 构建制品。正版仓库是 BerriAI/litellm,两者只差一个连字符。[1] [2]第二个开发者令牌通过了生产发布审批。第三个令牌随后删除了工作流运行记录,减少了可用于调查的日志。[1]因为制品走的是正常发布通道,构建来源证明(provenance)看起来是合法的。它如实记录了仿冒仓库作为源码来源。[2]

LiteLLM 认为,令牌来自其公网暴露的内部 LiteLLM 部署的日志。官方称,Claude Code 在某些情况下会把 GitHub CLI 令牌写入响应体,而这些响应体被记录到了日志里。[1]攻击者如何进入这个内部部署尚未确认。官方怀疑是利用了一个最近修复的漏洞。[1]

技术细节

恶意版本在 site-packages 中加入 3 个文件:cook.pth、cook.py、sitecustomize.py。[2]Python 每次启动都会自动执行 .pth 文件和 sitecustomize.py。所以只要环境里装了这个版本,运行任何 Python 程序都会触发恶意代码,即使程序从未导入 LiteLLM。[2]运行 pip 本身也会再次触发。删除 litellm 包目录不能清除这些文件。[1] [2]

cook.py 是凭据窃取器,有 16 个收集模块。[3] 收集范围如下:

  • 云凭据:AWS、GCP、Azure 凭据文件和实例元数据令牌,Kubernetes、Docker、Vault、Terraform 密钥。[2] [3]
  • 开发凭据:SSH、GPG、TLS 私钥,Git、npm、PyPI 令牌,.env 文件,Shell 历史。[2] [3]
  • AI 工具凭据:Claude Code、Cursor、Copilot、Gemini CLI、Codex 等 AI 编程工具的会话和配置。[2] [3]
  • 浏览器:Chrome、Edge、Brave 等浏览器保存的密码和 Cookie。[3]
  • 进程环境变量:在 Linux 上读取所有可读进程的 /proc/<pid>/environ。[3]
  • LiteLLM 代理数据库:如果设置了 DATABASE_URL,它会查询代理保存的上游模型服务商凭据。[2] [3]

窃取的数据先用 AES-256-CBC 加密,再用内置的 RSA-4096 公钥包裹密钥。[3]数据通过明文 HTTP POST 发往仿冒域名 www.litellm[.]dev/healthcheck。[2] [3]因为数据已加密,抓包无法判断具体被偷了什么。[3]

sitecustomize.py 是远程代码加载器。它在 Linux 和 macOS 上派生一个常驻守护进程,并持有 /tmp/remote_code_loader.lock。[3]守护进程每小时读取 GitHub 仓库 letters9813/pythonclient-test 中的 domain.txt。如果文件里有域名,它就下载并执行该域名下的 /codepy。[2] [3]发布时 domain.txt 为空,所以未观察到第二阶段载荷。[2] [3]该 GitHub 账号已被删除。但如果有人重新注册同名账号并创建同名文件,仍在运行的守护进程会执行他的代码。[3]

主要 IoC(入侵指标)如下:[2] [3]

类型值
投放文件cook.pth、cook.py、sitecustomize.py
外传地址http://www.litellm.dev/healthcheck
外传请求头X-Token: XWiA8gZNa7NcX2XRoAEb
窃取成功标记/tmp/.pc_once_72129118c59f5636c0bb
加载器锁文件/tmp/remote_code_loader.lock
环境变量PRIVCOLLECT_ACTIVE=1
恶意镜像索引sha256:1bbcb1443bc962e45f5aad53fe3d2c30600e0379715fb6c664cdd3ac126c339e
仿冒源码仓库github.com/Berri-AI/litellm,提交 20535d8fa11f786a6c24df7488a0e449ed5f09ad

影响范围

LiteLLM 每周下载量约 2,300 万次。[2]受影响的是 11:39 至 13:23 UTC 之间未固定版本、通过 pip 安装 LiteLLM 的环境。[1]也包括在 11:46 至 14:20 UTC 之间启动 v1.107.0、latest、main-latest、main-stable 镜像的容器。[1]GHCR 上的 litellm、litellm-database、litellm-non_root 三个镜像都受影响。[1]使用私有企业版镜像仓库的企业客户不受影响。[1]官方和第三方都没有公布实际下载次数、受害组织数或被盗凭据数。这些数字未验证。

时间线

  1. 2026-10-13 00:45 UTC
    仿冒域名 litellm.dev 注册。[3]
  2. 2026-10-18 04:17 UTC
    攻击者创建用于远程加载的 GitHub 仓库。[3]
  3. 2026-10-21 10:08:29 UTC
    GitHub 分支保护拒绝了对私有发布工作流的未授权修改。[1]
  4. 2026-10-21 10:08:34 UTC
    攻击者用特权开发者令牌绕过保护,强推工作流修改。[1]
  5. 2026-10-21 10:46:39 UTC
    修改后的工作流从 Berri-AI/litellm 开始预发布构建。[1]
  6. 2026-10-21 11:11:18 UTC
    第二个开发者令牌通过生产发布审批。[1]
  7. 2026-10-21 11:39:51 UTC
    7 个恶意 wheel 开始上传到 PyPI,11:40:13 完成。[1]
  8. 2026-10-21 11:46:56 UTC
    恶意 Docker 镜像发布。[1]
  9. 2026-10-21 11:53:49 UTC
    第三个开发者令牌删除工作流运行记录。[1]
  10. 2026-10-21 12:06 UTC
    用户在 GitHub 报告该问题。[3]
  11. 2026-10-21 13:23 UTC
    PyPI 已移除 1.107.0。[1]
  12. 2026-10-21 14:20 UTC
    所有受影响的 Docker Hub 标签被删除或改指向干净镜像。[1]
  13. 2026-10-21 16:42 UTC
    @Manjusaka_Lee 发布本段子,北京时间为 10-22 00:42。
  14. 2026-10-21 20:30 UTC
    LiteLLM 更新公告,称已识别攻击链。[1]

修复与缓解

  1. 不要先运行 pip install。因为任何 Python 启动都会再次执行恶意代码。[1]
  2. 在 Shell 中删除每个受影响 site-packages 里的 cook.pth、cook.py、sitecustomize.py 及对应 .pyc 文件。[1] [2]
  3. 结束持有 /tmp/remote_code_loader.lock 的守护进程。[1]
  4. 重建虚拟环境和镜像,并固定到 litellm==1.106.2。[1] [2]
  5. 只要主机曾安装 1.107.0 且能访问外网,就假定凭据已外泄。没有标记文件不能证明安全。[1]
  6. 从干净的机器轮换主机可访问的全部凭据。重点是实例 IAM 角色、LiteLLM 代理数据库中的所有服务商密钥、主密钥和虚拟密钥、DATABASE_URL 密码。[1]
  7. 在 CloudTrail 中检查安装时间附近的 GetCallerIdentity 调用,以及之后从外部使用该角色凭据的记录。[1]

3 月 24 日的第一次投毒

2026-03-24,攻击者向 PyPI 发布 litellm 1.82.7 和 1.82.8。[5] [6]那次的入口不同。LiteLLM CI 使用的 Trivy 依赖被投毒,泄露了 PyPI 发布令牌。[5] [7]1.82.8 用 litellm_init.pth 在 Python 启动时运行载荷,并尝试在 Kubernetes 中部署特权 Pod。[7]PyPI 统计,这两个版本在暴露期间被下载超过 119,000 次。[6]Datadog 称,截至 10-21,尚未发现两次事故之间存在关联。[2]

对段子中公司的影响

段子说“CI 昨晚刚从 PyPI 拉了新包并推送到了生产环境,现在全公司电脑都装上了这套 Harness”。如果 CI 在 10-21 11:39 至 13:23 UTC(北京时间 19:39 至 21:23)拉取了未固定版本的 LiteLLM,它拿到的就是 1.107.0。[1]这时生产环境和每台员工电脑都要按“已失陷”处理。因为恶意代码在任何 Python 启动时运行,并会读取所有进程的环境变量。[2] [3]员工电脑上的浏览器密码和 AI 编程工具会话也在窃取范围内。[3]如果 Harness 后面接了 LiteLLM 代理数据库,所有上游模型服务商的密钥都要轮换。[2] [3]在段子列出的所有组件中,只有这一项是“恶意代码已确认存在,而且公司已经装上”。所以它的处置优先级最高。

存疑与未验证

  • 实际下载次数、受害组织数和被盗凭据数量:未公布,未验证。
  • 攻击者如何进入 LiteLLM 内部部署:官方怀疑是一个最近修复的漏洞,未确认。[1]
  • Claude Code 把令牌写入响应体的具体条件:来自 LiteLLM 单方说法,未独立验证。[1]
  • 两次投毒是否为同一攻击者:未确认。[2]
  • LiteLLM 提到一个计划在 10-27 披露的漏洞,企业版已提前修复。该漏洞与本次事故的关系未验证。[1]
  • 段子的发帖时间由推文 ID 推算,不是 X 页面直接显示的时区时间。

参考资料

调研截止 2026-10-22 UTC+8 · 未验证的内容已在正文中标注 · 数字以原始来源为准

本页目录