跳到正文
Hacker News· abhisek·· 12 天前精选AI 评分85

PyPI 上的 LiteLLM 1.107.0 被植入凭据窃取器与远程代码执行后门

Compromised LiteLLM 1.107.0 on PyPI Installs a Credential Stealer and Backdoor

AI 导读

LiteLLM 1.107.0 在 PyPI 发布的 7 个 wheel 均含有凭据窃取器和远程代码执行后门,PyPI 已下架该版本。恶意包向 site-packages 写入 cook.pth、cook.py 和 sitecustomize.py,Python 启动时即使未导入 LiteLLM 也会运行相关代码。

推荐理由

文章通过比对源码、发布标签、构建产物与依赖清单,拆解 LiteLLM 恶意版本的植入方式、自动启动机制和可核对的取证线索。

正文 · AI 翻译

• Oct 21, 2026 • 6 分钟阅读

PyPI 上的 LiteLLM 1.107.0 版本包含一个凭据窃取程序和一个远程代码执行后门。全部七个 wheel(Linux、macOS、Windows)都会将它们作为三个文件安装到 site-packages 中。二者会在主机上的任何 Python 进程启动时运行,即使该进程从未导入 litellm。上游 GitHub 源代码中并不存在它们。PyPI 此后已下架该版本。

1.106.2、1.107.0rc1 和 1.107.0rc2 版本均未受到污染。1.107.0 固定的配套包 litellm-proxy-extras==0.4.110 和 litellm-enterprise==0.1.78 也未受到污染。

攻击的工作方式

安装 litellm==1.107.0 会将三个文件放入 site-packages。Python 每次启动时都会加载其中两个。

  1. cook.pth 导入 cook.py,这是一个凭据窃取程序。它会收集 SSH 密钥、云凭据、CI/CD 密钥、AI 工具令牌、浏览器密码,以及 LiteLLM 代理数据库中的 LLM 提供商密钥。它会加密这些数据并将其发送到 www.litellm[.]dev。
  2. sitecustomize.py 会启动一个后台守护进程。该守护进程每小时从一个 GitHub 文件读取服务器地址,再次运行窃取程序,并从该服务器下载和运行代码。

植入程序是如何进入发布版本的

1.107.0 源码分发版(sdist)中的 pyproject.toml 在 maturin 构建部分多出了一行:

pyproject.toml (litellm-1.107.0.tar.gz)

TOML 6 行

wheel 中的 maturin data = "cook" 设置会将 cook/ 文件夹复制到 litellm-1.107.0.data/purelib/。pip 会将该文件夹安装到 site-packages。

sdist 中省略了 cook/ 文件夹,因此这一行是唯一可见的更改。BerriAI/litellm 中没有任何公开提交包含 data = "cook" 或 cook/ 文件夹。

wheel 中的 RECORD 列出了新增的三个文件:

litellm-1.107.0.dist-info/RECORD

TEXT 4 行

该发布版本与其标签不一致

标签 v1.107.0 指向提交 66c8f5b(06:59 UTC)。其 pyproject.toml 中写着 version = "1.108.0"。SafeDep 通过 blob 哈希将每个 sdist 文件与 Git 树进行了比较。该 sdist 与之后的 main 提交 a8113b0(08:50 UTC)一致,但另有五个文件经过编辑,并包含 cook/ 文件夹。

其中四个经过编辑的文件是 Cargo.toml 文件,各新增了一行 readme = "README.md"。合法的 1.106.2 和 rc2 发布版本也有相同的编辑。第五个是 pyproject.toml,此处与 a8113b0 进行比较:

pyproject.toml (a8113b0 → litellm-1.107.0.tar.gz)

DIFF 11 行

该编辑将版本重新设为 1.107.0,并将配套包固定为 rc2 的值。因此,与 rc2 进行依赖差异对比时,不会显示任何异常。合法的 1.106.2 sdist 与其标签提交 49943cd 一致,唯一例外是 Cargo.toml readme 行。

这些 wheel 是如何构建的

恶意 wheel 与 BerriAI 正常发布流水线的输出完全一致:

  • WHEEL 文件将 maturin 命名为 1.9.4,与合法发布中的版本相同。植入文件具有正确的 RECORD 条目,这表明构建后没有进行过编辑。
  • Zip 时间戳显示这些 wheel 是分别原生构建的:macOS 为 11:20,Linux 为 11:21,Windows 为 11:37 UTC。
  • 在 Windows wheel 中,全部 2,804 个 .py 文件都采用 CRLF 行尾,包括三个植入文件。Linux wheel 中没有任何文件采用这种行尾。在 Windows 上执行启用了行尾转换的 git checkout 会产生这种模式。

没有任何公开的 GitHub Actions 运行构建或发布该版本。SafeDep 检查了 UTC 09:30 至 12:30 之间的全部 539 次运行。UTC 11:50,也就是 PyPI 上传约 10 分钟后,litellm-dispatcher[bot] 发布了 GitHub 版本 v1.107.0。1.106.2 也出现了同样的延迟。PyPI 没有为 1.107.0、1.106.2 或 rc2 提供来源证明。

SafeDep 以中等至较高的置信度评估认为,BerriAI 的私有发布流水线从一个被攻击者修改的 git 源码构建了这些 wheel。攻击者可能使用了被入侵的维护者或机器人凭据、私有分支或镜像,或流水线构建时所引用的版本号。攻击者从其自身机器上使用被盗 PyPI 令牌的说法与现有证据的吻合度较低。只有 BerriAI 的流水线日志才能确认具体原因。

载荷 1:cook.py 中的凭据窃取器

在启动时,Python 会运行 site-packages 中 .pth 文件中以 import 开头的每一行。cook.pth 包含 import cook,因此窃取器会在主机上的每个 Python 进程中运行:应用程序、pip、IDE 语言服务器以及 CI 任务。

cook.py 将约 61 KB 的 Python 代码用一层 exec(zlib.decompress(base64.b64decode('...'))) 进行了包装。解码后的代码以这段配置开头:

cook.py(已解码)

PYTHON 10 行

收集内容

模块目标
sysinfo、netinfo主机名、用户、操作系统、IP 地址、网络设置
browser_pwChromium 保存的密码,使用 profile 主密钥解密(Windows 上使用 DPAPI)。Firefox logins.json 和 key4.db
browser_hist浏览器历史记录
ssh_keys~/.ssh/*
shell_histbash 和 zsh 历史记录,PowerShell PSReadLine,cmd 历史记录
cloud_creds~/.aws/credentials 和 config,Azure profile 和令牌,gcloud 凭据,~/.kube/config、~/.docker/config.json、gh hosts.yml、rclone.conf、~/.netrc
dev_secrets.pem、.key、.pfx、.p12、.pk8、.ppk 文件(位于 $HOME 下),Composer auth.json,FileZilla 已保存的服务器
container_credsKubernetes 服务账户令牌
cicd_secretsGitLab runner config.toml,Jenkins initialAdminPassword 和 master.key,.vault-token,Terraform credentials.tfrc.json,Packer 设置
ai_devtoolsClaude Code、Claude Desktop、Cursor、Windsurf、Copilot、VS Code mcp.json、Gemini CLI、Codex auth.json、Continue、Aider、Goose、opencode、Qwen、Crush、Kiro、Zed、Hugging Face 令牌
env_vars它自身以及其他进程的环境,通过 /proc/<pid>/environ
db_litellm读取 DATABASE_URL 并导出 LiteLLM_CredentialsTable 和 LiteLLM_ProxyModelTable 表,其中保存了 LiteLLM 代理的 LLM 提供商 API 密钥
cloud_metadataAWS 实例元数据服务(IMDSv2,然后是 v1):实例身份和角色凭证
gpg_keys, tls_privkeyGPG 密钥、TLS 私钥

它如何发送数据

  1. 它使用随机生成的 AES-256-CBC 密钥加密 JSON 结果,并用 RSA-OAEP 和嵌入的公钥加密该密钥。
  2. 它将结果打包为 tar.gz(hdr.json、data.bin、key.bin),并通过 POST 请求发送到 www.litellm[.]dev/healthcheck,请求头为 X-Token: XWiA8gZNa7NcX2XRoAEb。
  3. 成功上传后,它会写入 /tmp/.pc_once_72129118c59f5636c0bb,从而每台主机只收集一次。它还会设置 PRIVCOLLECT_ACTIVE=1,以避免在同一进程树中再次运行。

载荷 2:sitecustomize.py 中的后门

Python 在启动时会导入 sitecustomize,因此该文件也会在每个 Python 进程中运行。

sitecustomize.py

PYTHON 5 行

  1. 它对 /tmp/remote_code_loader.lock 加上排他锁,因此每台主机只能运行一个守护进程。
  2. 它调用 fork() 和 setsid(),将标准输入和输出重定向到 /dev/null,并将工作目录切换到 /,以脱离父进程。
  3. Every hour, it:
    1. 从攻击者的 GitHub 仓库读取 domain.txt,并取第一个看起来像域名的行,
    2. 运行其内嵌的窃取程序副本,该副本没有“每台主机一次”的标记,
    3. 下载 http://<domain>/codepy 并使用 exec() 运行它。

攻击者可以通过编辑 domain.txt 将守护进程指向新的服务器。每台受感染的主机都会运行该服务器作为 codepy 返回的内容。

UTC 时间 13:40,GitHub 账户 letters9813 及其仓库返回 404,距离发布约两个小时。后门现在找不到服务器地址,因此什么也不做。在删除之前运行过该守护进程的主机可能已经收到并运行了第二阶段代码。SafeDep 无法恢复该服务器地址。

时间线

所有时间均为 2026-10-21 的 UTC 时间。

时间事件
06:59标签 v1.107.0 提交 66c8f5b 已创建
08:50提交 a8113b0 位于 main,是发布源码的基础
10:44合法的 1.106.2 已上传至 PyPI
11:20 to 11:37构建恶意的 1.107.0 wheels
11:39 to 11:401.107.0 已上传到 PyPI(共 8 个文件)
11:50litellm-dispatcher[bot] 发布 GitHub 版本 v1.107.0
13:40观察到:1.107.0 已从 PyPI 下架,letters9813 账户已删除

入侵指标

网络

指标用途
www.litellm[.]dev, hxxp://www.litellm[.]dev/healthcheck接收被盗数据
HTTP 头 X-Token: XWiA8gZNa7NcX2XRoAEb随每次上传一起发送
raw.githubusercontent[.]com/letters9813/pythonclient-test/main/domain.txt后门在此处读取其服务器地址(账户已删除)
hxxp://<domain>/codepy第二阶段代码下载
来自 Python 进程对 169.254.169.254 的请求AWS 实例凭据盗窃

主机

指标含义
cook.pth, cook.py, sitecustomize.py in site-packages植入程序已安装
/tmp/.pc_once_72129118c59f5636c0bb窃取程序已上传数据
/tmp/remote_code_loader.lock后门守护进程已运行
环境变量 PRIVCOLLECT_ACTIVE=1存在于受感染进程中
分离的 Python 守护进程(父 PID 1,独立会话,工作目录 /)后门循环

文件哈希值(SHA-256)

文件SHA-256
litellm-1.107.0.tar.gz2befe2a79fb4fbbd9a543b5b40b530c8cffa8771bab22b8fb22b2e4ae3b1f819
litellm-1.107.0-cp310-abi3-manylinux_2_28_x86_64.whl462d0c9f67ca522d9e0e4acd245e90b36ce0d5353604a66bb7c43a1ec4a6fcf7
litellm-1.107.0-cp310-abi3-manylinux_2_28_aarch64.whl668169d35b87bf51324080390b1b1c5ab12bd335cfe5f1a99e3689abd5e02ae6
litellm-1.107.0-cp310-abi3-musllinux_1_2_x86_64.whl1bbce8caa94f01c0aaa0b7ddae51553a8a32e1ce53d96d44fe583272aff7ad00
litellm-1.107.0-cp310-abi3-musllinux_1_2_aarch64.whlc2e32d0ce2548aa662c18bf5001911a79fe5b30cf8357132275add02fdcde054
litellm-1.107.0-cp310-abi3-macosx_10_12_x86_64.whl7598727f209d717041db37f7dca271d3a7d328a279890e0e1d55375729aeb86d
litellm-1.107.0-cp310-abi3-macosx_11_0_arm64.whl0aaf7ba346d41ef2f40390436738b001180d5a1c03aa093f121078a9969d9a1a
litellm-1.107.0-cp310-abi3-win_amd64.whl12d4ccc5c6f8d35cf4f2cf233b7f3e418e863e657d81ff5f5fc9e210005b9484

来自 wheel RECORD 的植入文件:

文件SHA-256(URL 安全的 base64)
cook.pthfxkWMucyBwXRVLhSBPGuVGtUOsvX6IYSKbdvUEK5K9s
cook.pyndCjkm-Wo364bPHuIxDZvpMTnMTr7z754u_pUxOQviU
sitecustomize.pyNL7wT-iKydCq4EdWMLFzhoHRW5TyM6yKpG6s9ZaDBfo
  • pypi
  • python
  • 恶意软件
  • 供应链
  • litellm

作者

Kunal Singh

最新内容来自 SafeDep 博客

关注以获取开源安全与工程方面的最新动态和洞察

Background

SafeDep Logo

交付代码。

不是恶意软件。

在你的机器上免费开始使用开源工具。扩展为面向你的组织的统一平台。

来源:Hacker News · safedep.io