# LiteLLM Proxy: Four Evolving Exploit Chains (Pre-auth RCE, Internal-User RCE, Master Key Theft) Plus Exploited CVE-2026-42208 SQLi and CVE-2026-30623 MCP stdio Command Injection

> STAR Labs documented four successive exploit chains against the LiteLLM AI gateway (v1.82.3 through v1.83.14) ahead of Pwn2Own Berlin 2026, spanning pre-auth RCE, internal-user privilege escalation to RCE via MCP stdio execution, and LITELLM_MASTER_KEY exfiltration. The related CVE-2026-42208 (pre-auth SQL injection, CVSS 9.3) was actively exploited roughly 36 hours after advisory publication and added to CISA KEV; CVE-2026-30623 (authenticated MCP stdio command injection) was patched the same release cycle.

- **Published:** 2026-10-31T23:12:32Z
- **Last reviewed:** 2026-10-31T23:12:32Z
- **Canonical:** https://intel.threadlinqs.com/threat/TL-2026-4936
- **ID:** TL-2026-4936
- **Severity:** CRITICAL (CVSS 9.3)
- **Category:** VULNERABILITY
- **Status:** ACTIVE
- **Detections:** 9 · **IOCs:** 6 (full data via the Threadlinqs MCP server — Purple tier)
- **CVEs:** CVE-2026-30623, CVE-2026-42208

## Description

LiteLLM is a widely deployed open-source LLM proxy/AI gateway that centralizes and holds upstream provider credentials (OpenAI, Anthropic, AWS Bedrock IAM). While preparing a submission for Pwn2Own Berlin 2026 (Local Inference category), STAR Labs researchers developed four distinct full-chain compromises against successive LiteLLM releases; each chain was neutralized by a vendor patch before the researchers could complete contest submission, and a new chain was found in the replacement release.

Chain 1 targeted v1.82.3 (released 2026-03-17) and required no valid credentials, contingent on the operator-set option allow_requests_on_db_unavailable being enabled. An authentication-exception handler in user_api_key_auth.py / auth_exception_handler.py granted the built-in PROXY_ADMIN identity to any request when a database lookup failed, and a Prisma connection-pool exhaustion technique (flooding database-touching endpoints such as /models, /key/list, /user/list with bogus keys) could reliably force that failure window on demand. From the resulting admin-equivalent context, two independent RCE primitives were reachable: a server-side template injection in the dotprompt prompt manager (POST /prompts/test), where a user-supplied prompt template was rendered by a permissive Jinja2 Environment and could reach Python object internals (the classic cycler.__init__.__globals__ gadget chain) to invoke os.popen and return command output in the HTTP 500 error body; and a sandbox-escape in the custom-code guardrail tester (POST /guardrails/test_custom_code), where a denylist-based Python sandbox failed to block sibling attributes such as cr_frame and f_builtins, letting submitted guardrail code recover the real interpreter __builtins__ via a coroutine frame object and call __import__('os').popen(). The SSTI bug was fixed by commit d910a95661 (input validation on management endpoints); the sandbox-escape bug was later replaced wholesale with RestrictedPython (commit 0a1b4427a6c4) after independent public disclosure by X41 D-SEC. Pwn2Own organizers (ZDI) ultimately ruled the DB-unavailability prerequisite out of scope for the default configuration, ending Chain 1's contest viability.

Chain 2 targeted v1.83.7 (released 2026-04-19) starting from only a low-privileged internal_user API key, the contest-mandated starting point. Three authorization flaws chained together: (1) permission checks on POST /key/generate validated only top-level request fields, so nesting premium/restricted fields such as allowed_passthrough_routes inside the untyped metadata object bypassed validation entirely (common_utils.py); (2) route-authorization in route_checks.py matched allowed routes by string prefix rather than exact path, so a single granted prefix such as /team or /user silently also granted every sub-route in that family (/team/member_add, /user/update, etc.); (3) the self-update path of /user/update (internal_user_endpoints.py) unconditionally permitted a user to modify their own record with no field-level restriction, unlike the admin-role-creation guard present on /user/new, so a user could set their own user_role to proxy_admin. Combined, a standard internal_user key could self-escalate to proxy_admin, then abuse the already-patched-for-unauthenticated-use-but-still-authenticated-exploitable MCP stdio server feature (POST /v1/mcp/server, triggered via /mcp-rest/test/connection) to launch an allow-listed interpreter (e.g. python3) with attacker-controlled arguments, achieving command execution as the LiteLLM process (commonly root in container deployments) — this is the mechanism later assigned CVE-2026-30623. Microsoft/BerriAI closed the escalation path with commit e6f18ce75b, adding field-level validation that blocks user_role modification via self-update.

Chain 3 targeted v1.83.10 (released 2026-04-28), reusing the still-unpatched metadata-nesting and prefix-routing bugs from Chain 2 but replacing the now-fixed self-escalation step with two newly found flaws: a completely unauthenticated onboarding endpoint, GET /onboarding/get_token?invite_link=<UUID> (proxy_server.py), which returned a JWT containing the invited user's real API key and role to anyone who supplied a valid invite-link UUID with no auth dependency at all; and an invitation-authorization gap in common_utils.py's team-admin-invite check, which verified only that the inviter and invitee shared a team, never checking the invitee's existing privilege level — allowing a team admin to generate an invitation for the built-in default_user_id proxy-admin account. The full chain created a team, added the default proxy-admin user to it (exploiting the prefix-route bypass to reach /team/new and /team/member_add), waited out LiteLLM's ~60-second in-memory user-object cache, then issued and immediately redeemed an invitation for that admin account via the unauthenticated onboarding endpoint to obtain a valid proxy-admin JWT, which was then used to register a malicious MCP stdio server for RCE exactly as in Chain 2. The onboarding flaw was fixed by PR #26843, which added session-level verification so an invite-link UUID alone is no longer sufficient to mint a credential.

Chain 4 targeted v1.83.14 (released 2026-05-02) after the admin-escalation paths used by Chains 2 and 3 were closed, and pivoted strategy from privilege escalation to direct master-key theft. LiteLLM resolves callback configuration values of the form os.environ/VAR_NAME to the corresponding environment variable at use time via litellm.utils.get_secret(). An earlier fix (commit df75e79615, 2026-04-13) blocked this environment-reference syntax only on the inference request path; the write path for callback metadata submitted through POST /key/generate (validated in _types.py's AddTeamCallback.validate_callback_vars) performed no equivalent check. An internal_user could therefore create a key whose logging/callback metadata set a Langfuse secret-key field to the literal string os.environ/LITELLM_MASTER_KEY and point the Langfuse host at an attacker-controlled or public echo service (e.g. httpbin.org). The first inference request made with that key caused LiteLLM to resolve the environment reference to the real master key value, hand it to the Langfuse SDK, which built an HTTP Basic Authorization header from it and sent that header to the configured host via the proxy's Langfuse passthrough route (POST /langfuse/anything); because the chosen host echoed request headers back in its response body, the attacker recovered and base64-decoded the Authorization header to obtain the plaintext LITELLM_MASTER_KEY — equivalent to full root-level control of the proxy. The master key could then be used directly against the MCP stdio server-registration endpoint for RCE. This was fixed by commit f2f1e3a0ba (2026-05-06), which added write-time validation (validate_no_callback_env_reference) rejecting environment-variable references in key metadata during Pydantic validation, before any database persistence. Notably, the actual Pwn2Own contest build (v1.83.14-stable.patch.3, released 2026-05-08) shipped a separate, narrower mitigation (requiring a cookie or Authorization header to create an MCP server) but did NOT include the f2f1e3a0ba master-key write-time fix, so the master-key leak remained exploitable at contest time and could be chained with a stolen admin WebUI session cookie to satisfy the new MCP-creation requirement.

Separately, but from the same codebase and disclosure period, CVE-2026-42208 is a pre-authentication SQL injection (CVSS 9.3) affecting LiteLLM >=1.81.16 and <1.83.7: a database query executed during proxy API-key validation concatenated the caller-supplied Authorization header value directly into query text instead of using parameterized binding, and was reachable via the proxy's error-handling path on any LLM API route (e.g. POST /chat/completions) without authentication. It was fixed in 1.83.7-stable (2026-04-19). Sysdig's Threat Research Team observed live exploitation against LiteLLM honeypots beginning 2026-04-26 04:24 UTC / 16:17 UTC reporting windows, roughly 26-36 hours after the GitHub Security Advisory was indexed — a single operator used 17 distinct UNION-based payloads across two adjacent source IPs in the same /22 block on AS200373 (3xK Tech GmbH, Germany) to enumerate schema and extract rows from LiteLLM_VerificationToken, litellm_credentials.credential_values, and litellm_config, tables that store upstream provider API keys (OpenAI org keys, Anthropic console keys, AWS Bedrock IAM credentials) and proxy runtime configuration. The flaw was added to the CISA KEV catalog on 2026-05-08 with a federal remediation deadline of 2026-05-11. Operators who could not immediately patch were advised to set general_settings.disable_error_logs: true as a stopgap, since the vulnerable query was only reached through the error-logging code path.

CVE-2026-30623, reported by OX Security (Moshe Siman Tov Bustan, Mustafa Naamnih, Nir Zadok) and published 2026-04-15, is the formal CVE for the MCP stdio command-injection primitive exploited as the final RCE step in Chains 2-4: LiteLLM passed the user-specified stdio 'command' value for a newly created MCP server directly into StdioServerParameters and executed it as a subprocess with no validation, letting any authenticated user able to create MCP servers run arbitrary OS commands as the LiteLLM process. It requires authentication (unlike the SQLi) and was fixed in v1.83.6-nightly / v1.83.7-stable by introducing a command allow-list (npx, uvx, python, python3, node, docker, deno, extensible via LITELLM_MCP_STDIO_EXTRA_COMMANDS) plus restricting the /mcp-rest/test/connection and /mcp-rest/test/tools/list preview endpoints to PROXY_ADMIN. As STAR Labs' later research showed, the allow-list alone was insufficient because allow-listed interpreters can still execute attacker-supplied code via arguments (e.g. python3 -c '<code>'), so the command-injection class of risk persisted through MCP stdio servers even after the formal CVE fix landed.

Overall this threat illustrates systemic authorization-boundary problems in a security-critical AI infrastructure component: permission checks implemented inconsistently across dozens of endpoints, coarse prefix-based route matching, untyped metadata dictionaries used to bypass field-level checks, environment-variable secret resolution scattered across multiple code paths with inconsistent validation, and Python sandboxing attempted with a denylist against an inherently unsound set of live object references.

## MITRE ATT&CK

- T1190 Exploit Public-Facing Application
- T1078 Valid Accounts
- T1098 Account Manipulation
- T1548 Abuse Elevation Control Mechanism
- T1059.006 Command and Scripting Interpreter: Python
- T1212 Exploitation for Credential Access
- T1552 Unsecured Credentials
- T1552.001 Unsecured Credentials: Credentials In Files
- T1005 Data from Local System
- T1567 Exfiltration Over Web Service

## Sources

- [Race Against The Patch: The Evolution of Four Exploit Chains in LiteLLM](https://starlabs.sg/blog/2026/05-race-against-the-patch-the-evolution-of-four-exploit-chains-in-litellm/)
- [LiteLLM Security Update: MCP stdio Command Injection (April 2026)](https://docs.litellm.ai/blog/mcp-stdio-command-injection-april-2026)
- [CVE-2026-30623](https://access.redhat.com/security/cve/CVE-2026-30623)
- [LiteLLM 1.18.10 - Command Injection CVE-2026-30623](https://pentest-tools.com/vulnerabilities-exploits/litellm-11810-command-injection_29521)
- [LiteLLM CVE-2026-42208 SQL Injection](https://thehackernews.com/2026/04/litellm-cve-2026-42208-sql-injection.html)
- [CVE-2026-42208: LiteLLM bug exploited 36 hours after its disclosure](https://securityaffairs.com/191483/hacking/cve-2026-42208-litellm-bug-exploited-36-hours-after-its-disclosure.html)
- [CVE-2026-42208: LiteLLM: Unauthorized data access and modification via SQL injection](https://research.averlon.ai/vulnerability-intelligence/cve/CVE-2026-42208)
- [CSA Research Note: LiteLLM CVE-2026-42208 Pre-Auth SQLi](https://labs.cloudsecurityalliance.org/research/csa-research-note-litellm-cve-2026-42208-ai-proxy-sqli-20260/)
- [CVE-2026-42208 (GCVE-0-2026-42208)](https://cve.circl.lu/cve/CVE-2026-42208)
- [CVE-2026-42208](https://access.redhat.com/security/cve/CVE-2026-42208)

## Full data

Detection queries (Splunk SPL / Microsoft KQL / Sigma) and IOC values require the Threadlinqs MCP server (Purple tier): https://intel.threadlinqs.com/mcp

Canonical: https://intel.threadlinqs.com/threat/TL-2026-4936
