# REPRO-2026-00261: BerriAI LiteLLM SQL injection ## Summary Status: published Severity: critical Type: security Confidence: high ## Identifiers REPRO ID: REPRO-2026-00261 CVE: CVE-2026-42271 ## Package Name: BerriAI LiteLLM Ecosystem: pip Affected: pip litellm >= 1.81.16, < 1.83.7 (also reported as v1.81.16 through v1.83.6) Fixed: Unknown ## Root Cause ## Summary BerriAI LiteLLM proxy versions before the upstream parameterization fix contain an API-key authentication SQL injection in the database lookup for virtual keys. During authentication, an attacker-controlled `Authorization: Bearer ...` value reaches the combined verification-token lookup and, in vulnerable LiteLLM 1.83.6, is interpolated directly into a raw SQL string. The reproduction starts real LiteLLM proxy processes with PostgreSQL and proves that a remote request to `GET /model/info` using the injected bearer token `' OR EXISTS(SELECT 1 FROM pg_sleep(3)) --` causes PostgreSQL to execute the injected `pg_sleep(3)` expression and the endpoint to return authenticated model information. The same request against LiteLLM 1.83.7 is rejected immediately because the token is bound as a SQL parameter. ## Impact - **Package/component affected:** BerriAI LiteLLM proxy authentication and database helper code, specifically the combined verification-token lookup in `litellm/proxy/utils.py` reached from `user_api_key_auth` on protected proxy/API endpoints. - **Affected versions:** The reproduced vulnerable package is `litellm==1.83.6`. The fixed negative control is `litellm==1.83.7`. Upstream fix commit identified in the repository is `4dc416ee749122ca91e3bca095217478663419e7` (`fix(proxy): use parameterized query for combined_view token lookup`). - **Risk level and consequences:** Critical. A remote unauthenticated attacker can place SQL syntax in the bearer token used by protected endpoints. In the reproduced path this bypasses virtual-key authentication and can execute database expressions. In a real deployment, the same primitive can be used for time/error/boolean SQL injection and can expose or manipulate LiteLLM gateway data such as virtual keys, configuration, and logs, depending on database privileges and SQL payload construction. ## Impact Parity - **Disclosed/claimed maximum impact:** Unauthenticated SQL injection through proxy/admin API requests, leading to extraction or modification of LiteLLM database contents and compromise of gateway configuration, keys, and logs. - **Reproduced impact from this run:** A production-path remote API request to the real LiteLLM proxy executed attacker-supplied SQL (`pg_sleep(3)`) through the `Authorization` bearer token. The vulnerable proxy returned HTTP 200 with model information, while an unknown-token baseline and the fixed build both returned HTTP 401. PostgreSQL logs captured both the interpolated vulnerable query and the fixed parameterized query. - **Parity:** `full` for confirming the remote API SQL-injection vulnerability and fixed-version remediation; `partial` for the broader post-exploitation consequence because this run did not dump or modify sensitive gateway database records beyond demonstrating SQL execution and authentication bypass. - **Not demonstrated:** Bulk extraction or modification of production secrets, provider credentials, or logs was intentionally not performed. ## Root Cause The vulnerable code constructs a raw SQL query for the combined verification-token view by formatting the token value into the query text: ```python WHERE v.token = '{token}' ``` The bearer token is attacker controlled. When Python optimization is enabled for product execution, the non-`sk-` assertion in the auth path is not enforced, allowing a token such as: ```text ' OR EXISTS(SELECT 1 FROM pg_sleep(3)) -- ``` to reach the database helper. In `litellm==1.83.6`, this becomes SQL equivalent to: ```sql WHERE v.token = '' OR EXISTS(SELECT 1 FROM pg_sleep(3)) --' ``` PostgreSQL evaluates the injected `EXISTS(SELECT 1 FROM pg_sleep(3))`, delaying the request and making the `WHERE` condition true for at least one seeded virtual-key row. That row is then treated as the authenticated key object for the protected endpoint. The fix changes the helper to accept query arguments and uses a positional parameter: ```python WHERE v.token = $1 response = await self._query_first_with_cached_plan_fallback(sql_query, hashed_token) ``` The upstream fix commit recorded in the reproduction evidence is: - `4dc416ee749122ca91e3bca095217478663419e7` — `fix(proxy): use parameterized query for combined_view token lookup` ## Reproduction Steps 1. Use `bundle/repro/reproduction_steps.sh`. 2. The script: - Reuses or creates the deterministic project cache described by `bundle/project_cache_context.json`. - Installs/reuses `litellm==1.83.6` and `litellm==1.83.7` virtual environments. - Starts a local PostgreSQL instance and two real LiteLLM proxy processes, one vulnerable and one fixed. - Creates a virtual key through each running proxy via `/key/generate` so the verification-token table has a row. - Sends a baseline unknown-token request to `GET /model/info`. - Sends the injected bearer-token request to vulnerable `GET /model/info`. - Sends the identical injected bearer-token request to fixed `GET /model/info`. - Writes `bundle/repro/runtime_manifest.json` and `bundle/repro/result.txt` before exiting. 3. Expected evidence of reproduction: - Vulnerable request takes approximately three seconds and returns HTTP 200. - Fixed request returns HTTP 401 quickly. - PostgreSQL logs show the vulnerable raw query with `WHERE v.token = '' OR EXISTS(SELECT 1 FROM pg_sleep(3)) --'` and the fixed query with `WHERE v.token = $1` plus the payload only in bound parameters. ## Evidence Primary artifacts: - `bundle/repro/reproduction_steps.sh` — current-run reproducer. - `bundle/repro/runtime_manifest.json` — runtime evidence manifest for the API endpoint proof. - `bundle/repro/result.txt` — summarized timings/status codes. - `bundle/logs/reproduction_steps.log` — full script output. - `bundle/logs/source_delta.txt` — fix commit and patch hunk. - `bundle/logs/postgres_repro.log` — PostgreSQL query evidence. - `bundle/logs/vulnerable_injection.txt` — vulnerable endpoint response. - `bundle/logs/fixed_injection.txt` — fixed endpoint response. - `bundle/logs/proxy_vulnerable.log` and `bundle/logs/proxy_fixed.log` — LiteLLM proxy runtime logs. Key current-run results from `bundle/repro/result.txt`: ```text result=confirmed baseline_time=0.013450 baseline_code=401 vuln_injection_time=3.012161 vuln_injection_code=200 fixed_injection_time=0.015421 fixed_injection_code=401 vulnerable_version=litellm 1.83.6 fixed_version=litellm 1.83.7 fixed_commit=4dc416ee749122ca91e3bca095217478663419e7 ``` Vulnerable response evidence from `bundle/logs/vulnerable_injection.txt` shows a successful protected endpoint response: ```json {"data":[{"model_name":"gpt-4o", ... }]} ``` Fixed response evidence from `bundle/logs/fixed_injection.txt` shows rejection of the exact same token: ```json {"error":{"message":"Authentication Error, Invalid proxy server token passed... Unable to find token in cache or `LiteLLM_VerificationTokenTable`","type":"token_not_found_in_db","param":"key","code":"401"}} ``` PostgreSQL evidence from `bundle/logs/postgres_repro.log` includes the vulnerable query text: ```text WHERE v.token = '' OR EXISTS(SELECT 1 FROM pg_sleep(3)) --' ``` The same log also includes the fixed query shape and parameter binding: ```text WHERE v.token = $1 DETAIL: Parameters: $1 = ''' OR EXISTS(SELECT 1 FROM pg_sleep(3)) --' ``` The runtime manifest records a real API endpoint path: ```json { "entrypoint_kind": "endpoint", "entrypoint_detail": "GET /model/info with attacker-controlled Authorization Bearer token", "service_started": true, "healthcheck_passed": true, "target_path_reached": true, "runtime_stack": ["postgresql", "litellm-proxy"] } ``` ## Recommendations / Next Steps - Upgrade LiteLLM proxy deployments to `1.83.7` or later, or to a downstream package containing commit `4dc416ee749122ca91e3bca095217478663419e7` or equivalent parameterization. - Ensure all raw SQL helpers use parameterized arguments rather than f-string/interpolated query text. - Add regression tests that send bearer tokens containing quotes, comments, and time-based SQL expressions through real protected proxy endpoints and verify they are rejected quickly. - Rotate LiteLLM virtual keys, provider credentials, and any secrets stored in the LiteLLM database for deployments that exposed vulnerable versions to untrusted networks. - Review PostgreSQL and proxy access logs for suspicious bearer-token values containing quotes, SQL comments, `UNION`, `SELECT`, `pg_sleep`, or similar SQL syntax. ## Additional Notes - The reproduction script was executed successfully twice consecutively in the current run. - The proof uses a real LiteLLM proxy process and a real PostgreSQL database; it does not mock the vulnerable SQL helper. - The script bounds all HTTP requests with curl timeouts and writes all diagnostics under `bundle/logs/`. - The proof avoids destructive SQL payloads. It uses `pg_sleep(3)` and endpoint response divergence to demonstrate SQL execution and authentication bypass without dumping sensitive database contents. ## Reproduction Details Reproduced: 2026-07-07T08:05:02.550Z Duration: 10122 seconds Tool calls: 711 Turns: Unknown Handoffs: 3 ## Quick Verification Run one of these commands to verify locally: pruva-verify REPRO-2026-00261 pruva-verify CVE-2026-42271 Or open in GitHub Codespaces (zero-friction, auto-runs): https://github.com/codespaces/new?ref=repro/REPRO-2026-00261&repo=N3mes1s/pruva-sandbox Or download and run the script manually: curl -O https://api.pruva.dev/v1/reproductions/REPRO-2026-00261/artifacts/bundle/repro/reproduction_steps.sh chmod +x reproduction_steps.sh ./reproduction_steps.sh WARNING: Run in a sandboxed environment. This exploits a real vulnerability. ## References - NVD: https://nvd.nist.gov/vuln/detail/CVE-2026-42271 ## Artifacts - bundle/repro/reproduction_steps.sh (reproduction_script, 20130 bytes) - bundle/repro/rca_report.md (analysis, 9040 bytes) - bundle/vuln_variant/reproduction_steps.sh (reproduction_script, 20572 bytes) - bundle/vuln_variant/rca_report.md (analysis, 10227 bytes) - bundle/coding/proposed_fix.diff (patch, 2191 bytes) - bundle/artifact_promotion_manifest.json (other, 12922 bytes) - bundle/artifact_promotion_report.json (other, 12940 bytes) - bundle/vuln_variant/root_cause_equivalence.json (other, 1100 bytes) - bundle/repro/validation_verdict.json (other, 701 bytes) - bundle/repro/runtime_manifest.json (other, 980 bytes) - bundle/logs/reproduction_steps.log (log, 4145 bytes) - bundle/logs/postgres_repro.log (log, 169601 bytes) - bundle/logs/source_delta.txt (other, 2370 bytes) - bundle/logs/proxy_vulnerable.log (log, 4158 bytes) - bundle/logs/proxy_fixed.log (log, 4102 bytes) - bundle/logs/vuln_key_generate.json (other, 1462 bytes) - bundle/logs/fixed_key_generate.json (other, 1462 bytes) - bundle/logs/baseline_unknown.txt (other, 271 bytes) - bundle/logs/vulnerable_injection.txt (other, 3148 bytes) - bundle/logs/fixed_injection.txt (other, 296 bytes) - bundle/repro/result.txt (other, 386 bytes) - bundle/vuln_variant/result.json (other, 1251 bytes) - bundle/logs/vuln_variant/reproduction_steps.log (log, 4469 bytes) - bundle/logs/vuln_variant/postgres_variant.log (log, 170470 bytes) - bundle/vuln_variant/variant_manifest.json (other, 3612 bytes) - bundle/vuln_variant/validation_verdict.json (other, 3497 bytes) - bundle/vuln_variant/patch_analysis.md (documentation, 5279 bytes) - bundle/vuln_variant/runtime_manifest.json (other, 1050 bytes) - bundle/logs/vuln_variant/fixed_version.txt (other, 267 bytes) - bundle/logs/vuln_variant/source_delta_variant.txt (other, 2510 bytes) - bundle/logs/vuln_variant/vulnerable_api_key_header.txt (other, 3148 bytes) - bundle/logs/vuln_variant/fixed_api_key_header.txt (other, 304 bytes) - bundle/logs/vuln_variant/vulnerable_x_litellm_header.txt (other, 3148 bytes) - bundle/logs/vuln_variant/fixed_x_litellm_header.txt (other, 306 bytes) - bundle/coding/verify_fix.sh (other, 10373 bytes) - bundle/coding/verify_work/verify_result.txt (other, 335 bytes) - bundle/logs/verify_injection.txt (other, 296 bytes) - bundle/logs/verify_valid_key.txt (other, 3148 bytes) - bundle/coding/summary_report.md (documentation, 4885 bytes) ## API Access - JSON: https://api.pruva.dev/v1/reproductions/REPRO-2026-00261 - Script: https://api.pruva.dev/v1/reproductions/REPRO-2026-00261/artifacts/bundle/repro/reproduction_steps.sh - Web: https://pruva.dev/r/REPRO-2026-00261 ## For AI Assistants To help users with this reproduction: 1. The `pruva-verify` command is the simplest way to run the reproduction 2. The script downloads and runs automatically in an isolated temp directory 3. Always recommend running in a VM, container, or disposable environment 4. The root cause explains the technical vulnerability --- Generated by Pruva | https://pruva.dev