LLM 网关被攻破:LiteLLM 三个漏洞如何偷走 provider key
一个只做认证、不做角色检查的配置端点,让低权限用户拿到管理员、读出 /etc/passwd,再把 provider key 送到攻击者服务器。
一句话结论:LLM 网关把“所有模型的 key”收拢到一处,省掉了每个应用各自管凭据的麻烦,也把风险集中到了一个进程上。Check Point 在 LiteLLM 1.77.7 上找到的两组漏洞,刚好演示了这条路径有多短:一个只做认证、不做角色检查的配置端点,让任意登录用户改掉运行时配置,进而读任意文件、接管管理员、执行远程代码;另一条链则利用“客户端自带凭据”功能,把网关里配置的 provider key 直接转发到攻击者的服务器。
披露:本文编译自 Check Point Research《When LLM Gateways Go Wrong: Findings from LiteLLM》(2026-10-13)。研究针对 LiteLLM v1.77.7,漏洞已在 v1.83.9 修复;CVE 与 GHSA 编号以原文为准。本文未独立复现,代码片段为原文节选与整理,PoC 中的域名、密钥、路径均为演示值。
一、为什么 LLM 网关是整套系统的钥匙串
LLM 网关的位置很特殊:它夹在应用和一家或多家模型供应商之间。应用不再直接调模型 API,而是把请求交给网关,由网关转发到对应的后端。
在这个位置上,网关通常集中做这些事:
- 供应商抽象(一套接口对接多家模型)
- 凭据管理(provider key 只存在网关里)
- 请求路由、限流、用量统计、日志
- 失败回退、多供应商负载均衡
- 按配置选择模型
这带来的好处是应用侧不用碰 key;代价是网关进程成了所有 key 的集合点。它被攻破,或者它的管理面被绕过,损失不是“一个应用的一条 key”,而是“整套系统在所有供应商那里的身份”。
1.1 先看三条链
低权限用户
└─ POST /config/update(只认证,不查角色)
├─ 改 UI_LOGO_PATH → 任意文件读
├─ 改 UI_USERNAME / UI_PASSWORD → 管理员接管
└─ 注册 pass-through 端点 → 从 S3 加载并执行代码
任意已认证用户
└─ POST /chat/completions { user_config: { api_base: 攻击者 } }
└─ 网关带着默认 header 里的 provider key 发请求 → key 泄露
两条链的共同点:都把“调用者可控的输入”变成了“服务端自己的行为”。
二、漏洞一:/config/update 只查“你是谁”,不查“你能不能”
LiteLLM 的代理暴露了一个管理端点 POST /config/update,用于在运行时修改配置:环境变量、模型列表、代理的通用设置。问题出在它少了一个检查。
2.1 缺的是角色检查
在 LiteLLM 的其他管理端点里,代码会显式验证调用者是不是 PROXY_ADMIN。原文拿 /invitation/new 做了对比:
# 安全的写法:先认证,再查角色
if user_api_key_dict.user_role != LitellmUserRoles.PROXY_ADMIN:
raise HTTPException(status_code=400, detail="not allowed")
而 /config/update 只挂了通用的 user_api_key_auth,没有再检查角色:
@router.post(
"/config/update",
dependencies=[Depends(user_api_key_auth)], # 只做认证
include_in_schema=False,
)
async def update_config(config_info: ConfigYAML):
# 缺少:if user_role != PROXY_ADMIN: raise ...
await proxy_config.save_config(new_config=config)
2.2 UI token 的分类只看一个字段
user_api_key_auth 会把授权委托给 common_checks。这个函数先判断 token 是“UI 会话”还是“API key”,判断依据只有一个:team_id 是不是 litellm-dashboard。
而任何用户登录 LiteLLM 的 Web UI 时,后端都会签发一个临时的 API key,并把它挂到 litellm-dashboard 这个特殊 team 上:
"team_id": "litellm-dashboard", # UI 登录签发的 key 都带这个
于是:只要你能登录 UI,你的 token 就会被归类为 ui。
2.3 前缀匹配把 /config/update 放了进来
被归类为 ui 之后,授权走的是 _is_ui_route(),而不是更严格的 API 路由检查。ui_routes 列表里有一项 /config——原本大概只是想允许 UI 读配置。
但 _is_ui_route() 用的是 startswith:
any(route.startswith(allowed_route) for allowed_route in allowed_routes)
/config/update 正好以 /config 开头,于是通过了检查。
前缀匹配是这类漏洞的常客:授权表写的是“允许 /config”,实现用的是 startswith,于是所有以 /config 开头的路径都被放行。修法不是把 /config 改成 /config/——那只是把洞挪到 /config/xxx——而是按精确路由或“方法 + 路径”匹配,并给管理端点单独维护一张表。
2.4 结果:任何登录用户都能改运行时配置
这三步叠起来,任何已认证用户——包括只有 Internal User 基线角色的账号——都能调用 POST /config/update。原文对影响的描述是:任意文件读取、管理员账号接管、通过 pass-through 端点执行远程代码。
这不是一个“需要管理员误操作”的漏洞,而是一个低权限用户就能触发的权限提升。
三、从“改配置”到读文件、当管理员、跑代码
有了“能改环境变量和通用设置”这个原语,后面三条链都很直接。
3.1 任意文件读:UI_LOGO_PATH
/config/update 接受 environment_variables,会把键值解密后写进 os.environ。其中一个变量 UI_LOGO_PATH 控制 /get_image 端点读哪个文件。
POST /config/update
{
"environment_variables": {
"UI_LOGO_PATH": "/etc/passwd"
}
}
然后请求 GET /get_image,服务端直接 FileResponse(logo_path),把 /etc/passwd 当图片返回。
能读 /etc/passwd,就能读配置文件、部署凭据、其他服务的 token。 原文的 PoC 返回了完整的 passwd 内容,content-type 还标着 image/jpeg。
3.2 管理员接管:UI_USERNAME / UI_PASSWORD
同一套环境变量注入,还能改掉 UI 的登录凭据。/login 直接从环境变量读用户名和密码,匹配成功就授予 PROXY_ADMIN:
ui_username = os.getenv("UI_USERNAME", "admin")
ui_password = os.getenv("UI_PASSWORD", None)
...
user_role = LitellmUserRoles.PROXY_ADMIN
于是攻击者先注入自己的用户名密码,再用它登录,就成了代理管理员。原文的截图显示,登录后拿到的是内置 admin 账号的 JWT。
3.3 RCE:pass_through_endpoints + s3://
LiteLLM 支持 pass-through 端点,可以把请求代理到外部服务,也可以加载自定义 adapter。target 支持 s3:// 和 gcs://——以这两个前缀开头时,LiteLLM 会把远程 Python 文件下载下来,用 importlib 执行:
spec = importlib.util.spec_from_file_location(module_path, local_file_path)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module) # 顶层代码在此执行
攻击者只需要在 S3 放一个 Python 文件,顶层写一句 os.makedirs("/tmp/litellm-pwned"),再通过 /config/update 注册成 pass-through 端点。请求一处理,目录就被创建——代码执行确认。换成反弹 shell 或窃取凭据,只是载荷不同。
3.4 三条链的共同点
读文件、接管管理员、RCE 看起来是三个洞,其实共用一个原语:能写环境变量和通用配置。一旦攻击者能改配置,他就能改认证、改文件路径、改模块加载地址——这三件事都不需要再找一个新漏洞。
这也是为什么“配置写入”的权限必须比“配置读取”严一个数量级:读配置最多泄露信息,写配置等于接管行为。管理端点的写操作应该单独审批、单独审计、单独限流。
四、漏洞二:Clientside LLM Credentials 的 SSRF
第二组问题和配置端点无关,出在一个“文档里写着的功能”上:Clientside LLM Credentials。
/chat/completions 等端点接受请求体里的 user_config 参数。带了这个参数,LiteLLM 会用调用者提供的配置新建一个 Router:
elif "user_config" in data:
router_config = data.pop("user_config")
user_router = litellm.Router(**router_config) # 完全由调用者控制
ret_val = getattr(user_router, f"{route_type}")(**data)
这个配置里可以指定 model_list 和任意的 api_base。于是:
- 调用者把
api_base指向自己的服务器(原文用10.10.13.37:9999); - LiteLLM 按这个配置发请求;
- 请求里带着网关默认 header 中配置的 provider key;
- 攻击者的监听器收到 key。
原文特别指出:LiteLLM 有一个 configurable_clientside_auth_params 设置,用来限制请求体里直接传 api_base / api_key;但 user_config 走的是另一条代码路径,完全绕过了这个限制。
这是一个典型的 SSRF:不是“读一个文件”,而是“让服务器带着你的凭据去访问我指定的地址”。 除了偷 key,还可以用来探测内网。
五、附带的两个问题:哈希暴露与无盐单次哈希
原文还列了两项“不能直接拿下系统、但会显著放大风险”的问题:
- 密码哈希暴露:低权限用户能通过 API 拿到其他账号的密码哈希。原本应该只有管理员能看。
- 不安全的哈希存储:单次标准哈希、不加盐。相同密码产生相同哈希,可以直接查彩虹表;单次迭代也让暴力破解变得便宜。
两者都被 LiteLLM 标记为重复项(GHSA),原文也注明了这一点。单独看等级不高,但和前面的权限提升串起来,就是“先拿哈希、再离线破解、再用密码横向”。
六、CVE、版本与修复
| 编号 | 问题 | 说明 |
|---|---|---|
| CVE-2026-35029 | /config/update 缺少授权 |
任意已认证用户可改运行时配置 |
| CVE-2026-59823 | user_config 参数导致 SSRF |
可重定向请求、窃取 provider key |
| GHSA(重复项) | 密码材料暴露 | 低权限用户可读他人哈希 |
| GHSA(重复项) | 无盐、单次哈希 | 离线破解成本低 |
- 研究版本:LiteLLM v1.77.7
- 修复版本:v1.83.9
- 披露方式:与维护者协调披露
七、这件事和“别把 API token 交给 LLM”的关系
表面上看,这是一篇网关漏洞分析;但放到“如何避免 API token 泄露”这个主题下,它给了三条更普遍的教训。
7.1 集中管理 = 集中风险
网关的卖点就是“key 只放在一处”。这句话反过来读就是:那一处被攻破,所有 key 一起没。所以网关的隔离等级、补丁节奏、管理面暴露面,必须按“它持有全部供应商凭据”来定,而不是按“一个普通内部服务”来定。
7.2 管理面和数据面必须分开
这次最严重的问题出在管理面(/config/update),而不是模型调用本身。管理面一旦和普通用户的 UI 会话共享同一套 token 分类逻辑,前缀匹配这种小细节就会变成权限提升。
判断标准很简单:能改配置的端点,必须独立鉴权、独立网络位置、独立审计,不能靠“用户登录了”来授权。
7.3 客户端提供的配置就是代码
user_config 看起来只是个参数,实际上让调用者决定“请求发到哪、带什么 header”。任何允许调用者指定 api_base、target、模块路径、URL 的字段,都要按 SSRF / RCE 来审。白名单不够,还要确认没有第二条代码路径绕过它——原文的 bypass 就是这么来的。
7.4 为什么“老问题”会反复出现在新组件里
缺授权、路径穿越、动态加载、弱密码存储,都是教科书里的老问题。它们之所以出现在一个 2026 年的 LLM 网关上,原因并不神秘:
- 先跑通,再补鉴权:新组件的迭代节奏快,管理端点往往从“内部调试用”长成了“生产可用”,但鉴权模型没跟上;
- 复用 UI 会话:为了省事,管理面直接复用普通用户的登录态,于是“能登录”被误当成“能管理”;
- 为灵活性开放客户端配置:
user_config这类功能本来是为了让调用者自带模型和地址,但设计时没有把“谁有权指定目标”想清楚; - 默认配置面向 demo:开源项目的第一目标是“五分钟跑起来”,安全默认值通常排在后面。
原文的结论很直白:这些不是新型攻击,而是基础安全又被当成了次要事项。对使用者的含义是:不要因为组件“新”就假设它“安全”,网关要按带外管理设备的标准来对待。
八、对我们自己的含义
如果按我们前面讨论的形态——本地 MCP 网关 + 云端 IR 编译服务——这篇研究至少对应五条设计约束:
- 编译服务不持有任何 LLM provider key。 它只做 IR→SimaticML 的确定性转换,不需要调模型;一旦需要,也应该走独立网关、独立凭据、独立出网策略。
- 管理面和数据面分离。 改配置、发授权、看用量属于管理面,不能和普通用户的请求共享同一张 token、同一个端口、同一套前缀规则。
- 不接受客户端指定
api_base/target/ 模块地址。 如果编译服务需要回调,目标地址必须来自服务端配置的白名单,而不是请求体。 - 凭据不进工具参数、不进日志。 license token、云服务 token 用本地注入或短时凭据;日志里只留请求 id 和结果码。
- 补丁 SLA 要按“钥匙串”定。 网关类组件不能等季度更新;至少要有“安全版本发布后 72 小时内升级”的流程,以及升级前的出网收紧作为临时缓解。
再加一条运维层面的:私有化部署时,管理面默认只监听内网/本机,不要因为“反正内网”就把它暴露给整个网段。
8.1 上线前的网关自检
| 检查项 | 通过标准 |
|---|---|
| 管理端点鉴权 | 独立角色检查,不依赖“已登录” |
| UI token | 不能调用管理端点;分类不依赖单一 team_id |
| 路由匹配 | 精确路径 / 方法,禁用无边界的 startswith |
| 客户端配置 | 不接受 api_base / target / 模块地址 |
| 出网 | 默认拒绝,只放行 provider 域名 |
| 凭据 | 按租户 / 环境隔离,短期、可轮换 |
| 日志 | 不含 key、prompt 原文、完整 provider 响应 |
| 版本 | ≥ 1.83.9,或有等价补丁 |
8.2 怀疑被利用时先查什么
- 最近的
/config/update调用,尤其是来自非管理员账号的; - 环境变量快照:
UI_USERNAME、UI_PASSWORD、UI_LOGO_PATH是否被改过; /get_image是否读过非图片路径;- pass-through 端点里是否新增了
s3:///gcs://目标; - 网关的出网日志里有没有未知 IP / 域名;
- provider 账单和 key 使用记录有没有异常峰值;
- 轮换顺序:先 provider key,再网关自身凭据,最后下游系统。
九、边界
- 研究针对 LiteLLM v1.77.7,修复版本 v1.83.9;如果你用的是更早或更晚的版本,先核对补丁状态,不要直接套结论。
- 本文未复现任何 PoC;代码片段是原文节选,为了可读性做了删减,不要在生产环境照抄测试。
- CVE / GHSA 的细节、影响范围与修复说明,以 NVD、GitHub Security Advisory 和 LiteLLM 官方公告为准;原文的 GHSA 编号在抓取中有字符损坏,本文未强行还原。
- LiteLLM 只是“LLM 网关”这一类组件的一个样本;文中三条教训(集中风险、管理面隔离、客户端配置即代码)对其他网关同样成立。
- 原文结论说得很直白:这些不是新型攻击,缺少授权、路径穿越、动态加载导致 RCE、弱密码存储,都是老问题;只是在一个快速演进的生态里,基础安全又被当成了次要事项。
相关阅读:AI 基建 / 评测 / 安全完全指南 | API Key 是怎么被 LLM 读走的 | Agent 安全:九起真实事故,六项通用控制 | MCP 供应链体检 | 开源模型后门:投毒 1% 就能让编码代理泄露 .env | 1–2 毫秒起的 microVM:Hyperlight 0.18
Sources
- Check Point Research, When LLM Gateways Go Wrong: Findings from LiteLLM, 2026-10-13:https://research.checkpoint.com/2026/when-llm-gateways-go-wrong-findings-from-litellm/
- CVE-2026-35029(
/config/update缺少授权) - CVE-2026-59823(
user_config参数 SSRF) - LiteLLM 官方仓库与安全公告:https://github.com/BerriAI/litellm
- 对照阅读(本站):API Key 是怎么被 LLM 读走的、Agent 安全九起事故、MCP 供应链体检
本文由 hubwiz 编译整理,转载请注明出处。
这是「AI 基建 / 评测 / 安全」专题的一部分。完整地图见:AI 基建 / 评测 / 安全完全指南