LiteLLM 连中三发:大模型网关为什么成了密钥金库的入口

9 月 2 日,CISA 把 BerriAI LiteLLM 的第三个漏洞 CVE-2026-59822(认证缺陷)拉进了 KEV 目录——已知被利用漏洞目录。加上 5 月的 CVE-2026-42208(SQL 注入)和 6 月的 CVE-2026-42271(命令注入),LiteLLM 在四个月里连中三发,而且三个都在野外被实际利用。这不是某个冷门组件被扫到了,而是一个 5.8 万 star、被大量团队当「大模型 nginx」用的网关,成了攻击者偷上游 API key 的入口。

LiteLLM 是什么,为什么它天生是攻击面

LiteLLM 的定位是 LLM 网关:你把 OpenAI、Anthropic、Azure、Bedrock、vLLM 这些上游的 key 都交给它,它对外统一暴露一个 OpenAI 格式的 /v1/chat/completions,负责路由、负载均衡、限流、预算追踪、guardrail 和日志。一句话,它是所有模型调用流量的咽喉。

问题就出在这。它不像普通业务服务那样只握着「自己的」数据,它握着的是你所有云厂商的 LLM API key。一个部署在内网或公网上的 LiteLLM 实例,本质上是一个密钥金库:打穿它,等于同时打穿了 OpenAI、Anthropic、Azure 的账单。

部署形态很简单:

litellm --config config.yaml   # 默认监听 4000 端口

三样东西构成了它的核心资产,也构成了攻击面:

  1. master key:环境变量 LITELLM_MASTER_KEY,是访问代理全部能力的总钥匙。不设这个变量,代理默认无任何鉴权——谁能连到 4000 端口,谁就能白嫖你的模型额度,还能直接调管理接口。
  2. virtual keys/key/generate 给每个用户/团队发的子 key,带预算和速率上限。/key/info/key/delete/key/update 是它的管理端点。
  3. config.yamlmodel_list 里每个模型的 litellm_params 藏着真实的 api_keyapi_base。预算追踪走 Postgres + Prisma,密钥元数据也落在这里。

顺带说一句,LiteLLM 现在的核心是 Rust 写的,外面包一层 Python SDK,两者之间有进程边界和序列化开销。这个架构本身不是漏洞,但它解释了命令注入为什么危险:Rust core 和 Python 侧之间的参数传递,一旦有字段能落进 subprocess / Command::new,执行上下文就是代理进程自己的权限。

认清这个结构,下面三个 CVE 就好理解了。

三个 CVE 逐一拆

CVE-2026-42208:预算追踪层的 SQL 注入(5 月进 KEV)

LiteLLM 的 spend tracking 和 key 管理依赖数据库查询。SQL 注入发生在 key 查询、用户查询、预算统计这条链路上。攻击者一旦能构造恶意的查询参数,就能绕过预算校验,甚至直接把数据库里的 virtual key 和 master key 读出来。

这类注入最典型的入口是那些「按字段过滤」的查询——按 user、team、model 名过滤 spend 记录的地方,参数拼接进了 SQL。对攻击者来说,SQLi 在这里的回报比普通 Web 应用高得多:表里存的是密钥和账单,不是普通的业务数据。

CVE-2026-42271:命令注入(6 月进 KEV)

命令注入通常藏在「把配置值传给子进程」的路径上。LiteLLM 现在的核心是 Rust 写的,Python SDK 和 Rust core 之间有进程边界;自定义 provider、custom_llm_provider、或者是某些把模型参数拼进 shell 的调用链,都是经典的命令注入点。

对这类漏洞,攻击者不需要拿到 master key 就能开火:只要某个配置字段能落进 subprocess / Command::new 的参数,就能让代理进程以运行者的身份执行命令。而代理进程通常以 root 或高权限容器身份跑,因为它要读配置、写日志、连上游。

CVE-2026-59822:认证缺陷(9 月 2 日进 KEV,最新)

这是最新一个,也是 FreeBuf 那句「黑客正顺着 LiteLLM 偷你的大模型密钥」的直接来源。认证缺陷这一类,最典型的表现是:某些端点没挂在鉴权中间件后面,或者 master key 和 virtual key 的校验逻辑存在旁路。

LiteLLM 的认证层覆盖的端点很多——/v1/*/key/*/user/*/team/*/spend/*/health。只要其中一条路由漏了鉴权,攻击者就能在没 key 的情况下访问管理接口。这类漏洞最要命的地方在于:它不需要任何前置条件。SQLi 可能还要碰运气猜参数,命令注入要找到拼接点,但认证旁路只要命中一个漏网的端点,/key/info 直接吐给你所有 virtual key。

第四个没进 KEV、但同样危险的向量:SSRF

严格说 SSRF 不是这三个 CVE 里的,但它和「密钥集中」这个主题绑定得最紧,值得单独拎出来。LiteLLM 的 config.yaml 里,每个模型的 litellm_params 有两个字段:api_keyapi_baseapi_base 决定请求打到哪个 URL 上。

这天然就是个 SSRF 温床:如果攻击者能控制模型配置——比如通过某个管理接口新增一个「自定义模型」,把 api_base 指到 http://169.254.169.254/latest/meta-data/,代理就会替它请求云元数据服务。即便拿不到 master key,只要能写 config 或者利用认证旁路新增模型,就能让 LiteLLM 变成内网探测的跳板。

再叠加一个更阴的玩法:把 api_base 指到内网某个没鉴权的服务(Redis、K8s API、内部 LLM 推理端点),借网关的身份去打内网。对部署了 LiteLLM 的团队,这条链路的价值不在于「SSRF 本身」,而在于网关通常被部署在网络分区里比较靠里的位置——它够得着很多应用够不着的内网资产。

攻击链:从暴露端口到密钥失窃

把三个漏洞串起来,就是一条完整的攻击链,每个阶段都有对应的动作:

Step 1 — 发现。攻击者扫公网上的 4000 端口,或者在内网横向时撞到部署了 LiteLLM 的主机。指纹很好认:GET /health/liveliness/health/readiness 返回典型的 LiteLLM JSON,/ui 是管理界面。

Step 2 — 认证旁路。打 CVE-2026-59822,或者干脆撞上「没设 LITELLM_MASTER_KEY」的裸奔实例——这类实例在真实环境里多到离谱,因为文档里的快速上手示例默认就是不带 key 起服务。

Step 3 — 枚举密钥。拿到访问权后,GET /key/info 列出所有 virtual key 及其对应的 model、spend、上限;GET /user/infoGET /team/info 摸清组织结构和预算。

Step 4 — 窃取上游 key。要么读 config.yaml 里的 api_key/api_base,要么直接通过代理转发调用上游——账单记在受害者头上。更隐蔽的做法是 SQLi / 命令注入直接拖库,把 master key 和所有上游 key 一次性带走。

Step 5 — 变现。偷来的 OpenAI/Anthropic key 转手倒卖,或者直接用受害者额度跑自己的任务(挖矿式消耗、批量内容生成、搭代理)。大模型 key 的「损耗」比云主机更难察觉,因为账单只在月底对账时才看得出来。

防御:三条硬规则

规则一:master key 是必选项,不是可选项。 起服务前先设 LITELLM_MASTER_KEY,用强随机值。检查部署有没有裸奔:

# 检查代理进程是否带着 master key 启动
ps aux | grep litellm
docker inspect <container> --format '{{.Config.Env}}' | tr ',' '\n' | grep -i master_key

规则二:端口别裸奔。 LiteLLM 默认绑 0.0.0.0:4000,公网部署等于把密钥库挂到门口。要么绑定内网地址,要么前面套反代只留白名单:

# 绑定回环 / 内网网卡
litellm --config config.yaml --host 127.0.0.1 --port 4000
# 或容器内只映射到宿主机内网
docker run -p 192.168.1.10:4000:4000 ...

排查当前有没有暴露:

ss -tlnp | grep 4000

看到 0.0.0.0:4000 就说明公网可达,赶紧改。

规则三:virtual key 最小权限 + 轮换。 每个应用一个 virtual key,只授予它需要的 model 和预算上限,别把 master key 到处发。上游 key 一旦怀疑泄露,立刻在云厂商控制台轮换——LiteLLM 里存的只是引用,真正的止血在 OpenAI/Anthropic 那边。

一次到位的自查清单,照着一遍过,五个问题全绿才算安全:

  1. LITELLM_MASTER_KEY 设了没?值是不是强随机?
  2. 4000 端口绑的是回环/内网,还是 0.0.0.0
  3. /key/info 这种管理端点,不带头能不能访问?(curl -s http://localhost:4000/key/info 试试,能出数据就是裸奔)
  4. config.yaml 里有没有明文 api_key
  5. 有没有监控上游账单的异常调用量?

我的做法

我自己跑 LiteLLM 只用于内网开发和自用,几条底线:

  1. 永远回环 + 反代。代理只绑 127.0.0.1:4000,对外走 Caddy/Nginx 加一层 Basic Auth 或 IP 白名单。公网直连 4000 这种事一次都不干。
  2. config.yaml 里不放明文上游 key。用环境变量引用(os.environ/OPENAI_API_KEY),避免配置文件被拖走时连带密钥。
  3. 开审计日志。LiteLLM 的 callback 日志会记每次调用的 key、model、token 数。定期 grep 出异常的 key 用量突增,比月底对账单早一个量级发现泄露:
grep -E '"user":|"spend":' litellm.log | tail -200

大模型网关这层,我见过太多团队把它当「又一个微服务」来部署,结果忘了它手里攥着的是所有云厂商的钥匙。三个 KEV 漏洞不是巧合,而是「密钥集中 + 攻击面大 + 默认配置宽松」三个条件叠加的必然。如果你已经在生产上用 LiteLLM,今天就去查一遍 master key 和端口绑定——这比任何新功能都值得先做。

⚠️ 网络安全免责声明

本文内容仅供技术研究与安全学习之用。文中描述的漏洞分析、攻击链拆解和代码示例均基于公开披露的安全研究,旨在帮助开发者理解攻击原理、提升安全意识和防御能力。

请勿将本文所述技术用于任何未经授权的安全测试、渗透攻击或非法用途。任何因滥用本文信息而造成的法律后果,由使用者自行承担,与本文作者无关。

如发现系统安全漏洞,请通过合法渠道向相关厂商或平台报告,共同维护网络安全生态。