pip install 是新的攻击面:LiteLLM 事件给 AI 创业者的三个教训

TL;DR 一行 pip install litellm 就能把你机器上的 SSH 密钥、云凭证和所有 API Key 发送给攻击者。月下载 9700 万次的 LiteLLM 在 3 月 24 日被植入后门,50 万台机器中招。本文还原事件、提供自查 prompt、分析三个创业者需要认真对待的教训。


昨天晚上刷 Twitter 的时候,看到 Andrej Karpathy 发了一条帖子。标题用了 “Software horror”,内容确实配得上这个词:一个每月被下载 9700 万次的 Python 库,在 PyPI 上被替换成了带后门的版本。安装它的那一刻,机器上的 SSH 密钥、AWS/GCP/Azure 云凭证、Kubernetes 配置、所有环境变量里的 API Key、Git 凭证、Shell 历史记录、加密货币钱包,全部被打包加密发送到攻击者控制的服务器。

这条帖子拿到了 2.5 万个赞和 1.2 万个收藏。

我看完之后做的第一件事,是让我的 AI Agent 检查自己的项目有没有中招。结果:在一个闲置项目的虚拟环境里,找到了 litellm 1.82.5。安全版本,但离被感染的 1.82.7 只差两个小版本号。如果那天我恰好运行了一次 pip install --upgrade,这篇文章的开头就会是另一个故事。

发生了什么

LiteLLM 是 AI 开发者中最常用的 Python 库之一,核心功能是统一调用各家大模型 API:OpenAI、Anthropic、Google、Mistral,一个接口全部搞定。GitHub 超过 4 万星,2000 多个下游包依赖它。

2026 年 3 月 24 日 UTC 10:39,一个名为 TeamPCP 的黑客组织用窃取的 PyPI 发布令牌,推送了 LiteLLM 1.82.7 和 1.82.8 两个恶意版本。这两个版本从未经过 GitHub 代码审查,直接绕过正常发布流程上传到 PyPI。

恶意版本中包含一个叫 litellm_init.pth 的文件。.pth 是 Python 的一个冷门机制:放在 site-packages 目录里的 .pth 文件会在每次 Python 解释器启动时自动执行。不需要 import litellm,不需要调用任何函数。只要这个包存在于你的虚拟环境中,同一环境里跑的 Flask、Jupyter、pytest 全都会触发恶意代码。

恶意载荷分三个阶段。第一阶段收割凭证:SSH、云平台、K8s、数据库、加密钱包、.env 文件,用 AES-256 加密后通过伪装域名外泄。第二阶段检测 Kubernetes 环境,如果存在,就利用 ServiceAccount 在每个节点上部署特权 Pod,实现横向移动。第三阶段安装 systemd 服务做持久化后门,持续轮询远程服务器下载更多恶意载体。

恶意版本在 PyPI 上存活了约 5.5 小时。

发现过程充满讽刺。FutureSearch 的 Callum McMahon 在 Cursor 编辑器里使用了一个 MCP 插件,这个插件间接依赖 litellm。恶意 .pth 文件在每次 Python 启动时触发,子进程又触发同一个 .pth,形成指数级的 fork bomb,直接把机器内存撑爆。Karpathy 的评价是:“如果攻击者没有 vibe code 这个攻击,它可能好几天甚至好几周都不会被发现。“攻击者用 AI 写的恶意代码质量太差,反而救了大家。

攻击链:安全工具反成突破口

更值得关注的是攻击路径。这不是一次孤立事件,而是一条精心设计的三级跳。

3 月 19 日,TeamPCP 攻陷了 Trivy,一个被数千家企业使用的开源漏洞扫描器。3 月 23 日,利用从 Trivy 窃取的凭证,攻陷了 Checkmarx 的 KICS GitHub Action(另一个代码审计工具)。3 月 24 日,因为 LiteLLM 的 CI/CD 流程中使用了被污染的 Trivy,攻击者从中提取了 PyPI 发布令牌,然后直接往 PyPI 推送了带毒版本。

安全扫描器本身成了攻击载体。Wiz 安全研究员 Gal Nagli 的评价是:“开源供应链正在形成连锁崩塌,被攻破的凭证成为下一次攻击的弹药。”

据 vxunderground(与攻击者直接接触的安全研究组织)确认,仅 LiteLLM 这一次攻击就导致约 50 万台机器的凭证被窃取,总数据量约 300GB。TeamPCP 声称正在利用这些凭证勒索多家数十亿美元级别的公司。

他们留下的话是:“TeamPCP is here to stay. Long live the supply chain.”

为什么 AI 创业者需要特别紧张

传统 Web 项目的 .env 文件里可能有数据库密码、一两个第三方 API Key。AI 项目的 .env 文件长这样:

OPENAI_API_KEY=sk-...
ANTHROPIC_API_KEY=sk-ant-...
GOOGLE_AI_API_KEY=AIza...
AZURE_OPENAI_KEY=...
AWS_ACCESS_KEY_ID=AKIA...
AWS_SECRET_ACCESS_KEY=...
PINECONE_API_KEY=...
LANGCHAIN_API_KEY=...

一个典型的 AI 创业项目,.env 里的 API Key 密度是传统项目的三到五倍。

而 LiteLLM 的设计初衷就是做 LLM API 的统一网关。它存在的意义就是集中管理所有模型 API Key。攻击者选择这个目标不是随机的。这是精准打击:攻陷一个包,就能拿到一家公司调用所有大模型的全部凭证。

还有一个容易被忽略的传染路径:transitive dependency(传递依赖)。你可能从来没有手动执行过 pip install litellm,但你用的 DSPy、MLflow、Open Interpreter,或者某个 Cursor 的 MCP 插件,替你装了。LiteLLM 被 2000 多个包当作依赖项。browser-use 项目官方在事件当天发了声明,确认 v0.12.3 受影响。

现在就自查:给你的 Agent 一个 Prompt

如果你在用 Claude Code、Cursor、ChatGPT 或者任何 AI 编程助手,可以直接把下面这段 prompt 复制过去,让它帮你检查:

我需要你帮我检查当前机器是否受到 2026年3月24日 LiteLLM PyPI 供应链攻击
(版本 1.82.7 / 1.82.8)的影响。请逐步执行并报告结果:

1. 检查全局和所有虚拟环境中的 litellm 版本:
   - 运行 pip show litellm 和 pip3 show litellm
   - 搜索所有 .venv 和 venv 目录中的 litellm:
     find ~ -path "*/site-packages/litellm" -type d 2>/dev/null
   - 对找到的每个实例检查版本号

2. 搜索恶意 .pth 文件:
   - find ~ -name "litellm_init.pth" 2>/dev/null
   - 检查所有 Python site-packages 目录中是否有可疑 .pth 文件

3. 检查持久化后门:
   - ~/.config/sysmon/sysmon.py 是否存在
   - systemctl status sysmon(Linux)或 launchctl list | grep sysmon(macOS)
   - 是否有异常的后台 Python 进程

4. 如果在 Kubernetes 环境中:
   - kube-system 命名空间是否有 node-setup-* 异常 Pod

5. 扫描依赖树中的间接引用:
   - 检查所有 requirements.txt、pyproject.toml、Pipfile
   - 列出所有直接或间接依赖 litellm 的包

6. 评估 API Key 暴露面:
   - 列出 .env 文件位置(不输出内容)
   - 统计环境变量中含 KEY、TOKEN、SECRET、PASSWORD 的条目数量

对每一步给出"安全/存在风险"的明确判断,最后给出总体评估和建议的下一步行动。

如果检查发现了 1.82.7 或 1.82.8 版本,假设所有凭证已经泄露,立即执行:

  1. 轮换所有凭证:.env 中的每一个 API Key、数据库密码、云平台凭证
  2. 清除恶意文件:删除 litellm_init.pth,卸载受感染版本
  3. 检查持久化:删除 ~/.config/sysmon/ 目录和 sysmon 服务
  4. 审计 K8s:如果在 Kubernetes 环境中,检查并删除 node-setup-* Pod
  5. 锁定版本:在 requirements.txt 中固定 litellm==1.82.6 或更早的干净版本

教训一:你的依赖树就是你的攻击面

这次事件最让人不安的地方不是 LiteLLM 本身被攻破,而是传染路径。

你装了 dspy,dspy 依赖 litellm>=1.64.0。pip 解析依赖时拉取最新兼容版本。如果那个时间窗口恰好落在 3 月 24 日 UTC 10:39 到 16:00,你就中招了。你甚至不知道 litellm 存在于你的环境中。

这个问题在 AI 领域尤其严重。AI 项目的依赖树普遍比传统 Web 项目更深更宽。一个典型的 LangChain 项目动辄几百个传递依赖。每一个依赖都是一次信任决策,而大多数人从来没有意识到自己在做这个决策。

Twitter 上有一个虚构但精准的帖子,写的是一位 Series C 创业公司安全副总裁的视角。他提到:团队两年前就锁定了所有依赖版本,但有人在二月份为了用一个新功能把 litellm 的版本锁定去掉了。requirements.txt 里的一行改动,没有经过代码审查。然后他批准了一个 34 万美元的紧急凭证轮换项目。这个场景虽然虚构,但它描述的决策链条在每一家快速迭代的创业公司里都在发生。

对于创业者来说,实际的行动建议:运行 pip-audit 扫描已知漏洞,用 poetry.lockuv.lock 锁定版本哈希值,在 CI/CD 中加入依赖安全检查步骤。这些工具一直存在,只是大多数 AI 创业团队从来没用过。

更激进一点的做法是减少依赖本身的数量。这就引出了第二个教训。

教训二:Karpathy 的 “yoink” 模式

Karpathy 在那条 2.5 万赞帖子的结尾写了一段话:

Classical software engineering would have you believe that dependencies are good (we’re building pyramids from bricks), but imo this has to be re-evaluated, and it’s why I’ve been so growingly averse to them, preferring to use LLMs to “yoink” functionality when it’s simple enough and possible.

“yoink” 在英语口语里是"顺手拿走"的意思。Karpathy 用它描述一种新的依赖管理策略:对于功能足够简单的外部库,不要 pip install,而是让 LLM 直接生成等效的实现代码,放在你的项目内部。

这个思路不是安全层面的修修补补。它是一个更根本的架构哲学转变。

传统软件工程的假设是:代码复用通过共享库实现,pip install 是获取功能的默认方式。这个假设建立在两个前提上。第一,写代码很贵,能用现成的就不自己写。第二,共享库经过社区审核,质量有保证。

这两个前提在 LLM 时代都在动摇。

写代码的成本正在急剧下降。让 Claude 生成一个 HTTP 重试逻辑、一个 YAML 解析器、一个简单的 rate limiter,可能只需要 30 秒和几百个 token。相比之下,引入一个外部库意味着一个新的维护者信任链、一棵可能很深的传递依赖树、一个未来可能被攻破的攻击面。

社区审核的假设在这次事件中被彻底击穿。LiteLLM 有 4 万 GitHub 星,有 SOC2 认证(Delve 审计),有完善的 CI/CD 流程。所有这些都没有阻止恶意版本通过 PyPI 绕过一切安全机制上传。因为攻击者拿到了 PyPI 发布令牌,代码审查、PR 审批、CI 检查,全部失效。攻击发生在所有人盯着的地方下面一层。

我自己在维护一个 AI 驱动的个人助手系统时,scripts 目录下有十几个 Python 脚本。昨天排查完后意识到,其中一些轻量级的依赖完全可以用 LLM 生成的本地实现替代。不是所有依赖都适合 yoink。复杂的加密库、数据库驱动、需要持续跟进安全更新的组件,当然还是应该用正式维护的包。但那些"只是为了省写 20 行代码"而引入的库,值得重新评估。

这是一个更大趋势的信号。当代码生成成本趋近于零,“依赖是砖块"的隐喻开始失效。每一块砖都可能是特洛伊木马。如果你能在 30 秒内自己造一块完全透明的砖,为什么要从一个无法验证的供应链里拿?

教训三:API Key 管理不能再停留在 .env 文件

这次事件暴露了 AI 创业公司的一个结构性盲区。

想一下这个场景。你的 AI 创业项目有一个 Python 虚拟环境,里面装了 LiteLLM 做模型路由。同一个环境的 .env 文件里有 OpenAI、Anthropic、Google 的 API Key,有 Stripe 的支付密钥,有数据库凭证。这些凭证全部以明文形式存在于同一个进程可达的空间里。一个被攻破的依赖就能一次性全部读取。

这是一个架构问题,不是一个"小心一点就行"的问题。

鸭哥(AI Builder Space 社群)在同一天的分析中提到,1Password 上个月发布了 Unified Access,把人类用户、AI Agent 和机器身份放进同一套凭证治理体系。这个产品方向的出现不是巧合。当 AI Agent 越来越多地代替人类执行操作时,Agent 的凭证需要和人类的凭证一样被严格管理:最小权限、定期轮换、独立隔离。

早期创业团队可能用不上企业级的 secrets manager,但有几个方向值得现在就开始做。把 API Key 从 .env 文件迁移到系统密钥链或者 secrets manager(哪怕是 dotenvx 这样的轻量方案)。给每个服务、每个环境用独立的 Key。设置消费限额和告警,大多数 API 提供商都支持。定期轮换凭证。

在"先跑起来再说"的创业节奏里,这些往往是第一批被跳过的事情。LiteLLM 事件是一个提醒:跳过的代价,可能是在某个周二的早上发现所有凭证都在别人手里。

最后

昨天排查完自己的项目后,我做了三件事。在全局 shell 配置里加了 export LITELLM_TELEMETRY=False,关闭所有 litellm 实例的遥测。把那个闲置项目的 .venv 整个删了。给自己的工具链做了一次依赖审计,标记出所有可以用 LLM 生成替代的轻量依赖。

这次事件里,LiteLLM 的维护者同样是受害者,他们的 PyPI 发布令牌是通过被污染的 Trivy 安全扫描器窃取的。真正的问题在信任链本身。

AI 工具链让构建速度快了一个数量级。但这个速度有一部分是借来的:每一个 pip install 背后是一条看不见的信任链,链上任何一个环节断裂,速度瞬间变成负债。LiteLLM 事件之后,我开始重新理解 Karpathy 说的 yoink:当 LLM 能在 30 秒内生成等效代码时,少引入一个依赖就是少一个无法控制的风险敞口。对 AI 创业者来说,这可能是一种被严重低估的竞争力。


参考来源

如果这篇文章对你有帮助,欢迎请我喝杯咖啡,支持我继续创作更多内容。

Buy me a coffee