就在这两天,Python 生态系统遭遇了一场波及极广的供应链攻击。这次事件的中心是极受欢迎的开源 LLM 代理库LiteLLM,它在被投毒期间正处于每日数百万次下载的高峰期。
反直觉但真实。很多人默认更新软件就是在修漏洞、变安全,但在现实的软件供应链里,这个结论是不成立的,甚至有时候是反过来的。不要假设最新版本是安全的,而要任何版本都可能都不可信,然后通过机制去验证它。
攻击者先拿下上游依赖(PyPI 包),然后在发布版本中植入后门,让开发者在不知情情况下安装,再通过依赖链进入下游所有系统。
LiteLLM 的 1.82.7 和 1.82.8 版本被植入了恶意代码。攻击者在发布的 wheel 包中嵌入后门,通过在 Python 文件中注入隐藏代码并使用 base64 对 payload 进行混淆,从而实现自动执行。更隐蔽的是,通过 .pth 文件的机制,来让得这些代码在 Python 启动的时候便会自动运行。
这次围绕 LiteLLM 的供应链攻击,本质上不是单一漏洞,而是一次典型的软件供应链安全事件。所谓供应链攻击,指攻击者不直接攻击最终用户系统,而是通过污染上游依赖、发布渠道或构建流程,将恶意代码植入被广泛使用的组件中,从而实现“以点控面”的传播效果。这类攻击在开源生态中近年来频繁出现,并已被认为是软件安全中最难防范的一类问题之一。
这次事件涉及 LiteLLM 的两个版本,1.82.7与 1.82.8,这两个版本在 PyPI 上被发现包含恶意代码。LiteLLM 本身是一个用于统一调用多个大模型 API 的中间层库,被大量 AI 应用、Agent 框架以及编排系统依赖,因此其影响面非常广。公开数据中提到其月下载量接近一亿级别,这意味着一旦被污染,传播范围会非常迅速。
攻击的核心载体是一个被植入的.pth文件机制。这种机制属于 Python 的启动加载机制之一,正常情况下用于在解释器启动时自动执行初始化代码。而攻击者正是利用这一特性,将恶意逻辑嵌入其中,使其在任何 Python 进程启动时都会被触发,而不需要显式 import 该库。这一点使攻击具有隐蔽性,因为即使用户没有直接调用 LiteLLM,只要其在依赖链中,就可能被间接触发。
在行为层面,恶意代码的主要目的被描述为凭证窃取与横向扩散。这类后门通常会扫描系统环境变量、配置文件、SSH 密钥、云服务凭证、Kubernetes 配置、CI/CD token、数据库连接信息等敏感数据,并将其收集后外传。由于现代开发环境高度依赖云服务与自动化部署,这些凭证一旦泄露,攻击者可以进一步访问云资源、控制容器集群,甚至在基础设施层面进行持久化驻留。
更值得关注的是其横向移动能力。在容器化和 Kubernetes 环境中,如果攻击进程拥有足够权限,它可能读取集群配置,获取 service account token,并进一步在集群中创建新的 pod 或执行命令,从而扩展控制范围。这种从单机到集群的扩散,是供应链攻击中常见但非常危险的一种演化路径。
从传播机制来看,这类攻击通常依赖两个关键前提,一是依赖链的自动解析机制,二是开发者对第三方依赖的默认信任。现代软件开发大量使用包管理器,例如 pip、npm 等,这些工具会自动解析依赖树并下载远端包,而开发者往往不会逐层审查所有间接依赖。攻击者正是利用这一点,将恶意包嵌入到“看似无害”的依赖中,使其在多个项目中被间接引入。
从历史上看,类似事件不是首次发生了。过去已经出现过多个供应链攻击案例,例如 XZ Utils 后门事件,其攻击者通过长期渗透开源社区,逐步获取维护权限,最终在构建链中植入后门。这类攻击通常具有隐蔽性强、周期长、社会工程成分高的特点,不依赖单一漏洞,而是结合信任机制进行渗透
此外,研究也表明,供应链攻击不仅发生在代码层,也可能发生在模型层、依赖包层、甚至发布渠道层。例如恶意包在 PyPI 或 npm 上被上传,或者官方发布渠道被劫持,甚至下载链接被篡改,都会形成类似风险 。在 AI 生态中,这种风险进一步扩大,因为模型、权重、推理框架、插件系统等都属于“供应链”的一部分。
从防御角度来看,这类事件暴露出几个关键问题。第一是在依赖管理缺乏锁定机制,如果直接使用浮动版本号,例如 pip install -U,会自动升级到最新版本,一旦上游被污染,就会在无感知情况下引入恶意版本。第二是缺乏构建可验证性,例如没有对发布包进行签名验证或哈希校验。第三是运行时权限过高,使得单个库能够访问过多敏感信息。
已有的安全研究和行业实践建议采取多层防护策略。包括固定依赖版本并使用 lock 文件,避免自动升级,使用私有镜像仓库或镜像代理,对依赖进行缓存与审计,启用软件签名验证,以及在运行环境中进行权限隔离。例如容器最小权限原则,限制文件系统访问范围,限制网络访问范围,并对敏感凭证进行动态注入而非明文存储。
首先要知道的是,Python 生态的依赖机制是高度开放的,pip install 默认会从公共源获取包,并且依赖会递归安装,这种设计提升了开发效率,但也带来了攻击面。一旦某个包被投毒,并且进入了你的依赖树,就可能在安装阶段或运行阶段执行恶意代码。因此讨论防护,本质是在减少“信任面”和“执行面”。
另外,运行时监控也被认为是重要手段,例如检测异常网络请求、异常子进程创建、异常文件访问行为等。一些安全团队会在 CI/CD 流程中加入依赖扫描、SCA(Software Composition Analysis)工具,对依赖树进行风险评估。
从更宏观角度看,这次事件反映出开源生态的一种结构性风险,即“信任链过长”。一个项目可能依赖数百个间接依赖,而其中任何一个环节都可能成为攻击入口。随着 AI 应用的复杂度提升,Agent 框架、插件系统、工具调用链不断增加,这种依赖关系会进一步放大攻击面。
很多开发环境和生产环境会赋予依赖过多权限,比如容器以 root 运行,Kubernetes 中的 service account 权限过大,或者 CI 环境可以访问云凭证。如果一个恶意包在运行时获得这些权限,它就可以读取环境变量中的密钥,访问云 API,甚至在集群内部横向移动。
因此权限控制的原则是最小权限原则。对于 Python 服务,尽量避免以 root 用户运行,容器内部使用非特权用户。对于 Kubernetes,要限制 service account 的 RBAC 权限,只授予必要的资源访问权限,例如只读配置,而不允许列出 secrets 或创建 pod。对于 CI/CD 系统,要避免将长期有效的云凭证直接暴露在环境变量中,可以使用短期 token 或者工作负载身份认证机制。
总结来说,这次 LiteLLM 相关事件可以归纳为几个关键点。首先是攻击目标选择具有高价值的基础依赖组件,其次是利用 Python 包机制中的自动执行特性植入后门,再通过凭证窃取与集群扩散实现更大范围的控制,最后通过开源分发渠道完成大规模传播。它本质上不是单点漏洞,而是供应链信任体系被利用的结果。
对于开发者们来说,具备一定的网络安全意识,其实是在为自己的代码和职业生涯建立最后一道减震器了。