1. 先搞清楚 LiteLLM 网关这次到底出了什么事
LiteLLM 是一个把 OpenAI、Anthropic、通义、DeepSeek 等多家模型统一成 OpenAI 兼容接口的开源网关,很多团队拿它当内部大模型入口。这次 CVE-2026-42208 的问题出在 1.81.16 到 1.83.7 这个版本区间:网关在处理Authorization: Bearer请求头时,把里面的值直接拼进了 SQL 查询,没有做参数化,也没有做校验。攻击者只要能访问到你的 LiteLLM 代理端口,构造一个畸形的 Bearer 值,就可能绕过认证、把恶意语句带进 PostgreSQL 后端。
受影响的不只是聊天接口,POST /v1/chat/completions、POST /v1/embeddings以及所有需要校验 API key 的 endpoint 都在风险面上。换句话说,只要你的 LiteLLM 实例暴露在公网、又落在那个版本区间,就值得立刻排查。这篇不聊 POC 细节,只讲两件运维真正要做的事:怎么快速确认自己中招没有,以及怎么把入口收敛、配置加固,让这类"请求头直连数据库"的路径彻底断掉。
适合谁看:自建 LiteLLM 网关的运维、安全同学,以及用统一 Key 通道管理多家模型 API 的开发者。下面所有命令和配置都可以直接复制改路径使用。
2. 用 TaoToken 统一 Key 通道做前置收敛
排查之前先想清楚一件事:这次漏洞的触发点是"网关自己解析并信任了请求头里的凭证"。如果你的架构里,客户端是直接拿着各家模型的原始 Key 去请求 LiteLLM,那网关就成了唯一的信任边界,一旦它出问题,后端数据库和上游 Key 全暴露。
更稳的做法是把凭证入口收敛到一层统一通道。我这边用的是 TaoToken(官网 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ),它把多家模型的调用统一成一套 Key 和 API 通道,LiteLLM 只跟这一层打交道,不再直接持有散落的原始凭证。这样即使网关版本有风险,攻击面也被压到"网关到统一通道"这一段,而不是"网关到你的数据库 + 到所有上游厂商"。
具体到这次加固,TaoToken 的价值有三个:
一是入口收敛。客户端只认 TaoToken 的 Key,LiteLLM 的config.yaml里上游指向统一 API 地址https://taotoken.net/api,不再配置一堆厂商原始 Key,减少凭证泄露面。
二是版本排查期间可以平滑切换。你升级 LiteLLM 需要停机窗口,这段时间可以把流量先切到统一通道直连,业务不中断。
三是审计清晰。统一通道的调用日志能对上 LiteLLM 的请求,出问题时定位是哪条链路被打了畸形头,比翻一堆厂商后台快得多。
需要提前准备的:一个 TaoToken 账号、一个可用的 API Key、以及你 LiteLLM 实例的部署方式(Docker 还是裸机 pip 装)。Key 在控制台生成,地址是 https://taotoken.net/console ,生成后先别急着写进配置,下面会讲怎么放才安全。
3. 可复制的版本自查与 config.yaml 加固骨架
3.1 三步确认你的 LiteLLM 版本是否在风险区间
先确认版本。Docker 部署的话:
# 查看正在运行的 LiteLLM 容器镜像版本 docker ps --format '{{.Names}}\t{{.Image}}' | grep -i litellm # 进入容器确认实际安装版本 docker exec -it <你的容器名> pip show litellm | grep -i version裸机 pip 部署的话:
pip show litellm | grep -i version # 或者 python -c "import litellm; print(litellm.__version__)"拿到版本号后对照判断:
| 版本区间 | 状态 | 动作 |
|---|---|---|
| < 1.81.16 | 不受影响 | 保持观察,建议仍升级 |
| 1.81.16 ~ 1.83.7 | 受影响 | 立即加固或升级 |
| > 1.83.7 | 已修复 | 确认升级来源可信 |
如果输出落在 1.81.16 到 1.83.7 之间,别慌,先做临时加固再安排升级。升级命令:
pip install --upgrade "litellm>1.83.7" # Docker 方式则拉取新镜像后重建容器 docker pull ghcr.io/berriai/litellm:main-latest3.2 config.yaml 关键配置骨架
下面这份骨架的重点是:上游统一指向 TaoToken,数据库连接信息不写在明文配置里,请求头校验交给网关自身和前置层双重把关。
model_list: - model_name: gpt-4o litellm_params: model: openai/gpt-4o api_base: https://taotoken.net/api api_key: os.environ/TAOTOKEN_API_KEY - model_name: claude-sonnet litellm_params: model: anthropic/claude-sonnet-4 api_base: https://taotoken.net/api api_key: os.environ/TAOTOKEN_API_KEY general_settings: master_key: os.environ/LITELLM_MASTER_KEY database_url: os.environ/DATABASE_URL # 关闭不必要的请求头透传,降低畸形头进入查询路径的概率 forward_client_headers_to_llm_api: false litellm_settings: drop_params: true set_verbose: false几个要点解释一下。api_key和database_url都用os.environ/引用环境变量,配置文件里不出现明文,这样即使配置被读到也拿不到真实凭证。forward_client_headers_to_llm_api: false是关键,它阻止客户端请求头被原样转发,减少畸形Authorization值流到下游的机会。master_key也走环境变量,别硬编码。
环境变量这样设:
export TAOTOKEN_API_KEY="你的TaoToken Key" export LITELLM_MASTER_KEY="一个足够随机的管理密钥" export DATABASE_URL="postgresql://user:pass@db-host:5432/litellm"3.3 数据库侧的最小权限收口
就算网关被打了,也别让注入语句能随便跑。给 LiteLLM 用的数据库账号只授必要的权限:
-- 只给业务表读写,不给 DDL 和超级权限 GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO litellm_user; REVOKE CREATE ON SCHEMA public FROM litellm_user; ALTER ROLE litellm_user NOSUPERUSER NOCREATEDB NOCREATEROLE;这一步配合前面的统一 Key 通道,等于把"凭证入口"和"数据库权限"两个面同时收窄。
4. 验证请求与成功结果
配置改完,重启 LiteLLM,然后做两件验证:确认网关能正常走 TaoToken 通道,以及确认畸形请求头不再触发异常查询。
先验证正常调用:
curl -X POST http://127.0.0.1:4000/v1/chat/completions \ -H "Authorization: Bearer $LITELLM_MASTER_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-4o", "messages": [{"role": "user", "content": "ping"}] }'预期返回是标准的 OpenAI 格式 JSON,choices里有内容,说明 LiteLLM 到 TaoToken 的链路通了。如果返回 401,检查master_key环境变量有没有生效;返回 500 且日志里有数据库报错,检查DATABASE_URL。
再验证畸形头被挡住。构造一个带特殊字符的 Bearer 值:
curl -X POST http://127.0.0.1:4000/v1/chat/completions \ -H "Authorization: Bearer test' OR '1'='1" \ -H "Content-Type: application/json" \ -d '{"model":"gpt-4o","messages":[{"role":"user","content":"ping"}]}'加固后预期结果是直接返回 401 或 403,且 LiteLLM 日志里不会出现把该字符串拼进 SQL 的记录。你可以同时开着日志观察:
docker logs -f <你的容器名> | grep -i "authorization\|sql\|error"如果看到的是认证失败而不是数据库查询异常,说明请求头校验这一层起作用了。升级到 1.83.7 以上版本后,同样的请求也会被参数化处理,不再有注入路径。
最后确认统一通道侧的调用记录。登录 TaoToken 控制台 https://taotoken.net/console ,在调用日志里应该能看到刚才那次正常ping的记录,模型、时间、消耗都对得上。这一步是确认"网关到统一通道"这段链路真实生效,而不是本地缓存糊弄过去了。
5. 本篇常见错排查
报错一:ModuleNotFoundError: No module named 'litellm'多半是虚拟环境没激活,或者 pip 装到了别的 Python 下。用which python和which pip确认两者指向同一环境,再重装。
报错二:升级后启动报database_url is required说明环境变量没传进容器。Docker 部署要在docker run或 compose 里显式-e DATABASE_URL=...,光在宿主机 export 容器读不到。
报错三:调用返回 401 但 Key 明明是对的先确认请求头格式是Authorization: Bearer <key>,中间有空格。再确认master_key和客户端用的 Key 一致。如果走的是 TaoToken 通道,确认api_base是https://taotoken.net/api,别多写或少写路径。
报错四:日志里出现大量invalid authorization header这可能是有人在扫你的端口。检查 LiteLLM 是否暴露在公网,建议只监听内网或加一层反向代理做来源限制。同时确认forward_client_headers_to_llm_api已设为false。
报错五:数据库连接数被打满注入尝试或异常请求可能触发大量查询。除了升级,给数据库连接池设上限,并在前置层加请求频率限制。LiteLLM 侧可以调litellm_settings里的并发参数。
报错六:升级后模型名对不上新版本可能调整了模型映射。对照model_list里的model_name和客户端请求的model字段,确保一致。走 TaoToken 通道时,模型名按统一通道支持的写法填。
6. 把入口收敛这件事做到底
这次 CVE-2026-42208 暴露的核心问题不是某一个函数写错了,而是"网关直接信任了外部请求头里的凭证"。版本升级能修掉这个具体漏洞,但架构上的收敛才是长期解法。把上游凭证统一到 TaoToken 这类通道,LiteLLM 只做协议转换和路由,不再持有散落的原始 Key,数据库账号只给最小权限,请求头不做无脑透传——这几条叠起来,下次再出类似问题时,你的爆炸半径会小很多。
排查动作建议固化成例行检查:每周跑一次版本确认命令,把 LiteLLM 版本、数据库账号权限、config.yaml里的forward_client_headers_to_llm_api状态对一遍。升级窗口安排在低峰期,升级前先把流量切到统一通道直连,业务不中断。
需要生成和管理统一通道的 Key,去 https://taotoken.net/api-keys ;接入细节和参数说明看文档 https://taotoken.net/doc ;如果你在跑长期编码或 Agent 类任务,想用更稳定的通道方案,可以了解 Coding Plan https://taotoken.net/coding-plan 。验证模型连通性时,直接用模型对话页 https://taotoken.net/chat 发一条消息最快。