恶意 LiteLLM 1.107.0 窃取凭据并在主机植入后门
威胁行为者利用泄露且从未撤销的主密钥劫持 LiteLLM 发布流水线,于 2026 年 10 月 21 日向 PyPI 和 Docker 推送恶意 1.107.0。该 wheel 安装 Python 启动文件,即使从未导入 LiteLLM,也会窃取凭据并开启每小时运行的后门。PyPI 在 1 小时 44 分钟后隔离该版本;任何安装过它的用户都必须重建环境,并轮换所有可触及的密钥。
要点速览
- 2026 年 10 月 21 日 11:39 UTC 发布至 PyPI、11:46 UTC 发布至 Docker Hub 和 GHCR 的 LiteLLM 1.107.0,由攻击者而非项目构建。Upwind 于 12:06 UTC 报告攻击后,PyPI 于 13:23 UTC 隔离该版本,Docker 标签于 14:20 UTC 被移除或重新指向。
- 恶意 wheel 在 LiteLLM 包目录之外写入 Python 启动文件,因此每次在该环境启动 Python,载荷都会运行,即使从未导入 LiteLLM。Microsoft 安全研究人员记录,仅移除包会留下启动组件。
- 载荷包括凭据窃取器,收集 SSH 和 Git 凭据、环境变量、注册表和包管理器令牌、云及 AI 密钥、浏览器数据,并 POST 到 litellm[.]dev/healthcheck;另有 Unix 后门,每小时抓取并运行攻击者提供的代码。
- 如果资产中任何系统在该窗口安装或拉取了 1.107.0,应将主机及其密钥视为已失陷:从经验证的干净版本重建环境,轮换主机、构建和周边 CI 能触及的所有凭据。最后一个干净的 PyPI 版本为 1.106.3。
我是否受到影响?
以下条件全部成立时,您就受到影响:
- 某个系统在 2026 年 10 月 21 日 11:39 UTC 至 13:23 UTC 隔离前,从 PyPI 安装了 litellm 1.107.0;或拉取了 11:46 UTC 发布、直到 14:20 UTC 才移除或重新指向 v1.107.0、latest、main-latest、main-stable 标签的 LiteLLM Docker 或 GHCR 镜像。
- 安装后环境至少启动过一次。执行通过 Python 启动文件发生,因此不需要导入 LiteLLM,从未调用它也不能保护主机。
- 此后尚未重建环境并轮换密钥。
检查主机、CI Runner 和镜像中安装及固定的版本:
pip show litellm | grep -E '^(Name|Version|Location)'
grep -rn 'litellm' requirements.txt pyproject.toml 2>/dev/null
grep -n -A2 'name = "litellm"' uv.lock poetry.lock 2>/dev/null # shows the pinned version
docker images | grep -i litellm # local caches
在 CI 和开发者机器上,还要查找本不该存在的 Python 启动文件:环境 site-packages 或用户 site 目录中的意外 .pth 文件、sitecustomize.py 或 usercustomize.py。这就是 wheel 使用的持久化机制。截至 10 月 25 日,PyPI 完全没有最终版 1.107.0(仅有 dev 和 rc 预发布构建),1.106.3 是最新最终版。这本身就能快速确认最终版 1.107.0 从未合法发布。
规模方面,litellm 过去一周记录了 21,343,835 次 PyPI 下载(pypistats,2026 年 10 月 25 日核查),因此即使仅有 1 小时 44 分钟的暴露窗口,也会触及大量自动安装、CI 缓存和夜间构建。
恶意代码做了什么?
恶意版本将代码安装到 Python 启动路径,位于正常卸载会移除的包之外,把 LiteLLM 从库变成主机级植入物。
Socket、OpenSourceMalware 研究团队和 Microsoft Security Research 的分析一致指出,1.107.0 wheel 内有两条执行路径:
- 在 Python 启动时运行的凭据收集器。它收集系统信息、SSH 文件、Git 和 GitLab 凭据及令牌、环境变量、开发工具、AI 应用、云环境和浏览器的身份验证材料,以及 npm、PyPI、pip、Yarn、Maven、Gradle、Composer、RubyGems 和 Cargo 相关令牌。数据经过压缩,通过 HTTP POST 发送至 litellm[.]dev/healthcheck;该域名于 2026 年 10 月 13 日注册,早于发布八天。
- 面向 Unix 的后门,以后台进程启动,每小时联系攻击者,抓取并执行任意代码;即使修复被盗会话或更改密码,这种持久化访问仍然存在。
关键在于代码存放位置。wheel 将 cook.pth、cook.py 和 sitecustomize.py 三个文件打包在 litellm-1.107.0.data/purelib/ 数据目录下,pip 安装时会将其复制至 site-packages 根目录,即 litellm 包之外;wheel 的 RECORD 清单为这些文件记录了有效哈希,说明它们在发布构建时就已加入,而非后来添加。Python 每次解释器启动都会运行 site-packages 中的 .pth 文件和 sitecustomize.py。Microsoft Security Research 指出,恶意启动文件位于 LiteLLM 应用目录之外,因此“仅在受影响环境启动 Python,就可能激活恶意代码,即使从未导入 LiteLLM 本身”,并且“只移除应用文件可能留下恶意启动组件”。因此,卸载或升级包不是清理,重建环境才是。
入侵如何发生?
LiteLLM 自身披露重建了完整链条,Socket 时间线补充了工作流细节:
- 2026 年 5 月 27 日,提交到公开 LiteLLM-Labs/lite-harness 仓库的配置文件包含某个 LiteLLM Agent Platform 部署的主密钥。错误被发现后,提交被强制推送覆盖,密钥被标为需要撤销,但撤销从未执行。
- 10 月 10 日,来自 69.48.229[.]143 的攻击者使用未撤销主密钥进入 Agent Platform,提取其中配置的 GitHub CLI OAuth 令牌。令牌属于 GitHub 组织所有者账户,权限范围未收缩,因此获得组织内每个仓库的所有者级访问权。
- 当天 22:11 至 22:12 UTC,攻击者向内部仓库 BerriAI/litellm 和 BerriAI/litellm-auto 的短期分支 ci-tmp-a351cc 与 ci-tmp-4d8517 推送提交,各自添加
.github/workflows/cache.yml工作流,使用看似无害的主题“ci: bump cache config”,每次推送均触发。工作流收集 GitHub 令牌,以及组织 Linear 工作区、LiteLLM 部署、Together AI 的 API 密钥,还有 GitHub App 标识符和签名密钥,并发送到两个攻击者控制的 webhook[.]site 端点。运行记录和分支几分钟后被删除。10 月 12 日的第二轮扩大到 Anthropic、OpenAI 和 AWS Bedrock 密钥、Tavily 密钥、GitGuardian 密钥扫描租户密钥、Playwright 存储状态,以及 PostgreSQL 和 Redis 凭据。GitGuardian 租户密钥对防御尤为重要:它是密钥扫描平台本身的凭据,可查看甚至控制原本会揭示这些活动的告警。 - 10 月 21 日 10:08 至 11:08 UTC,攻击者绕过分支保护,将发布流水线源码从 BerriAI/litellm 改向仿冒仓库“Berri-AI/litellm”,在“Berri”和“AI”之间多了一个连字符。发布通常需要授权工程师加上锁定到办公室实体设备的特殊账户批准,但该限制在本周较早时放宽为任意两名工程师。攻击者用一个窃取的维护者令牌触发发布,另一个令牌批准。
- PyPI 于 11:39 UTC 收到 1.107.0,Docker Hub 和 GHCR 镜像于 11:46 跟进,生产与预发布运行记录于 11:53 删除。Upwind 研究人员 Lidor Machluf 于 12:06 报告供应链攻击,PyPI 于 13:23 隔离版本,Docker 标签于 14:20 被移除或重新指向经过验证的干净镜像。
LiteLLM 排除了最初关于 GitHub 令牌通过内部部署日志泄露的假设,目前正在撤销与每个内部系统和供应商平台关联的所有令牌。
攻击流程
从未撤销(5 月 27 日)"] --> B["攻击者使用密钥进入
Agent Platform(10 月 10 日)"] B --> C["提取组织所有者的
GitHub CLI 令牌"] C --> D["ci-tmp-* 分支运行
令牌收集工作流"] D --> E["发布流水线改向
仿冒 Berri-AI 仓库(10 月 21 日)"] E --> F["恶意 1.107.0 发布至
PyPI、Docker Hub 和 GHCR"] F --> G["启动 Hook 将凭据窃取至
litellm[.]dev;后门每小时运行"] style E fill:#f8d7da
攻击者能做什么?
在运行过恶意 wheel 的任何主机上:
- 读取并外传进程所有者可读取的每项凭据:SSH 密钥、Git 配置和令牌、云和 AI provider 密钥、数据库和缓存凭据、环境变量,以及 npm、PyPI、pip、Yarn、Maven、Gradle、Composer、RubyGems 和 Cargo 的包注册表令牌。
- 通过后门每小时重新执行攻击者代码,因此除非重建环境,否则即使被盗凭据轮换,攻击者仍保有访问权。
- 通过收集的 CI 和平台凭据横向移动:维护者级 GitHub 令牌、GitHub App 签名密钥、GitGuardian 扫描租户密钥,以及 LiteLLM 为用户代理的同类上游 API 令牌。
对于项目维护者,影响超出单个版本:攻击者持有 GitHub 组织所有者级访问权十一天,足以读取和修改每个仓库,并从两名拥有维护者权限的工程师处收集密钥。
如果安装过它,该怎么办?
没有可升级到的干净 1.107.0 最终版,它在 PyPI 上不存在。应将安装 1.107.0 视为主机失陷,按以下顺序处理:
- 隔离受影响主机、容器和 CI Runner。停止它们,而不是登录随意检查,因为启动 Python 会重新执行载荷。
- 使用经验证的干净版本从头重建环境(新容器镜像、新虚拟环境、新 CI Runner)。固定最后干净版本
litellm==1.106.3,或在项目发布后使用经过验证的更高版本。不要只执行pip uninstall litellm:启动文件位于包目录外,会继续保留。 - 轮换环境、构建及 CI 能触及的每项密钥:环境变量、SSH 密钥、Git 和 GitLab 令牌、云和 AI provider 密钥、数据库和 Redis 凭据、浏览器存储的凭据,以及窃取器针对的所有生态中的包注册表令牌(npm、PyPI、pip、Yarn、Maven、Gradle、Composer、RubyGems、Cargo)。应假定攻击者已持有它们,而非仅看到过。
- 检查并清理安装来源:10 月 21 日 11:39 至 14:20 UTC 拉取的 CI 缓存、基础镜像和 Docker 摘要,以及可能为下次构建仍固定 1.107.0 的锁文件。
- 如果您与 LiteLLM 组织或其工程师工作流存在关联,检查 GitHub 审计日志中的 ci-tmp-* 分支、已删除工作流运行及任何分支保护变更,并轮换 GitGuardian 租户密钥。
如何检查是否已遭入侵?
公开分析已发布以下指标:
- 包存在情况:
pip show litellm报告版本 1.107.0,或锁文件和镜像摘要固定该版本。PyPI 暴露窗口为 2026 年 10 月 21 日 11:39 至 13:23 UTC;Docker Hub 和 GHCR 窗口为 11:46 至 14:20 UTC。 - 网络:向 litellm[.]dev/healthcheck 的 HTTP POST(域名于 2026 年 10 月 13 日注册),以及连接工作流收集使用的两个 webhook[.]site 外传端点:65a42464-3cfa-4b02-a18c-17a6d7b86f37 和 4da03473-a3e7-4dc2-a087-9c564b4208e1;这些也适用于项目 CI。
- 主机:安装过 wheel 的环境
site-packages目录中的启动文件cook.pth、cook.py、sitecustomize.py,或其他意外.pth、sitecustomize.py、usercustomize.py;运行时标记/tmp/remote_code_loader.lock和/tmp/.pc_once_*;无法解释的、按小时联系远程主机的后台进程。 - GitHub 组织(维护者):名称为 ci-tmp- 加十六进制字符的分支,以“ci: bump cache config”为主题添加
.github/workflows/cache.yml的提交,10 月 10 日和 12 日创建几分钟后即删除的工作流运行,以及 10 月 21 日的分支保护或流水线变更。
时间线
- 2026-05-27:Agent Platform 主密钥被提交到公开 LiteLLM-Labs/lite-harness 仓库;提交被强制推送覆盖,但密钥从未撤销。
- 2026-10-10:攻击者使用密钥,提取组织所有者 GitHub 令牌,并于 22:11 UTC 从 ci-tmp-* 分支运行首个令牌收集工作流。
- 2026-10-12:第二个工作流将收集范围扩大到 AI、云、数据库和密钥扫描凭据。
- 2026-10-13:litellm[.]dev 外传域名注册。
- 2026-10-21:10:08 UTC 发布流水线改向仿冒仓库;1.107.0 于 11:39 到达 PyPI,11:46 到达 Docker;运行记录于 11:53 删除;Upwind 于 12:06 报告攻击;PyPI 于 13:23 隔离版本;Docker 标签于 14:20 清理。
- 2026-10-23:Microsoft Security Research 发布 Python 启动 Hook 分析。
- 2026-10-24:LiteLLM 发布根本原因披露;Socket 发布工作流时间线。
- 2026-10-25:本文发布。
常见问题
PyPI 本身被攻陷了吗?
没有。攻击者使用维护者级 GitHub 凭据,通过 LiteLLM 自身发布流水线推送,因此在研究人员报告前,PyPI 看来上传是合法的。PyPI 在发布一小时四十四分钟后隔离该版本,缩小了窗口,但没有消除窗口。
安装了 1.107.0 但从未导入 LiteLLM,安全吗?
不安全。恶意代码作为 Python 启动文件安装在 LiteLLM 包目录外,因此解释器启动、任何导入之前就会执行。仅安装了该包并运行无关 Python 代码的环境,与使用 LiteLLM 作为 LLM 网关的应用同样暴露。
只卸载包或升级到 1.107.0 之后可以吗?
不可以。卸载移除的是包,而非启动文件;也没有干净的 1.107.0 可升级,PyPI 显示 1.106.3 为最新最终版。应重建环境并固定干净版本,然后轮换凭据。
Docker 镜像和 wheel 一样危险吗?
是的。同一恶意构建于 11:46 UTC 发布到 Docker Hub 和 GHCR,受影响标签直到 14:20 才被移除或重新指向。在该窗口拉取的镜像,包括通过 latest 拉取的镜像,携带相同载荷;缓存摘要仍可能将它们提供给按摘要固定的构建。
为什么发布审批没有阻止攻击?
审批通常来自锁定到实体设备的特殊账户,但该周为加快发布而放宽限制:任意两名工程师即可触发和批准。攻击者使用一个窃取的维护者令牌触发发布,另一个批准,符合放宽后的规则。
这也影响 LiteLLM 的代理虚拟密钥吗?
进程能够读取的一切都应视为已被收集:窃取器收集环境变量、云和 AI provider 凭据,而 LiteLLM 部署正是在这些位置存放上游密钥和数据库配置。应将它们与其他凭据一同轮换,而非推测代码究竟能访问哪些。
窃取器还专门针对 LiteLLM 代理部署。当设置 DATABASE_URL 时,它启动 Python 子进程,使用 Prisma 读取 LiteLLM_CredentialsTable 的 credential_values 字段和 LiteLLM_ProxyModelTable 的 litellm_params 字段,每次查询最多 500 行,因此除环境数据外,还会窃取代理数据库中存储的上游模型凭据。
使用 Ostorlab 扫描仓库、容器镜像和 CI 配置,在重建前识别每个固定 litellm 1.107.0 的环境。
参考资料
- LiteLLM 根本原因披露《2026 年 10 月 21 日安全事件:攻击链》,Oliver Jensen 和 Mateo Wang 撰写,2026 年 10 月 24 日:https://docs.litellm.ai/blog/security-incident-oct-21-2026-attack-chain (2026 年 10 月 25 日核查)
- 公开 LiteLLM-Labs/lite-harness 仓库提交 e10b14a 中泄露的配置文件:https://github.com/LiteLLM-Labs/lite-harness/blob/e10b14a/harnesses/opencode/opencode.json (2026 年 10 月 25 日核查)
- LiteLLM 维护者对最初令牌泄露假设的更正:https://github.com/BerriAI/litellm/issues/47826#issuecomment-6374891275 (2026 年 10 月 25 日核查)
- Microsoft Security Research,《LiteLLM 1.107.0 供应链入侵内幕:通过 Python 启动 Hook 窃取凭据》,2026 年 10 月 23 日:https://www.microsoft.com/en-us/security/blog/2026/10/23/inside-the-litellm-1-107-0-supply-chain-compromise-credential-theft-through-python-startup-hooks/ (2026 年 10 月 25 日核查)
- Socket 对恶意 ci-tmp-* 工作流提交及外传端点的调查:https://socket.dev/blog/litellm-attack-timeline (2026 年 10 月 25 日核查)
- OpenSourceMalware 对 wheel 两条执行路径的分析:https://opensourcemalware.com/blog/litellm-1-107-0-pypi-wheel-contains-a-credential-stealer-and-persistent-python-backdoor (2026 年 10 月 25 日核查)
- The Hacker News 关于泄露主密钥和流水线劫持的报道,2026 年 10 月 24 日,引用 LiteLLM 披露:https://thehackernews.com/2026/10/leaked-litellm-master-key-let-attackers.html (2026 年 10 月 25 日核查)
- The Hacker News 关于 SafeDep、Socket、StepSecurity 和 Upwind 最初报告被入侵包的报道,2026 年 10 月 21 日:https://thehackernews.com/2026/10/litellm-compromised-in-supply-chain.html (2026 年 10 月 25 日核查)
- litellm 的 PyPI 发布历史,显示没有最终版 1.107.0,1.106.3 为最新最终版:https://pypi.org/pypi/litellm/json (2026 年 10 月 25 日核查)
- litellm 的 PyPI 下载统计,过去一周 21,343,835 次下载:https://pypistats.org/packages/litellm (2026 年 10 月 25 日核查)