摘要
2026年3月24日,全球广泛使用的AI基础设施组件 LiteLLM 在 PyPI 仓库中被发现存在恶意版本。攻击者通过入侵开发者账户,直接向 PyPI 发布了两个被植入后门的版本(1.82.7 和 1.82.8),绕过 GitHub Release 的正常发布流程。
本次攻击是名为 TeamPCP 的威胁行为组织发起的为期五天供应链攻击活动的最新环节。该活动始于 2026年3月19日对 Trivy 的入侵,随后扩散至 npm 生态系统、Aqua Security 内部 GitHub 组织、Checkmarx KICS 以及 OpenVSX 扩展市场。
核心结论: 任何安装了受影响版本的主机、容器、CI/CD 环境或开发者工作站,均应视为完全沦陷。攻击者能够窃取包括 LLM API Key、云服务凭证、Kubernetes 配置在内的所有敏感信息,并可能通过 Kubernetes 横向移动能力将攻击扩散至整个集群。
第一章:事件概述
1.1 基本信息
|--------------|------------------------------|
| 项目 | 详细信息 |
| 发现日期 | 2026年3月24日 |
| 受影响版本 | 1.82.7 和 1.82.8 |
| 发布时间 | 2026年3月24日(两个版本同一天发布) |
| 安全版本 | 1.82.6 及以下版本 |
| 发布方式 | 绕过 GitHub Release,直接推送至 PyPI |
| PyPI 当前状态 | 恶意版本已被删除,项目被隔离 |
| 月下载量 | 约 9500 万次 |
| GitHub Stars | 约 4 万 |
| 开发者/维护者 | BerriAI 团队 |
1.2 什么是 LiteLLM
LiteLLM 是一个广泛使用的 Python 库和代理层,为开发者提供统一的接口来调用超过 100 种大型语言模型(LLM)提供商的服务,包括 OpenAI、Anthropic、Azure OpenAI、Cohere、Hugging Face 等。
核心用途:
-
统一 API 接口:通过 OpenAI 兼容的接口调用不同 LLM 提供商
-
API Gateway:提供企业级的 LLM 代理服务,支持负载均衡、缓存、限流等功能
-
成本管理:统一跟踪和限制 LLM API 调用成本
由于其便利性和功能完整性,LiteLLM 已成为 AI 基础设施的核心组件,被大量企业、开发者和 AI 应用所依赖。
1.3 本次攻击的特殊性
这不是一次简单的包名抢注(typosquatting)攻击,而是对真实、广泛使用的官方项目的直接入侵。
攻击者并未创建名称相似的伪造包,而是通过某种方式获取了 LiteLLM 维护者的 PyPI 发布权限,直接向官方项目中植入恶意代码。这种攻击方式的隐蔽性和危害性远超传统供应链攻击,因为:
-
受害者会信任官方包名
-
代码审计可能仅关注 GitHub 源码,而忽略 PyPI 上的实际发布包
-
依赖自动更新的环境会在毫不知情的情况下被感染
第二章:攻击时间线完整还原
2.1 第一阶段:Trivy 入侵(3月19日)
2026年3月19日,攻击者利用被入侵的凭证,对 Aqua Security 的 Trivy 项目执行了以下操作:
|------------------|------------------------------------------|
| 操作 | 详情 |
| 发布恶意版本 | trivy v0.69.4 |
| 污染 GitHub Action | 强制推送 trivy-action 中 77 个标签中的 76 个到恶意提交 |
| 替换 Action 标签 | 替换所有 7 个 setup-trivy 标签 |
| 扩散至容器镜像 | 恶意构建被推送到 GHCR、ECR Public、Docker Hub |
| 扩散至包管理器 | 恶意构建被推送到 deb、rpm 包以及 get.trivy.dev |
恶意行为分析:
-
恶意的
trivy-action和setup-trivy会转储 GitHub Runner.Worker 内存 -
抓取常见凭据位置(环境变量、配置文件等)
-
使用 AES 和 RSA 加密窃取的数据
-
将数据泄露到拼写错误域名
scan.aquasecurtiy.org(注意拼写错误,应为 aquasecurity) -
备用方案:如果直接泄露失败且存在有效 GitHub Token,则创建公开仓库
tpcp-docs上传被盗数据
扩展攻击: 同一天,攻击者还在以下仓库中注入了恶意工作流:
-
aquasecurity/tfsec -
aquasecurity/traceeshark -
aquasecurity/trivy-action
这表明攻击者正在积极重用被攻破的身份,将单一攻击扩展为跨仓库的链式入侵。
2.2 第二阶段:npm 蠕虫扩散(3月20日 - 3月22日)
到 3月20日,攻击活动已超出单一 GitHub Action 的范围。攻击者开始向 npm 生态系统推送一种自我传播的蠕虫,影响范围包括:
|-------------------------------|--------|
| 组织/命名空间 | 受影响包数量 |
| @EmilGroup | 28 个包 |
| @opengov | 16 个包 |
| @teale.io/eslint-config | 多个版本 |
| @airtm/uuid-base32 | 1.0.2 |
| @pypestream/floating-ui-dom | 2.15.1 |
蠕虫行为分析:
-
从受感染环境中窃取 npm 发布令牌
-
解析每个令牌有权限发布的包
-
自动升级补丁版本(如 1.0.1 → 1.0.2)
-
获取原始 README 文件以保持外观一致
-
注入恶意负载后重新发布
横向移动升级: 到 3月22日,同一 C2 基础设施开始提供针对 Kubernetes 的攻击脚本:
-
检查系统时区和语言环境
-
伊朗系统: 部署
host-provisioner-iranDaemonSet,运行kamikaze容器,删除主机文件系统并强制重启节点(破坏性攻击) -
非伊朗系统: 部署
host-provisioner-std,挂载主机根文件系统,安装持久后门
GitHub 组织入侵: 3月22日晚,攻击者使用 GitHub 账户 Argon-DevOps-Mgt:
-
在
aquasecurity/trivy-plugin-aqua上创建并删除幽灵分支 -
约七小时后,入侵 Aqua Security 内部 GitHub 组织
aquasec-com -
重命名 44 个仓库,统一添加前缀
tpcp-docs-和描述 "TeamPCP Owns Aqua Security"
2.3 第三阶段:Checkmarx 与 OpenVSX 入侵(3月23日)
3月23日,攻击活动进入新的供应商发布链:
|-----------|-----------------------------|
| 目标 | 受影响组件 |
| Checkmarx | kics-github-action v1.1 |
| Checkmarx | ast-github-action v2.3.28 |
| OpenVSX | ast-results 2.53.0 |
| OpenVSX | cx-dev-assist 1.7.0 |
技术特征:
-
KICS 负载使用
setup.sh窃取器,C2 域名为checkmarx.zone -
备用方案:使用受害者的
GITHUB_TOKEN创建docs-tpcp仓库 -
与之前攻击模式完全一致,证明是同一攻击组织
2.4 第四阶段:LiteLLM 被入侵(3月24日)
3月24日,攻击者将目标锁定为 LiteLLM,同时发布两个恶意版本:
|--------|------------|-------------------------------------------|--------------------|
| 版本 | 发布时间 | 恶意负载位置 | 触发方式 |
| 1.82.7 | 2026-03-24 | litellm/proxy/proxy_server.py 第128-139行 | import litellm 时执行 |
| 1.82.8 | 2026-03-24 | proxy_server.py + litellm_init.pth | 任何 Python 启动自动执行 |
关键发现:
-
两个版本均绕过 GitHub Release,直接推送至 PyPI
-
GitHub 源码中不包含恶意代码,污染仅发生在 wheel 构建/发布阶段
-
这意味着仅审查 GitHub 源码无法发现此攻击
第三章:技术深度分析
3.1 恶意负载完整解析
3.1.1 信息收集阶段(332行Python代码)
恶意代码会系统性地收集以下类别信息:
|------------|-------------------------------------------------------------------------------------------------------------------------------------------------------|
| 类别 | 具体目标 |
| 系统信息 | hostname, whoami, uname, IP地址, 路由表 |
| 环境变量 | 完整的 printenv 输出(包含所有 API Keys、Secrets、Tokens) |
| SSH 凭证 | id_rsa, id_ed25519, id_ecdsa, id_dsa, authorized_keys, known_hosts, config |
| Git 凭证 | .gitconfig, .git-credentials |
| 云平台凭证 | AWS: ~/.aws/credentials, IMDS role credentials, Secrets Manager, SSM GCP: application_default_credentials.json, gcloud configs Azure: ~/.azure/ 目录树 |
| Kubernetes | ~/.kube/config, /etc/kubernetes/*.conf, 所有 namespace 的 Secrets |
| Docker | ~/.docker/config.json |
| 数据库 | .pgpass, my.cnf, redis.conf, .mongorc.js |
| 加密货币钱包 | Bitcoin (wallet.dat), Ethereum keystores, Solana validator keypairs, Cardano keys, Litecoin, Dogecoin, Zcash, Dash, Monero, Ripple 及各币种配置文件 |
| SSL/TLS 私钥 | /etc/ssl/private/, Let's Encrypt .pem 和 .key 文件 |
| CI/CD | terraform.tfvars, .gitlab-ci.yml, Jenkinsfile, .drone.yml |
| Shell 历史 | bash_history, zsh_history, mysql_history, psql_history, redis_history |
| .env 文件 | 递归扫描 /home, /root, /opt, /srv, /var/www, /app, /data 等目录,深度最多 6 层 |
3.1.2 数据加密与外泄阶段
收集数据 → 写入临时文件
↓
openssl rand → 生成 32-byte AES-256 会话密钥
↓
openssl enc -aes-256-cbc -pbkdf2 → 加密数据
↓
openssl pkeyutl -encrypt → 用 RSA-4096 公钥加密 AES 密钥
↓
打包为 tpcp.tar.gz
↓
POST 到 https://models.litellm.cloud/
请求头: X-Filename: tpcp.tar.gz
技术细节:
-
AES-256-CBC 加密数据内容
-
RSA-4096 加密会话密钥(公钥硬编码在恶意代码中)
-
混合加密方案确保即使通信被截获,也无法解密数据
3.1.3 持久化与横向移动
本地持久化机制:
|-------------|-----------------------------------------|-------------------|
| 组件 | 路径 | 说明 |
| 后门脚本 | ~/.config/sysmon/sysmon.py | 主要后门程序 |
| systemd 服务 | ~/.config/systemd/user/sysmon.service | 实现开机自启 |
| 服务显示名 | "System Telemetry Service" | 伪装成系统遥测服务 |
| C2 轮询地址 | https://checkmarx.zone/raw\ | 每50分钟轮询一次 |
| Kill Switch | 响应包含 "youtube.com" 则停止活动 | 紧急停止机制 |
| 初始延迟 | 5分钟(time.sleep(300)) | 避开即时检测 |
| 二进制路径 | /tmp/pglog | 伪装成 PostgreSQL 进程 |
Kubernetes 横向移动:
检测 /var/run/secrets/kubernetes.io/serviceaccount/token 存在
↓
枚举集群所有节点
↓
对每个节点创建特权 Pod(alpine:latest 镜像)
↓
Pod 名称:node-setup-{node_name}
↓
部署到 kube-system namespace
↓
请求 hostPID、hostNetwork,privileged: true
↓
挂载宿主机根文件系统到 /host
↓
chroot /host 安装相同后门
3.2 1.82.8 版本的额外风险:Fork Bomb
1.82.8 版本中的 litellm_init.pth 文件存在一个严重 bug:
-
.pth文件中的代码使用subprocess.Popen执行自身 -
这导致子进程再次触发
.pth文件执行 -
形成指数级递归调用 → Fork Bomb
-
可导致中招机器的 CPU 和内存资源迅速耗尽,系统崩溃
这一"特性"虽然可能是代码编写不当的副作用,但客观上增加了攻击的破坏性和检测难度。
第四章:IOC 完整清单
4.1 文件哈希
|------------------|--------------|--------------------------------------------------------------------|
| 文件名 | 大小 | SHA256 |
| litellm_init.pth | 34,628 bytes | 71e35aef03099cd1f2d6446734273025a163597de93912df321ef118bf135238 |
4.2 文件系统路径
|-----------------------------------------|-----------------------|
| 路径 | 说明 |
| litellm_init.pth | 1.82.8 中的恶意启动钩子 |
| ~/.config/sysmon/sysmon.py | LiteLLM 持久化脚本路径 |
| ~/.config/systemd/user/sysmon.service | LiteLLM 用户 systemd 单元 |
| /tmp/pglog | C2 下载的第二阶段载荷 |
| /tmp/.pg_state | 信标使用的状态文件 |
4.3 网络 C2 域名
|-------------------------------------------------------------|------------------------|------------------------|
| 域名 | 用途 | 备注 |
| models.litellm.cloud | LiteLLM 数据泄露端点 | 非官方域名 |
| checkmarx.zone/raw | 后续 C2 轮询端点 | 在 LiteLLM 和 KICS 攻击中出现 |
| scan.aquasecurtiy.org | Trivy 攻击中的数据泄露 | 拼写错误域名 |
| tdtqy-oyaaa-aaaae-af2dq-cai.raw.icp0.io | CanisterWorm ICP 容器 C2 | npm 蠕虫使用 |
| championships-peoples-point-cassette.trycloudflare.com | Cloudflare 隧道 C2 | 相关活动 |
| investigation-launches-hearings-copying.trycloudflare.com | Cloudflare 隧道 C2 | 相关活动 |
| souls-entire-defined-routes.trycloudflare.com | Cloudflare 隧道 C2 | 相关活动 |
4.4 Kubernetes 特征
|-------------------------|-------------------|
| 指标 | 说明 |
| node-setup-* | 特权 Pod 命名模式 |
| kamikaze | 伊朗目标破坏性容器名称 |
| provisioner | 标准后门部署容器名称 |
| host-provisioner-iran | 伊朗目标 DaemonSet 名称 |
| host-provisioner-std | 标准目标 DaemonSet 名称 |
4.5 受影响的包完整列表
Python 包
|---------|----------------|
| 包名 | 受影响版本 |
| litellm | 1.82.7, 1.82.8 |
Docker 镜像
|-----------------------------------|------------------------|
| 镜像 | 受影响版本 |
| aquasec/trivy | 0.69.4, 0.69.5, 0.69.6 |
| ghcr.io/aquasecurity/trivy | 0.69.4, 0.69.5, 0.69.6 |
| docker.io/aquasec/trivy | 0.69.4, 0.69.5, 0.69.6 |
| public.ecr.aws/aquasecurity/trivy | 0.69.4, 0.69.5, 0.69.6 |
GitHub Actions
|------------------------------|------------------------|
| Action | 受影响版本 |
| aquasecurity/setup-trivy | 0.2.0 至 0.2.6 |
| aquasecurity/trivy-action | 所有不以 v 开头的标签(除 0.35.0) |
| Checkmarx/kics-github-action | v1.1 |
| Checkmarx/ast-github-action | v2.3.28 |
OpenVSX 扩展
|---------------|--------|
| 扩展 | 受影响版本 |
| ast-results | 2.53.0 |
| cx-dev-assist | 1.7.0 |
npm 包(部分列表)
|-------------------------------|--------------|
| 包名 | 受影响版本 |
| @pypestream/floating-ui-dom | 2.15.1 |
| @leafnoise/mirage | 2.0.3 |
| @opengov/ppf-backend-types | 1.141.2 |
| @airtm/uuid-base32 | 1.0.2 |
| @teale.io/eslint-config | 1.8.9-1.8.16 |
| @emilgroup/setting-sdk | 0.2.1-0.2.3 |
| @emilgroup/partner-portal-sdk | 1.1.1-1.1.3 |
| ... | 共约 60+ 个包受影响 |
第五章:应急处置手册
5.1 快速检测(5分钟内完成)
步骤一:检查 Python 包版本
pip show litellm | grep Version
# 或
pip list | grep litellm
步骤二:搜索恶意 .pth 文件
# 在用户目录下搜索
find ~/.local -name "litellm_init.pth" 2>/dev/null
# 在系统 site-packages 中搜索
find $(python3 -c "import site; print(':'.join(site.getsitepackages()))") -name "litellm_init.pth" 2>/dev/null
步骤三:搜索持久化后门
# 搜索 sysmon 相关文件
find / -name "sysmon.py" 2>/dev/null
find / -name "sysmon.service" 2>/dev/null
# 检查用户 systemd 服务
ls -la ~/.config/systemd/user/
步骤四:检查网络连接
# 检查到恶意域名的连接
ss -tunap | grep -E "models.litellm.cloud|checkmarx.zone"
5.2 清理与恢复(15分钟内完成)
清理恶意包:
# 卸载恶意版本
pip uninstall litellm -y
# 删除所有 .pth 文件
find $(python3 -c "import site; print(':'.join(site.getsitepackages()))") -name "litellm_init.pth" -delete 2>/dev/null
清理持久化后门:
# 删除 sysmon 后门
rm -rf ~/.config/sysmon/
# 停止并删除 systemd 服务(如果存在)
systemctl --user stop sysmon.service 2>/dev/null
rm -f ~/.config/systemd/user/sysmon.service
清理缓存:
# 清理 pip 缓存
pip cache purge
# 清理 uv 缓存(如果使用)
rm -rf ~/.cache/uv
回退到安全版本:
# 安装安全版本
pip install litellm==1.82.6
# 或锁定版本范围
echo "litellm>=1.82.0,<1.82.7" >> requirements.txt
5.3 凭据轮换(必须执行)
即使未发现感染痕迹,只要曾经安装过受影响版本,也必须轮换以下凭据:
|---------------|---------------------------------------------------------------------------|
| 类别 | 具体操作 |
| LLM API Keys | OpenAI、Anthropic、Azure OpenAI、Cohere 等所有 API Key 重新生成 |
| 云服务凭证 | AWS Access Key/Secret Key、GCP Service Account Key、Azure Service Principal |
| SSH 密钥 | 删除旧公钥,生成新密钥对并更新到所有服务器 |
| Git 凭证 | 撤销所有 Personal Access Token,重新生成 |
| 数据库密码 | 所有数据库密码重置,更新应用程序配置 |
| Kubernetes 配置 | 轮换 Service Account Token,更新 kubeconfig |
| CI/CD 密钥 | 更新 GitHub Actions Secrets、GitLab CI Variables 等 |
| 环境变量中的任何密钥 | 所有通过环境变量传递的敏感信息 |
5.4 深度排查(适用于生产环境)
Kubernetes 环境:
# 检查可疑 Pod
kubectl get pods -A | grep -E "node-setup|kamikaze|provisioner"
# 检查特权 Pod
kubectl get pods -A -o json | jq '.items[ ] | select(.spec.containers[ ].securityContext.privileged==true)'
# 检查 kube-system 中的异常 Pod
kubectl get pods -n kube-system
# 检查 ServiceAccount 权限
kubectl get clusterroles -A | grep -E "admin|cluster-admin"
审计日志分析:
-
检查异常的秘密访问记录
-
检查异常的 Pod 创建记录
-
检查 API Server 的可疑调用
网络层面:
-
在防火墙/网关层面封禁所有恶意域名
-
检查出站流量日志中是否存在对恶意域名的访问
-
检查是否有异常的大量出站流量(数据外泄特征)
第六章:长期防护建议
6.1 依赖管理策略
|--------|------------------------------------------------|-----|
| 措施 | 说明 | 优先级 |
| 锁定版本 | 使用 requirements.txt 或 poetry.lock 固定所有依赖版本 | 最高 |
| 禁用自动更新 | CI/CD 中禁止使用 pip install --upgrade | 高 |
| 版本范围限制 | 使用 >=1.82.0,<1.82.7 而非 >=1.82.0 | 高 |
| 私有仓库镜像 | 将可信包镜像到私有仓库,禁止直接访问 PyPI | 中 |
6.2 供应链安全
|----------------|----------------------------------|-----|
| 措施 | 说明 | 优先级 |
| 源码 vs Wheel 校验 | 构建时比对 PyPI wheel 与源码构建产物的 SHA256 | 高 |
| 依赖扫描 | 使用 SCA 工具持续扫描依赖中的已知漏洞 | 高 |
| SCFW 防护 | 部署 Supply-Chain Firewall 拦截已知恶意包 | 中 |
| PyPI 安全通知 | 订阅 PyPI 安全公告,及时获取漏洞信息 | 中 |
6.3 终端与服务器安全
|-----------------|-------------------------------------------|-----|
| 措施 | 说明 | 优先级 |
| 审计 .pth 文件 | 定期扫描 site-packages 中的 .pth 文件,>1KB 需重点检查 | 高 |
| 检测异常 systemd 服务 | 监控用户级 systemd 服务的新增 | 中 |
| 审计 /tmp 可执行文件 | 定期扫描 /tmp 目录中的可执行文件 | 中 |
| EDR 部署 | 部署端点检测与响应系统,监控异常进程行为 | 高 |
6.4 Kubernetes 安全基线
|------------------------|------------------------------------------------|-----|
| 措施 | 说明 | 优先级 |
| 禁止特权容器 | 使用 Pod Security Standard 禁止 privileged: true | 高 |
| 限制 hostPID/hostNetwork | 通过准入控制器限制敏感主机命名空间访问 | 高 |
| 最小化 ServiceAccount | 禁止默认 ServiceAccount,限制 RBAC 权限 | 高 |
| 审计日志启用 | 启用 Kubernetes API 审计日志,监控异常操作 | 中 |
| 网络策略 | 使用 NetworkPolicy 限制 Pod 出站流量 | 中 |
6.5 网络层防护
在防火墙/网关/代理层封禁以下域名:
models.litellm.cloud
checkmarx.zone
scan.aquasecurtiy.org
*.icp0.io
*.trycloudflare.com
6.6 开发流程改进
|-------|-------------------------------------------|
| 措施 | 说明 |
| 代码审计 | 不仅审计 GitHub 源码,也审计实际发布的包 |
| 双人审核 | PyPI 发布权限设置双人审核机制 |
| 发布自动化 | 使用自动化流程从 GitHub Release 自动发布到 PyPI,避免手动操作 |
| 完整性校验 | 在 CI 中增加包完整性校验步骤 |
第七章:风险评级与影响评估
7.1 风险评级矩阵
|------|-------|--------------------------|
| 维度 | 评级 | 说明 |
| 影响范围 | ⭐⭐⭐⭐⭐ | 月下载量 9500 万,覆盖全球大量 AI 应用 |
| 隐蔽性 | ⭐⭐⭐⭐⭐ | 绕过 GitHub 源码审计,仅污染发布包 |
| 利用难度 | ⭐⭐ | 自动触发,无需用户交互 |
| 破坏性 | ⭐⭐⭐⭐⭐ | 可窃取所有凭据、横向移动、破坏系统 |
7.2 综合评级:极高(Critical)
7.3 潜在影响评估
对企业的影响:
-
AI 业务核心密钥泄露,可能导致服务中断或滥用
-
云资源被恶意使用,产生大量费用
-
Kubernetes 集群沦陷,生产环境数据泄露
-
供应链污染,可能通过 CI/CD 传播至下游系统
对开发者的影响:
-
个人凭据泄露(SSH Key、Git Token)
-
加密货币钱包被盗
-
开发环境被持久化后门
第八章:总结
8.1 事件总结
本次 LiteLLM 供应链攻击事件是一次典型的开源生态信任链攻击。攻击者通过入侵开发者凭证、投毒构建流程、滥用发布权限,成功在多个主流开源项目中植入后门,具备高度的隐蔽性、传播性与破坏性。
攻击者通过以下方式实现了大规模入侵:
-
入侵路径多样化:从 Trivy 开始,逐步扩展到 npm、GitHub 组织、Checkmarx,最终影响 LiteLLM
-
技术手段成熟:混合加密、多阶段载荷、Kubernetes 横向移动
-
隐蔽性极强:绕过 GitHub Release,仅在 PyPI 发布污染版本
-
破坏性全面:从凭据窃取到系统破坏,覆盖完整攻击链
附录
附录A:参考链接
附录B:版本对照表
|---------|------|----------------------|
| 版本 | 状态 | 说明 |
| ≤1.82.6 | ✅ 安全 | 最后干净版本发布于 2026-03-22 |
| 1.82.7 | ❌ 恶意 | 代码注入 proxy_server.py |
| 1.82.8 | ❌ 恶意 | 额外包含恶意 .pth 文件 |