昨天下午我像往常一样在开发机上跑编码 agent,直到刷到安全公司 SafeDep 的披露:10 月 21 日挂在 Python 官方包仓库上的 litellm 1.107.0,安装包里有一个模块,专门去翻 Claude Code、Codex、Cursor、Gemini CLI 这些编码 agent 存放钥匙的配置文件,和我的 SSH 私钥躺在同一张清单上。我放下手里的东西,第一件事是去看自己的开发机。
签名没过期,是「有资格签名的人」被偷了。锁版本这条线,从今天起要往前挪一步,挪到发布管道上。
LiteLLM 官方事故报告确认了全过程(10-21):攻击者先拿到三名开发者的命令行登录凭据,来源是一台暴露在公网的内部部署的日志;接着用组织所有者的权限绕过仓库的防呆规矩,把发布流程指向一个仿名仓库,再用第二名开发者的凭据走过审批门。剩下的步骤不用人参与了,官方流水线自己完成了构建、签名、发布,七个平台的安装包全部带毒,Docker 镜像也跟着中招,从上线到下架约两个小时。
我做电力那些年,学到的第一件事是操作票制度:谁签字,谁负责。这次的问题不是流程有缺口,而是审批门防的是流程缺失,防不了持票人本身被攻破。二十年前我们讲信任根,今天很多团队的信任根,其实就是一条跑发布流水线的机器加上几个有权限的人。这个根比我们以为的脆得多。
说回我自己。我每天用 Claude Code 改代码、用 Codex 跑任务,自建的新闻日报流水线每天要调几十个接口、装一堆依赖。我审过自己代码里的每一行,却从来没审过「发布 litellm 的那条管道」,因为在我过去的认知里,版本锁住了,管道就是透明的。这次连停机都不需要,装个包就够了。
这个包的狡猾之处在触发方式:它往 Python 的包目录里放三个文件,任何一个 Python 进程启动时都会自动加载:你装的包、你的包管理器、你的 IDE、你的 CI,一个都跑不掉,哪怕你从来不用 litellm。它偷的东西分成十五类,其中单独一类就叫「AI 开发工具」,点名了十七种编码 agent 的凭据文件;外传地址用的是仿冒官方域名,后门每小时从一个公开代码仓库的文件里读新地址、下载代码执行。想换载荷,攻击者只需要改一个文件。
我最在意的是这个细节:编码 agent 的钥匙权限,比传统凭据宽得多:能发合并请求、能读私有仓库、能调付费接口,可我们一直按「本地配置文件」的规格在管它。我给开发机上的凭据文件做过备份,却没给它做过任何隔离。权限早就升级了,管理口径还停在十年前。不是敌人太聪明,是我们的账本没跟上资产的变化。
cook.pth、cook.py、sitecustomize.py 这三个文件名,Docker 镜像对一遍摘要值,SafeDep 公布了完整的文件哈希,十分钟能查完,现在就能开工。