🔥 CVE-2026-42208 深度独立研究:源码审计 · 二次发现 · 利用方案
CVE-2026-42208 深度独立研究:源码审计 · 二次发现 · 利用方案
🔍 源码独立审计
对 https://github.com/BerriAI/litellm 源码进行独立审计(置信度 70%)。
🧬 根因独立理解
漏洞根因:LiteLLM代理在API密钥校验中,将请求头Authorization携带的Bearer令牌直接通过Python字符串拼接方式嵌入SQL查询文本,而非使用参数化查询。具体位置在`litellm/proxy/proxy_server.py`的`user_api_key_auth`函数中,该函数被FastAPI依赖注入,所有LLM API路由都会调用。查询代码类似`SELECT * FROM LiteLLM_VerificationToken WHERE token = '{api_key}'`,其中`api_key`完全由外部控制,未经任何转义或绑定。当请求触发异常(如模型不存在)时,`litellm/llms/custom_httpx/llm_http_handler.py`的错误处理路径会再次进入认证流程,使攻击者无需有效密钥即可触达该查询。补丁将该查询改为参数化接口(如Prisma的`find_first(where={'token': api_key})`或`query_raw`绑定变量),使得api_key被作为数据而非SQL代码处理,从根因上消除了注入。但需注意,其他数据库操作若仍使用原始字符串拼接,仍存在类似风险。
🛤️ 漏洞触发链路
攻击者向任意LLM API端点(如POST /chat/completions)发送请求,在Authorization头中构造恶意token,例如`Bearer ' OR 1=1 --`。LiteLLM的鉴权依赖`user_api_key_auth`提取该token,随后拼接到SQL中,使认证条件恒真,从而绕过密钥检查。若请求因模型无效等错误进入`llm_http_handler.py`的异常处理分支,该分支会再次调用认证函数,导致查询被二次执行。攻击者可通过联合查询、时间盲注或堆叠查询读取数据库中的密钥表、用户表等敏感数据,甚至修改验证令牌,完全控制代理及其管理的LLM凭据。整个利用无需任何前置认证,且不依赖具体模型名,攻击面覆盖所有代理路由。
🔁 二次发现(同类漏洞/扩展攻击面)
- litellm/proxy/proxy_server.py / get_api_key 与 check_valid_key: 同一认证逻辑中可能存在按key_alias或team_id查询的SQL语句,若采用相同拼接方式,同样可被Authorization头或请求body注入。
- litellm/proxy/prisma_client.py / query_raw 使用点: 项目中存在大量直接执行原始SQL的query_raw调用,凡外部输入进入字符串格式化拼接处,均可能构成同类SQL注入漏洞。
🩹 修复完整性分析
当前补丁仅修复了token校验查询,将api_key改为绑定参数,从根因上消除了该点。但修复是否完整取决于是否对所有数据库操作进行了统一参数化改造。若其他查询(如用户列表、密钥更新)仍存在字符串拼接,攻击者可能通过其他入口绕过。此外,错误处理路径中是否所有调用认证函数的子路径都使用了同一套参数化逻辑,需逐一确认。建议全局禁用`query_raw`中的字符串格式化,并强制使用参数绑定。
⚔️ 利用方案设计
利用未参数化SQL注入,攻击者首先构造payload验证漏洞:`Authorization: Bearer ' AND SLEEP(5)--`,观察响应延迟确认注入点。随后使用UNION SELECT提取数据,例如`Bearer ' UNION SELECT id, token, user_id, team_id FROM LiteLLM_VerificationToken--`,通过响应差异或盲注逐字符获取管理员令牌。若数据库支持堆叠查询,可执行`Bearer '; UPDATE LiteLLM_VerificationToken SET token='attacker' WHERE role='admin';--`直接改写认证令牌,从而伪造合法API key。攻击者只需向/chat/completions等端点发送带恶意头的普通请求,利用错误处理路径触发的二次查询,即可完成从认证绕过到数据窃取、权限提升的完整攻击链。
🧪 PoC 复现
从 GitHub 公开仓库抓取的实际 PoC 代码(仓库)。
📋 代码元数据语言md来源ridhinva/litellm-sqli-scanner针对性✅ 已验证与漏洞相关(代码含 CVE 引用)依赖见代码注释/README用法详见代码注释中的使用说明
# LiteLLM SQL Injection Scanner
>
CVE-2026-42208 — SQL injection in LiteLLM Proxy
Detects and validates CVE-2026-42208: SQL injection vulnerability in LiteLLM Proxy's database layer.
For authorized security testing only.
## Features
- CVE-2026-42208 SQL injection detection
- LiteLLM Proxy version fingerprinting
- PoC validation payloads
- Structured JSON / text output
## Requirements
- Python 3.8+
## Usage
```bash
python litellm_scanner.py --url http://target:4000 # Scan a target
python litellm_scanner.py --url http://target:4000 --poc # Run PoC validation
python litellm_scanner.py --help # Help
```
## Legal
**For authorized testing only.** Only scan systems you own or have explicit written permission to test.
## Author
ridhinva — https://github.com/ridhinva⚔️ EXP 利用代码
截至分析时,Exploit-DB 未收录该 CVE 的公开利用代码。可利用上述 PoC 进行验证,或关注 Exploit-DB 更新。
🕵️ 检测指纹
针对该 CVE 的自动化检测规则(可直接用于扫描与审计)。
🛡️ Semgrep 审计规则: CVE-2026-42208.yaml
📋 代码元数据语言yaml来源rules/semgrep/CVE-2026-42208.yaml针对性✅ 按 CVE 匹配依赖semgrep用法semgrep --config CVE-2026-42208.yaml
rules:
- id: CVE-2026-42208-sqli-python
languages:
- python
severity: ERROR
message: "Potential SQL injection in LiteLLM proxy API key check via string formatting instead of parameterized query"
patterns:
- pattern-either:
- pattern: |f"SELECT * FROM $TABLE WHERE key = $VALUE"
pattern-not: |f"SELECT * FROM $TABLE WHERE key = ?"
fix: |
cursor.execute("SELECT * FROM proxy_keys WHERE key = ?",
(key_value,))
metadata:
cwe: "CWE-89"
owasp: "A1: Injection"
technology: litellm
references:
- "https://nvd.nist.gov/vuln/detail/CVE-2026-42208"
- id: CVE-2026-42208-sqli-python-format
languages:
- python
severity: ERROR
message: "Potential SQL injection via string formatting in database query"
patterns:
- pattern-either:
- pattern: $QUERY.format(key=$VALUE)
- pattern-not: $QUERY.format(key="?")
fix: |
cursor.execute("SELECT * FROM proxy_keys WHERE key = ?",(key_value,))
metadata:
cwe: "CWE-89"
owasp: "A1: Injection"
technology: litellm
references:
- "https://nvd.nist.gov/vuln/detail/CVE-2026-42208"🛡️ CodeQL 审计规则: CVE-2026-42208.ql
📋 代码元数据语言ql来源rules/codeql/CVE-2026-42208.ql针对性✅ 按 CVE 匹配依赖codeql用法codeql database run
/**
* @kind path-problem
* @id python/sql-injection/cve-2026-42208
* @name SQL injection in LiteLLM proxy database query
* @description User-controlled Authorization header value is concatenated into a database query instead of being passed as a parameter,
allowing SQL injection.
* @problem.severity error
* @tags security
* external/cwe/cwe-089
*/
import python
import semmle.python.dataflow.new.DataFlow
import semmle.python.dataflow.new.TaintTracking
import semmle.python.ApiGraphs
class SqlInjectionConfig extends TaintTracking::Configuration {SqlInjectionConfig() {this = "SqlInjectionConfig" }
override predicate isSource(DataFlow::Node source) {exists(DataFlow::Node n |n.asExpr() = any(Subscript s |s.getObject().(Name).getId() = "headers").getItem(_) or
source.asExpr() = any(Call c |c.getFunc().(Attribute).getAttrName() = "get" and
c.getFunc().(Attribute).getObject().(Name).getId() = "headers"
)
)
}override predicate isSink(DataFlow::Node sink) {
exists(DataFlow::Node n |n.asExpr() = any(Call c |c.getFunc().(Attribute).getAttrName() = "execute" or
c.getFunc().(Attribute).getAttrName() = "executemany" or
c.getFunc().(Attribute).getAttrName() = "executescript"
) and
sink = n
)
}override predicate isAdditionalTaintStep(DataFlow::Node node1,DataFlow::Node node2) {
any(FString fstr).getAFormattedValue() = node1.asExpr() and
node2.asExpr() = fstr
}}from DataFlow::PathNode source,DataFlow::PathNode sink,SqlInjectionConfig config
where config.hasFlowPath(source,sink)
select sink.getNode(),source,sink,"User-controlled input from Authorization header reaches database execute() call,allowing SQL injection."🤖 高危漏洞深度独立研究引擎生成 · 2026-08-09 13:52