Home/Blog

Your AI Gateway Is the New Crown Jewel: LiteLLM's 2026

LiteLLM's poisoned PyPI releases, a pre-auth SQL injection and an MCP command injection, both in CISA KEV. What to check, rotate and lock down.

Your AI Gateway Is the New Crown Jewel: LiteLLM's 2026

Your AI Gateway Is the New Crown Jewel: LiteLLM's 2026

On March 24, 2026, two poisoned releases of LiteLLM (1.82.7 and 1.82.8) were published to PyPI and stayed live for about 40 minutes. In April the project disclosed a pre-auth SQL injection in the proxy's API key check (CVE-2026-42208) and a command injection in its MCP test endpoints (CVE-2026-42271). CISA added the first to its Known Exploited Vulnerabilities catalog on May 8 and the second on June 8. If you run the LiteLLM proxy, or any Python environment that pulled litellm without a pinned version, this affects you. And if you run any AI gateway at all, LiteLLM's year is the clearest case yet for treating that gateway like a vault.

Why the gateway is worth attacking

An AI gateway exists to concentrate things. One proxy holds the OpenAI, Anthropic, Bedrock, Vertex and Azure credentials so that application teams do not have to. It issues its own virtual keys, tracks spend, logs prompts and, increasingly, launches MCP servers on behalf of agents.

That design is sound for cost control and routing. It also means a single process, and usually a single Postgres database, holds every provider key your company has. CISA's own KEV entry for the SQL injection describes the impact in those terms: an attacker can read the proxy's database "leading to unauthorized access to the proxy and the credentials it manages" (CISA KEV).

Three different failure modes hit the same product in under three months: the build pipeline, the authentication path and an admin feature. Each one on its own ends with your provider keys in someone else's hands.

Incident 1: the PyPI releases (March 24)

LiteLLM's incident post states that litellm==1.82.7 and litellm==1.82.8 "were live on March 24, 2026 from 10:39 UTC for about 40 minutes before being quarantined by PyPI." The team treats anyone who installed or upgraded via pip between 10:39 and 16:00 UTC that day as potentially affected.

The two versions were not identical:

  • 1.82.7 carried a malicious payload in the gateway's proxy_server.py. It ran when that module loaded.
  • 1.82.8 carried the same payload plus a file named litellm_init.pth.

The .pth file is the part worth understanding. Python's site module processes every .pth file in site-packages at interpreter startup, and any line that begins with import is executed. So a .pth file runs on every Python process in that environment: your test runner, your linter, an unrelated script. Nothing has to import litellm.

Per LiteLLM, the payload harvested environment variables, SSH keys, AWS, GCP and Azure credentials, Kubernetes tokens and database passwords, then encrypted them and sent them by POST to models.litellm.cloud, which is not a LiteLLM domain. The team later added checkmarx[.]zone to the indicators of compromise.

How it happened. LiteLLM's townhall write-up (March 27) names three causes. Their CI ran on CircleCI in one shared environment. PyPI, GHCR and Docker release credentials sat there as static environment variables. And the security scanning step used an unpinned Trivy dependency: "a compromised Trivy package ran during the scan, had access to environment variables, and enabled attackers to obtain those credentials." The tool that was meant to scan for supply chain risk was the entry point.

The official proxy Docker image (ghcr.io/berriai/litellm) was not affected, because it pins dependencies in requirements.txt. LiteLLM published audited SHA-256 checksums for releases from 1.78.0 through 1.82.6, and announced a clean 1.83.0 on March 30, built by a new CI/CD v2 pipeline with isolated jobs, PyPI Trusted Publishing and cosign-signed images.

We walked through the same pattern for npm in our Axios supply chain post. The lesson carries over: a release credential in a shared CI environment is one compromised dependency away from being someone else's.

Incident 2: SQL injection in key verification (CVE-2026-42208)

The GitHub advisory GHSA-r75f-5x8p-qvmc describes a query in the proxy's API key check that "mixed the caller-supplied key value into the query text instead of passing it as a separate parameter." An unauthenticated attacker could send a crafted Authorization header to any LLM route, such as POST /chat/completions, and reach that query through the proxy's error-handling path.

  • Affected: 1.81.16 through 1.83.6
  • Fixed: 1.83.7 (LiteLLM recommends 1.83.10-stable)
  • CVSS 3.1: 9.8
  • Workaround if you cannot upgrade: set disable_error_logs: true under general_settings, which removes the path that carries unauthenticated input to the query

Read that again: the credential check itself was the injection point. The one component that every request must pass through was the one that talked to the database with attacker text. NVD published the CVE on May 8, and CISA listed it in KEV the same day with a remediation due date of May 11, three days later.

LiteLLM also published a helper query for reviewing Postgres query history if your proxy was reachable from an untrusted network while on an affected version.

Incident 3: MCP test endpoints that run commands (CVE-2026-42271)

LiteLLM lets admins register MCP servers. To preview one before saving it, the proxy exposed two endpoints: POST /mcp-rest/test/connection and POST /mcp-rest/test/tools/list. Per GHSA-v4p8-mg3p-g94g, both accepted a full server config, including the command, args and env fields of the stdio transport. Calling them with a stdio config spawned that command as a subprocess on the proxy host.

The endpoints required a valid proxy API key but checked no role. Any key holder, "including holders of low-privilege internal-user keys", could run arbitrary commands with the proxy's privileges.

  • Affected: 1.74.2 through 1.83.6
  • Fixed: 1.83.7, where both endpoints require PROXY_ADMIN
  • CVSS 3.1: 8.8
  • Workaround: block both paths at your reverse proxy

CISA added CVE-2026-42271 to KEV on June 8 with a due date of June 22. As The Hacker News reported on June 9, there is no public detail yet on who is exploiting it or how widely.

The chain. On its own, CVE-2026-42271 needs a key. Researchers at Horizon3.ai showed it can be chained with CVE-2026-48710, a Starlette flaw where an unvalidated Host header makes request.url.path differ from the path actually routed (Starlette advisory). LiteLLM's auth layer derived the route from request.url.path, so a crafted Host header could make a protected route look public. LiteLLM's own host header advisory (June 1) says the fix shipped in 1.84.0, which now reads the route from the ASGI scope path. Starlette fixed the parsing in 1.0.1. Put together, a vulnerable, internet-reachable proxy is an unauthenticated remote shell on the box that holds your provider keys.

If you have been reading our MCP guide, this is the stdio transport's risk made concrete: "connect to a server" and "execute a program" are the same operation.

Timeline and affected versions

Date (2026)Event
Mar 241.82.7 and 1.82.8 published to PyPI at 10:39 UTC; quarantined about 40 minutes later
Mar 27LiteLLM attributes the breach to an unpinned Trivy dependency in CI
Mar 30Clean 1.83.0 announced from the new CI/CD v2 pipeline
Apr 131.83.7 uploaded to PyPI, fixing CVE-2026-42208 and CVE-2026-42271
Apr 24 and 25GitHub advisories for both CVEs published
May 8NVD publishes both CVEs; CISA adds CVE-2026-42208 to KEV
May 141.84.0 released with the Host header auth fix
May 21Starlette 1.0.1 released
Jun 1LiteLLM publishes the Host header advisory (GHSA-4xpc-pv4p-pm3w)
Jun 8CISA adds CVE-2026-42271 to KEV
IssueAffectedFixed in
Malicious PyPI releases1.82.7, 1.82.81.83.0 (1.82.6 and earlier audited clean)
CVE-2026-42208, SQL injection1.81.16 through 1.83.61.83.7
CVE-2026-42271, MCP command injection1.74.2 through 1.83.61.83.7
Host header auth bypass (CVE-2026-48710 in Starlette)LiteLLM proxy before 1.84.0; Starlette 1.0.0 and earlierLiteLLM 1.84.0; Starlette 1.0.1

The practical floor today: LiteLLM 1.84.0 or later, running on Starlette 1.0.1 or later.

What to do this week

1. Find every copy and check the version

The proxy is the obvious one. The SDK hiding inside an agent framework's dependency tree is the one that gets missed.

# Every Python environment you can reach: venvs, CI images, notebooks
pip show litellm starlette 2>/dev/null | grep -E '^(Name|Version)'
 
# Who pulled litellm in?
pip install pipdeptree && pipdeptree --reverse --packages litellm
 
# A running proxy reports its version on the readiness check
curl -s https://llm-gw.internal/health/readiness | jq .litellm_version

To fail a CI job on a bad version:

from importlib.metadata import version, PackageNotFoundError
from packaging.version import Version
 
try:
    v = Version(version("litellm"))
except PackageNotFoundError:
    raise SystemExit(0)
 
if str(v) in ("1.82.7", "1.82.8"):
    raise SystemExit(f"litellm {v} is a known malicious release")
if v < Version("1.84.0"):
    raise SystemExit(f"litellm {v} is below the 1.84.0 floor")
if Version(version("starlette")) < Version("1.0.1"):
    raise SystemExit("starlette is below 1.0.1")

For the March window specifically, LiteLLM's incident post links scripts that scan GitHub Actions and GitLab CI job logs for installs of the two bad versions.

2. Look for .pth files that execute code

This check is worth keeping after the incident. It lists every line in every .pth file that Python will execute at startup:

python - <<'EOF'
import site, pathlib
dirs = site.getsitepackages() + [site.getusersitepackages()]
for d in dirs:
    for p in pathlib.Path(d).glob("*.pth"):
        for line in p.read_text(errors="replace").splitlines():
            if line.startswith(("import ", "import\t")):
                print(f"{p}: {line[:160]}")
EOF

Some legitimate packages (setuptools, editable installs, coverage tools) ship executable .pth lines, so baseline the output on a clean image and alert on anything new. A direct hit on litellm_init.pth means that host is compromised: remove the file, preserve the artifacts and treat every secret the host could read as stolen.

3. Rotate in the right order

If you ran 1.82.7 or 1.82.8, or ran an affected proxy that untrusted clients could reach, rotate:

  1. Every upstream provider key the gateway held (OpenAI, Anthropic, cloud model endpoints).
  2. Cloud credentials, SSH keys and Kubernetes tokens present on the host or in its environment.
  3. The proxy's master key and database password.
  4. Virtual keys. LiteLLM supports POST /key/{key}/regenerate with an optional grace_period so clients can move over without an outage.

Then review your provider billing dashboards for usage you cannot account for, and hunt egress logs for models.litellm.cloud and checkmarx.zone.

4. Take the admin surface off the network

A gateway's inference routes may need to be reachable by many services. Its admin UI, key management routes and MCP test endpoints should not be reachable by anything but an admin network. At minimum, in front of the proxy:

server {
    listen 443 ssl default_server;
    server_name _;
    return 444;
}
 
server {
    listen 443 ssl;
    server_name llm-gw.internal;
 
    location ^~ /mcp-rest/test/ { return 403; }
    location ^~ /ui/            { allow 10.20.0.0/24; deny all; proxy_pass http://litellm:4000; }
    location ^~ /key/           { allow 10.20.0.0/24; deny all; proxy_pass http://litellm:4000; }
 
    location / {
        proxy_set_header Host llm-gw.internal;
        proxy_pass http://litellm:4000;
    }
}

Two details matter. The catch-all default_server drops requests with unexpected Host values, and the explicit proxy_set_header Host stops a client-supplied value reaching the app. LiteLLM's advisory warns that forwarding the client's Host unchanged "may not fully protect" you, and that edge filtering is a stopgap, not a substitute for upgrading. This is the same segmentation argument we make in our zero-trust guide: a gateway should be reachable by name only from the networks that need it.

5. Give every team a key with a ceiling

Do not hand the master key to applications. Create teams and issue scoped virtual keys:

curl -s https://llm-gw.internal/key/generate \
  -H "Authorization: Bearer $LITELLM_MASTER_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "team_id": "search-team",
    "models": ["search-default"],
    "max_budget": 200,
    "budget_duration": "30d",
    "rpm_limit": 300
  }'

A leaked team key is then limited to one model alias and a monthly spend cap. It also narrows who can reach authenticated bugs like CVE-2026-42271 in the first place: fewer keys, fewer holders.

6. Limit what the gateway can reach

The March payload needed an outbound POST to work. A gateway only needs to talk to your model providers, its database and your logging backend. Route its egress through a proxy with a domain allowlist and deny the rest. That turns an exfiltration into a blocked connection and a log line.

7. Pin and hash your Python dependencies

The official Docker image survived because it pinned. Do the same for every service that installs litellm, and add hashes so a republished or swapped file fails to install:

# Compile exact versions with hashes
uv pip compile requirements.in --generate-hashes -o requirements.txt
 
# Install refuses anything without a matching hash
pip install --require-hashes --no-deps -r requirements.txt

Pin your CI tooling too. The LiteLLM compromise came through an unpinned scanner, not the application's own dependencies. If you use the proxy image, verify its cosign signature before deploying, using the key pinned to commit 0112e53 as LiteLLM documents. Our software supply chain guide covers lockfiles, provenance and CI isolation in more depth.

The takeaway

None of these three bugs is exotic. A leaked CI secret, string-built SQL and a missing role check are problems every engineering team has seen. What made them serious is where they lived. An AI gateway holds the credentials for every model you pay for, so it deserves the treatment you give a secrets manager: private network, narrow admin access, scoped keys, pinned builds and egress rules. If you run LiteLLM, get to 1.84.0 or later on Starlette 1.0.1 or later this week, then work down the list above.

If you want a second pair of eyes on how your gateway is deployed, get in touch.

Sources