The Auth Check Is the Attack Surface
A pre-authentication SQL injection in LiteLLM's API key verification path gave attackers read/write access to every credential the proxy manages — and the 401 it returned made each successful query look like a failed login.
LiteLLM is an API gateway. Its job is to sit between an application and whatever LLM backend it calls, handling routing, rate limits, and credential management for over a hundred upstream model providers. CVE-2026-42208 is a SQL injection in the authentication layer — not behind it. The mechanism built to reject unauthorized requests is the mechanism that hands the database over.
CISA added CVE-2026-42208 to the Known Exploited Vulnerabilities catalog on May 8, 2026. Active exploitation was confirmed within 36 hours of the GitHub advisory going public.
The Trust Boundary
Every LiteLLM API route requires a valid key. The proxy enforces this by looking up the bearer token from the Authorization: Bearer header against its PostgreSQL backend before the request goes anywhere.
The lookup takes the supplied token, finds it in the database, and determines what it is allowed to do. The failure is in how that lookup is built.
# Vulnerable pattern — versions 1.81.16 through 1.83.6
query = f"SELECT * FROM LiteLLM_VerificationToken WHERE token = '{api_key}'"
The raw, caller-supplied string from the HTTP header is interpolated directly into the query text. There is no parameterization. There is no sanitization. The database receives exactly what the caller sends.
# Correct pattern — v1.83.7 and later
query = "SELECT * FROM LiteLLM_VerificationToken WHERE token = $1"
await connection.fetch(query, api_key)
In the parameterized version, the database driver handles the key value as data. It cannot be interpreted as SQL syntax no matter what it contains. In the vulnerable version, an attacker who controls the token string controls the query.
This is CWE-89 — SQL Injection — at the worst possible location: the pre-authentication path that every API route passes through. No valid key is required to reach this code. The injection fires before any credential check completes.
Schema Knowledge as a Weapon
The exploitation confirmed after disclosure was not automated scanning. Attackers did not fire a generic injection tool and wait to see what surfaced. They arrived with queries pre-built for LiteLLM's specific database schema.
The targeted tables:
litellm_credentials.credential_values— upstream provider API keys; the credentials LiteLLM uses to call OpenAI, Anthropic, and every other configured backendlitellm_config— proxy runtime environment variables, including any secrets embedded in the deployment configuration
The tables left untouched:
litellm_userslitellm_team
That omission is deliberate. The attacker was not after account data or access management records. They targeted the two tables that hold the secrets the proxy uses to operate downstream. This required knowing LiteLLM's schema in advance — either through source code review, prior reconnaissance against other deployments, or both.
The attack was not an opportunistic probe. It was an application-specific extraction operation.
The Privilege Amplifier
The SQL injection gives an attacker arbitrary query execution against the database. How much damage that causes depends on what the application database user is allowed to do.
LiteLLM's reference Docker Compose configuration provisions the application user as a PostgreSQL superuser.
# From the default docker-compose.yml
environment:
- DATABASE_URL=postgresql://llmproxy:dbpassword1234@db:5432/litellm
The llmproxy user created by the default setup carries superuser privileges. LiteLLM does not require elevated database access to function — standard read/write on its own tables is sufficient. The superuser grant is an operational shortcut that ships as the default.
The consequence: what would otherwise be a targeted read against two known tables becomes full read/write access to the entire database. An attacker can read every active virtual key and its associated budget and team bindings from LiteLLM_VerificationToken. They can modify routing configuration. They can overwrite stored credentials.
A code failure and an operational failure produce an outcome neither creates alone.
The Cover of the 401
The injection executes during the token lookup. The attacker submits no valid key. The proxy checks, finds nothing, and returns HTTP 401 Unauthorized — the correct response to an unrecognized token.
That 401 is also the response to a successful data extraction.
Because the injected query runs and returns data that the proxy cannot match to a valid session, the application's response logic sees a lookup failure and issues the standard rejection. The attacker receives a 401. Their query ran. The 401 is indistinguishable from the thousands of legitimate authentication failures any exposed API endpoint receives.
Extraction works through a time-based blind channel. The attacker appends a conditional pg_sleep() call to the injected query:
' AND (SELECT CASE WHEN (condition) THEN pg_sleep(3) ELSE pg_sleep(0) END) IS NOT NULL--
If the condition is true, the response is delayed by three seconds. If false, it returns immediately. The attacker infers the value of individual bytes from response timing, reconstructing data without ever receiving it in a response body.
Every successful query looks identical to every failed login. Standard 401 alerting catches nothing. Detection requires monitoring for anomalous timing patterns or unexpected query volume against the authentication path — neither of which is configured in a default deployment.
The flaw was patched in v1.83.7. Organizations running affected versions (1.81.16 through 1.83.6) with a publicly reachable proxy should rotate all upstream provider credentials stored in the instance. The 401 wall means absence of alerts is not absence of compromise. The one layer that is not blind: a PostgreSQL instance with log_statement = 'all' or log_min_duration_statement configured will have every pg_sleep() call recorded directly — the database engine logs what the application layer never surfaces.