漏洞分析 | LiteLLM Proxy 预认证 SQL 注入 (CVE-2026-42208)
漏洞概述
LiteLLM 是一个开源的大语言模型代理网关(46.5k+ Stars),支持统一接口调用 OpenAI、Anthropic、Azure 等 100+ LLM 提供商。其 Proxy 模式使用 PostgreSQL 存储 API Key、团队配置及提供商凭据等敏感数据。
近期,LiteLLM Proxy 的 API Key 认证流程中被发现存在一个预认证 SQL 注入漏洞。攻击者无需任何有效凭据,仅通过发送构造的 `Authorization` 头即可触发注入,读取甚至篡改代理数据库中的所有数据,包括全部 LLM 提供商的 API Key。(网宿评分:极危、CVSS 3.0 评分:9.8)
目前该漏洞POC状态已在互联网公开,建议客户尽快做好自查及防护。
受影响版本
1.81.16 <= LiteLLM < 1.83.7
漏洞分析
- 前置知识:LiteLLM Proxy 的 API Key 认证流程
LiteLLM Proxy 启用 API Key 认证后,所有 LLM API 路由(如 `/chat/completions`)都需要在请求头中携带 `Authorization: Bearer sk-xxx` 格式的 Token。正常流程下:
1. 从 `Authorization` 头提取 Bearer Token
`litellm/proxy/auth/user_api_key_auth.py`
→`_get_bearer_token_or_received_api_key()`
2. 断言 Token 以 `sk-` 开头
`user_api_key_auth.py`
→`assert api_key.startswith("sk-")`
3. 对 Token 做 SHA256 哈希
`user_api_key_auth.py`
→`hash_token(api_key)`
4. 用哈希后的值查询数据库
`litellm/proxy/auth/auth_checks.py`
→`get_key_object(hashed_token=hash_token(api_key))`
→`_fetch_key_object_from_db_with_reconnect()`
→`prisma_client.get_data(token=hashed_token,table_name="combined_view")`
所以正常路径是安全的——因为 SHA256 哈希只产生 `[0-9a-f]` 字符,无法构造 SQL 注入 payload。
- 漏洞根因:错误处理回调中的 f-string 拼接
漏洞发生在认证失败的错误处理路径中,而非主认证流程。当发送的 Token 不以 `sk-` 开头时:
HTTP 请求: Authorization: Bearer <payload>
1. litellm/proxy/auth/user_api_key_auth.py
→_get_bearer_token_or_received_api_key() 提取 Bearer Token
→assert api_key.startswith("sk-") 断言失败,payload 以 ' 开头
2. litellm/proxy/auth/user_api_key_auth.py
→UserAPIKeyAuthExceptionHandler._handle_authentication_error(api_key=api_key) 原始 payload 作为 api_key 传入
3. itellm/proxy/auth/auth_exception_handler.py
→post_call_failure_hook(user_api_key_dict=UserAPIKeyAuth(api_key=api_key)) 原始 payload 封装进 user_api_key_dict
4. litellm/proxy/utils.py
→post_call_failure_hook()
→[回调链] 再次调用 get_key_object(hashed_token=RAW_PAYLOAD)
5. litellm/proxy/auth/auth_checks.py
→get_key_object()
→_fetch_key_object_from_db_with_reconnect()
→prisma_client.get_data(token=RAW_PAYLOAD,table_name="combined_view")
6. 关键步骤:litellm/proxy/utils.py
→get_data()
→hashed_token = _hash_token_if_needed(token=token)
→因 payload 不以 "sk-" 开头,直接返回原始值
7. litellm/proxy/utils.py
→sql_query = f"""...WHERE v.token = '{token}'""" 原始 payload 拼入 SQL
8. litellm/proxy/utils.py
→_query_first_with_cached_plan_fallback(sql_query)
→self.db.query_first(query=sql_query) 直接执行,注入完成
从 Authorization 头到 SQL 注入点的污点传播路径:
- 关键函数 `_hash_token_if_needed()`(`litellm/proxy/utils.py`)
这个函数是整个漏洞的核心开关。它的设计意图是兼容已经哈希过的 token(SHA256 hex 字符串不以 `sk-` 开头),但它同时也让攻击者构造的恶意输入畅通无阻地流入了 f-string SQL 拼接。攻击者只需确保 payload 不以 `sk-` 开头(例如以单引号 `'` 开头),即可绕过哈希处理,原样注入到 SQL 查询中。
def _hash_token_if_needed(token: str) -> str:Hash the token if it's a string and starts with "sk-" Else return the token as isif token.startswith("sk-"): return hash_token(token=token) else: return token # ← 非 sk- 开头的 token 原样返回,不做任何处理漏洞复现
修复方案
核心改动是将 f-string 拼接替换为参数化查询。修复后,即使 `_hash_token_if_needed()` 对非 `sk-` 前缀的 token 原样返回,该值也不会拼入 SQL 文本,而是作为 `$1` 占位符的绑定参数,由 PostgreSQL 驱动安全处理。
产品支持
网宿全站防护-WAF已支持对该漏洞利用攻击的防护,并持续挖掘分析其他变种攻击方式和各类组件漏洞,第一时间上线防护规则,缩短防护“空窗期”。
