10月21日,LiteLLM的1.107.0版本出现在PyPI上,带着一个凭据窃取器和一个远程代码执行后门。七个wheel包——Linux、macOS、Windows全在内——把三个文件装进了site-packages。两个载荷在主机上任何Python进程启动时都会运行,哪怕那个进程从未import过litellm。上游GitHub源码里从来没有这些东西。
![]()
PyPI在当天13:23 UTC撤下了这个版本。从发布到移除,中间隔了大约两个半小时。对于一个躺在数千个AI应用依赖树里的包来说,这段时间够长了,Docker镜像已经把它带得更远。LiteLLM在事件报告中确认了这次入侵,列出了补救步骤,并确认GitHub源码是干净的。
装进去的到底是什么
安装litellm==1.107.0,会往site-packages里丢三个文件。其中两个在每次Python启动时执行,这正是它比普通恶意包更麻烦的地方。
- cook.pth只有一行:import cook。Python在启动时会执行site-packages里每个.pth文件的每一行import,于是窃取器在你的应用里、在pip里、在IDE语言服务器里、在CI任务里都跑了一遍。
- cook.py收集SSH密钥、云凭据、CI/CD机密、AI工具令牌、浏览器密码,以及存在LiteLLM代理数据库里的LLM供应商密钥。数据加密后发往www.litellm[.]dev。
- sitecustomize.py启动一个后台守护进程。每小时,这个守护进程从GitHub上的一个文件读取服务器地址,再跑一次窃取器,并从该服务器下载和执行代码。
sdist里没有cook/文件夹,所以源码分发中唯一可见的改动是pyproject.toml里多出的一行。BerriAI/litellm的公开提交里找不到data = "cook",也找不到cook/文件夹。wheel的RECORD列出了这三个新增文件及其大小:cook.pth为12字节,cook.py为22,252字节,sitecustomize.py为25,509字节。
.pth机制是最安静的部分。大多数开发者从不看site-packages,而.pth文件由解释器在任何应用代码之前加载。这意味着窃取器在宿主应用来得及反应之前,就已经拿到了完整的进程环境,包括内存里的东西。sitecustomize.py的手法更老但同样有效:只要它在路径上存在,Python就会自动import它,所以守护进程不需要任何显式import语句就能启动。两个文件合起来,给了攻击者即时外泄和每小时一次的持久回调,既不需要宿主应用配合,也没有改动包的公开API。
植入是怎么进入发布流程的
1.107.0 sdist里的pyproject.toml,在maturin构建段被注入了一行:data = "cook"。maturin的data设置会把一个cook/文件夹复制进wheel内部的litellm-1.107.0.data/purelib/,pip随后把这个文件夹装进site-packages。sdist省略了cook/文件夹,所以这一行是源码分发里唯一可见的改动。审阅者看sdist,只会看到多了一行配置,别的什么都没有。
这招能成,是因为maturin的data设置是正常且有文档的功能,本来用于让基于Rust的Python包把非Python文件打进wheel。攻击者没有发明新的攻击原语,只是用合法构建工具做了工具设计上允许的事,并把载荷藏在sdist里没人看的上层目录。
攻击者是怎么发布的
这部分比载荷本身更该让人睡不着。攻击者持有三名开发者的GitHub CLI凭据。LiteLLM认为攻击者是从一个暴露在互联网上的内部LiteLLM部署日志里拿到的。用一个组织所有者的令牌,攻击者绕过了分支保护,把私有发布工作流指向一个仿冒仓库Berri-AI/litellm。随后攻击者用第二名开发者的凭据通过了审批关卡。官方流水线构建、签名并发布了这些产物。所有本该拦住这件事的检查,跑的都是攻击者控制的输入。
教训不是LiteLLM粗心。教训是发布流水线的强度取决于把守它的凭据,而那些凭据躺在一个本不该从互联网访问到的服务的日志里。如果你的CI日志里有令牌,而你的CI对外可达,你就有同样的问题,只是名字不同。攻击者不需要攻破LiteLLM的源码,他们需要攻破LiteLLM的流程,而流程就是构建流水线本身。
谁受影响
1.106.2、1.107.0rc1、1.107.0rc2是干净的。1.107.0锁定的配套包litellm-proxy-extras==0.4.110和litellm-enterprise==0.1.78也是干净的。Docker Hub和GHCR上的镜像标签v1.107.0、latest、main-latest、main-stable,在10月21日11:46到14:20 UTC之间携带了恶意代码。如果你在这个窗口里拉过其中任何一个标签,把那台主机当作已被入侵处理。
现在该查什么
- 卸载并降级:pip uninstall litellm,然后pip install litellm==1.106.2。
- 在site-packages里找这三个文件:cook.pth、cook.py、sitecustomize.py。存在就删掉。
- 轮换那台主机上可达的每一个凭据:SSH密钥、云厂商密钥、CI/CD机密、AI工具令牌、浏览器密码、LLM供应商密钥。假定窃取器已经把它们全部外泄。
- 检查主机上是否有Python进程在安装到卸载之间启动过。如果有,守护进程有一个小时的时间运行。
- 审计日志,查找发往www.litellm[.]dev的出站连接,以及每小时一次的GitHub文件读取。
为什么这事不止关乎LiteLLM
这次攻击没有利用代码漏洞,利用的是我们对发布流水线的信任。.pth文件手法不新,但在主机上每个Python进程里都跑一遍——包括那些从不碰这个包的进程——是刻意为之,目的是把爆炸半径拉到最大。每小时一次的守护进程让它持久化。凭据窃取覆盖了2026年真正要紧的密钥:云访问、CI/CD和LLM供应商密钥。
对在生产环境跑AI工具链的团队来说,这个教训不太舒服。你依赖来做LLM路由的包,同时也是对你机密访问面最广的包。锁定版本。校验哈希。内部镜像依赖。把高权限包的新版本当作生产主机上的新二进制来对待。在发布清单里加一道lockfile审查,要求任何对持有凭据访问权的包的改动,在上线前都经过第二双眼睛。这道审查的成本是几分钟,跳过的成本是每一台碰过这个包的主机上的全量凭据轮换。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.