LiteLLM CVE-2026-42271 Patch Guide: Fix the RCE Chain

litellmsecurityselfhostedcveai

TL;DR: A command-injection flaw in LiteLLM’s MCP test endpoints (CVE-2026-42271, CVSS 8.7) lets an authenticated user run shell commands on your proxy host. Chain it with the Starlette “BadHost” header bypass (CVE-2026-48710) and the requirement to log in disappears — the pair scores CVSS 10.0 and is under active exploitation. CISA added it to the KEV catalog on June 8, 2026. Upgrade to LiteLLM 1.83.14 or later, then check whether you were already hit.

What you’ll have running after this guide:

  • A LiteLLM proxy on a patched build (≥ 1.83.14) with the MCP test endpoints locked to admins and Starlette ≥ 1.0.1
  • The gateway bound behind a reverse proxy with real auth, off the public internet, credentials rotated
  • An audit checklist that tells you whether an attacker already reached your host

Honest take: If your LiteLLM proxy has been reachable from the internet at any point since May, patching is step one but it is not the whole job — assume the API keys it holds are burned and rotate them.


What CVE-2026-42271 Actually Does

LiteLLM is the open-source AI gateway from BerriAI — an MIT-licensed Python proxy that puts one OpenAI-compatible endpoint in front of 100+ model providers, handles key management, budgets, and routing, and has become the default control plane for teams running mixed local-and-cloud model fleets. It sits in a nasty spot for a security bug: it holds every provider API key you’ve configured, and it’s usually the one service you deliberately expose so apps can reach it.

The flaw lives in LiteLLM’s Model Context Protocol (MCP) integration. Two endpoints let the UI preview an MCP server before you save it:

  • POST /mcp-rest/test/connection
  • POST /mcp-rest/test/tools/list

Both accept a full MCP server configuration in the request body — including the command, args, and env fields used by the stdio transport. When you “test” a stdio configuration, LiteLLM tries to connect, which means it spawns the command you supplied as a subprocess on the proxy host, running with the privileges of the LiteLLM process. Hand it command: "bash" with the right args and you have arbitrary command execution.

On its own, CVE-2026-42271 scores CVSS 8.7 and requires an authenticated user — bad, but not catastrophic if your auth is tight. The catastrophe is the chain.

Why This Is a CVSS 10.0, Not an 8.7

Horizon3.ai’s researchers paired the command injection with CVE-2026-48710, nicknamed “BadHost” — a Host-header validation bypass in Starlette, the ASGI framework LiteLLM is built on. Starlette versions ≤ 1.0.0 mishandle the Host header in a way that lets an attacker slip past path-based authentication middleware entirely. LiteLLM’s dependency tree pulled in a vulnerable Starlette, so the “you must be authenticated” gate in front of the MCP endpoints could be sidestepped with a crafted header.

Bypass the auth, then hit the subprocess-spawning endpoint, and you get unauthenticated remote code execution with no credentials required. That combination is what pushed the assessed severity to CVSS 10.0. It is being exploited in the wild — the whole reason CISA added the bug to its Known Exploited Vulnerabilities catalog.

POST /mcp-rest/test/connection HTTP/1.1
Host: <spoofed-to-bypass-auth>
Content-Type: application/json

{"transport":"stdio","command":"bash","args":["-c","<attacker command>"],"env":{}}

That request — no API key, no login — is the attack in one shot. The command/args payload runs on your box.

The Vulnerabilities You’re Actually Patching

CVE-2026-42271 arrived in the same window as a separate privilege-escalation chain that Obsidian Security disclosed, and the two get conflated in the coverage. They are different bugs with different fixed versions, so it’s worth being precise about what a full patch covers.

CVECVSSRoot causeFixed in
CVE-2026-422718.7 (10.0 chained)MCP test endpoints spawn a caller-supplied command as a subprocess1.83.7
CVE-2026-48710— (enables the chain)Starlette Host-header auth bypass (“BadHost”), ≤ 1.0.0Starlette 1.0.1
CVE-2026-47101part of 9.9 chainAuthz bypass: unvalidated allowed_routes on key-management endpoints1.83.14
CVE-2026-47102part of 9.9 chainMissing field-level auth on /user/update lets any user set their own user_role to proxy_admin1.83.14
CVE-2026-40217part of 9.9 chainCustom Code Guardrail exec() sandbox escape → RCE1.83.14

CVE-2026-42271 affects LiteLLM 1.74.2 through 1.83.6. The command-injection fix landed in 1.83.7 (May 8, 2026), which restricts the MCP test endpoints to the PROXY_ADMIN role and bumps the Starlette dependency to 1.0.1. But the Obsidian privilege-escalation chain — where a default low-privilege user promotes themselves to proxy_admin via /user/update and then reaches the guardrail RCE — wasn’t fully closed until 1.83.14.

So don’t stop at 1.83.7. Upgrade to 1.83.14 or later (or the current stable) to cover both the CISA-flagged RCE and the self-promotion chain in one move. There is no reason to pin to an intermediate version.

Step 1: Find Out What Version You’re Running

Do this before anything else.

# pip / uv install
pip show litellm | grep -i version
# → Version: 1.82.0    ← vulnerable (anything 1.74.2–1.83.13)

# Docker
docker inspect --format '{{ index .Config.Labels "org.opencontainers.image.version" }}' \
  $(docker ps -qf "ancestor=ghcr.io/berriai/litellm") 2>/dev/null
docker images | grep litellm      # fall back to the tag you pulled

# Live proxy — the metadata often reports the build
curl -s http://127.0.0.1:4000/health/readiness | python3 -m json.tool

Also confirm the Starlette version in the same environment, because a patched LiteLLM with an old Starlette still leaves the BadHost bypass usable elsewhere:

pip show starlette | grep -i version
# → anything ≤ 1.0.0 is vulnerable to CVE-2026-48710; you want ≥ 1.0.1

Step 2: Patch

# pip
pip install --upgrade "litellm>=1.83.14"

# uv
uv pip install --upgrade "litellm>=1.83.14"

# Docker — pull a pinned patched tag, not :latest floating in your compose
docker pull ghcr.io/berriai/litellm:v1.83.14-stable

If you run the Docker image, edit your docker-compose.yml to pin the tag rather than tracking a moving main-latest, then recreate:

services:
  litellm:
    image: ghcr.io/berriai/litellm:v1.83.14-stable
docker compose up -d --force-recreate litellm

Verify Starlette came along for the ride — a stale lockfile can hold it back:

pip install --upgrade "starlette>=1.0.1"

Step 3: If You Can’t Patch This Minute

Sometimes you can’t restart the proxy immediately. Buy time by cutting off the attack surface at the edge. Block the two test endpoints at your reverse proxy so nothing reaches the subprocess path:

# nginx — return 403 for the MCP test endpoints
location ~ ^/mcp-rest/test/ {
    return 403;
}

Then pull the gateway off the open internet entirely — bind it to localhost and only expose it through the authenticated reverse proxy:

# don't run the proxy on 0.0.0.0 in production
litellm --host 127.0.0.1 --port 4000

These are stopgaps. They close the specific known path, not the whole class of bug. Patch as soon as your change window allows.

Step 4: Assume Breach — Audit for Compromise

This is the step people skip, and it’s the one that matters if you were exposed. Because the chained exploit is unauthenticated and scriptable, mass scanning hit exposed LiteLLM instances quickly after disclosure. Check whether yours was one of them.

Search your access logs for hits on the vulnerable endpoints and for the privilege-escalation calls:

# requests to the MCP test endpoints — especially with shell metacharacters
grep -E "/mcp-rest/test/(connection|tools/list)" access.log

# command injection markers in the body/query (;, |, backtick, $() )
grep -E "/mcp/test.*(%3B|%7C|%60|%24%28|;|\||\`)" access.log

# self-promotion attempts: user_role in /user/update or /user/bulk_update
grep -E "/user/(update|bulk_update)" access.log | grep -i "user_role"

# unusual Host headers (BadHost bypass leaves odd values)
grep -iE "Host: " access.log | sort | uniq -c | sort -rn | head

On the host itself, look for the aftermath: unexpected outbound connections, subprocesses spawned by the LiteLLM process, new cron entries, or SSH keys you didn’t add.

# processes whose parent is the litellm proxy
ps -ef | grep -i litellm
pstree -p $(pgrep -f litellm | head -1)

If you find any of these signatures — or if the proxy was internet-facing and you simply can’t rule it out — treat the API keys LiteLLM held as compromised and rotate every provider key it had access to (OpenAI, Anthropic, your local endpoints’ tokens, cloud credentials), plus the LiteLLM master key and any virtual keys minted through it. A stolen key is the whole prize here; patching without rotating leaves the door open.

The Bigger Pattern: AI Gateways Are Now Targets

CVE-2026-42271 is not an isolated LiteLLM problem. The same codebase had a separate PyPI supply-chain incident earlier in 2026, and the Obsidian privilege-escalation chain landed in the same season. The through-line: AI gateways have become high-value infrastructure — they concentrate credentials and sit at the network edge — and attacker attention has followed. Langflow went through the identical arc with a run of unauthenticated RCEs, which we covered in the Langflow security hardening guide, and exposed Ollama instances told the same story in our Ollama security guide.

The defensive posture is the same across all of them: never put the raw admin surface on the public internet, keep the dependency tree current (BadHost was a Starlette bug that became a LiteLLM RCE), and treat any credential the service touches as burnable. If you’re building out a self-hosted stack, bake that in from the start rather than bolting it on after a KEV entry forces your hand.

When This Doesn’t Apply to You

If your LiteLLM is bound to 127.0.0.1, reachable only from inside a private network segment, and you don’t use the MCP integration at all, the unauthenticated chain can’t reach you from outside — you’re exposed only to an already-authenticated internal user. That’s a real reduction in urgency, not an all-clear: CVE-2026-47102 still lets any user who can reach /user/update promote themselves to admin, so a shared internal instance with untrusted users is still on the hook. Patch anyway. The upgrade is a version bump, not a migration, and there’s no benefit to sitting on a known-exploited build.

FAQ

Is my LiteLLM affected if I don’t use MCP servers? The command-injection endpoint exists regardless of whether you’ve configured any MCP servers — the test endpoints are always present in vulnerable versions. Not using MCP does not protect you. Patch.

Does upgrading only LiteLLM fix everything? Upgrading to 1.83.14+ pulls in a fixed Starlette (≥ 1.0.1) as a dependency, which closes the BadHost bypass for LiteLLM. But confirm Starlette actually upgraded in your environment — a pinned or cached lockfile can hold back the transitive dependency. Run pip show starlette.

What’s the difference between 1.83.7 and 1.83.14? 1.83.7 fixed the CISA-flagged command-injection RCE (CVE-2026-42271). 1.83.14 additionally fixed the Obsidian-disclosed privilege-escalation chain (CVE-2026-47101/47102/40217) that lets a low-privilege user become proxy_admin. Go to 1.83.14+ to cover both.

I patched the day it came out. Do I still need to rotate keys? If your instance was internet-reachable before you patched, yes. Active exploitation and mass scanning began before many operators upgraded. Patching stops future access; it does nothing about keys already exfiltrated.

Is LiteLLM safe to keep using after all this? Yes — it’s still MIT-licensed, actively maintained, and the maintainers shipped fixes and hardening quickly. The lesson isn’t “drop LiteLLM,” it’s “don’t run an AI gateway naked on the internet.” Every project in this category has had its turn.

Sources

Was this article helpful?