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: trueundergeneral_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 24 | 1.82.7 and 1.82.8 published to PyPI at 10:39 UTC; quarantined about 40 minutes later |
| Mar 27 | LiteLLM attributes the breach to an unpinned Trivy dependency in CI |
| Mar 30 | Clean 1.83.0 announced from the new CI/CD v2 pipeline |
| Apr 13 | 1.83.7 uploaded to PyPI, fixing CVE-2026-42208 and CVE-2026-42271 |
| Apr 24 and 25 | GitHub advisories for both CVEs published |
| May 8 | NVD publishes both CVEs; CISA adds CVE-2026-42208 to KEV |
| May 14 | 1.84.0 released with the Host header auth fix |
| May 21 | Starlette 1.0.1 released |
| Jun 1 | LiteLLM publishes the Host header advisory (GHSA-4xpc-pv4p-pm3w) |
| Jun 8 | CISA adds CVE-2026-42271 to KEV |
| Issue | Affected | Fixed in |
|---|---|---|
| Malicious PyPI releases | 1.82.7, 1.82.8 | 1.83.0 (1.82.6 and earlier audited clean) |
| CVE-2026-42208, SQL injection | 1.81.16 through 1.83.6 | 1.83.7 |
| CVE-2026-42271, MCP command injection | 1.74.2 through 1.83.6 | 1.83.7 |
| Host header auth bypass (CVE-2026-48710 in Starlette) | LiteLLM proxy before 1.84.0; Starlette 1.0.0 and earlier | LiteLLM 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_versionTo 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]}")
EOFSome 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:
- Every upstream provider key the gateway held (OpenAI, Anthropic, cloud model endpoints).
- Cloud credentials, SSH keys and Kubernetes tokens present on the host or in its environment.
- The proxy's master key and database password.
- Virtual keys. LiteLLM supports
POST /key/{key}/regeneratewith an optionalgrace_periodso 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.txtPin 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
- LiteLLM, Security Update: Suspected Supply Chain Incident (March 24, 2026, updated March 30)
- LiteLLM, Security Townhall Updates (March 27, 2026)
- LiteLLM, Announcing CI/CD v2 for LiteLLM (March 30, 2026)
- GitHub, GHSA-r75f-5x8p-qvmc: SQL Injection in Proxy API key verification (April 24, 2026)
- GitHub, GHSA-v4p8-mg3p-g94g: Authenticated command execution via MCP stdio test endpoints (April 25, 2026)
- LiteLLM, Security Update: CVE-2026-42208 in LiteLLM Proxy (April 29, 2026)
- NVD, CVE-2026-42208 and CVE-2026-42271
- CISA, Known Exploited Vulnerabilities Catalog (CVE-2026-42208 added May 8, 2026; CVE-2026-42271 added June 8, 2026)
- Starlette, GHSA-86qp-5c8j-p5mr: missing Host header validation and NVD CVE-2026-48710
- LiteLLM, Authentication Bypass via Host Header Injection (GHSA-4xpc-pv4p-pm3w) (June 1, 2026)
- Horizon3.ai, CVE-2026-42271 chained with CVE-2026-48710
- The Hacker News, LiteLLM Flaw CVE-2026-42271 Exploited in the Wild (June 9, 2026)
- Python documentation, site: site-specific configuration hook
- LiteLLM docs, Virtual Keys
