The Key Was in the Quickstart: 294 LiteLLM Gateways Still Answer to sk-1234
Neha10 min read
SECRETS MANAGEMENT-CODE-SECURITY#ai-security#credential-theft#cloud-security

The Key Was in the Quickstart: 294 LiteLLM Gateways Still Answer to sk-1234

Wiz scanned 3,074 internet-facing LiteLLM gateways and found 294 accepting sk-1234, the key printed in the docs. That key signs session tokens and opens a path to your cloud credentials.

Share:

In February 2026, Wiz Research pointed Shodan at LiteLLM and found 3,074 gateways sitting on the public internet. 294 of them accepted sk-1234 as the administrator key. That is the literal string LiteLLM prints in its own quickstart guide, its Docker Compose example, and its configuration tutorials. As of the publication of Wiz's writeup on 9 September, the setup guide still showed it.

9.6 percent. Roughly one in ten.

The number that stopped me, though, was buried one level deeper. Of those 294, 191 had no master key configured at all. Any string would have worked. sk-1234 just happened to be the one Wiz tried. So the real split is about 103 operators who copied the docs and never edited the value, and 191 who never set the value in the first place, and before version 1.82.0-stable that second group was handing PROXY_ADMIN to every inbound request by default.

I have been writing about identity attacks on this blog for most of a year, and I keep coming back to the same shape: the interesting part is never the exploit. It is what the credential turns out to be wired into.

What sk-1234 is actually doing in there

Most people read "default admin key" and mentally file it next to admin/admin on a forgotten Jenkins box. Annoying, contained, someone's problem on Tuesday.

LiteLLM's master key does four jobs at once.

It authenticates admin API calls, which is the obvious one. It gates the configuration endpoints that let you register guardrails and pass-through routes. It is sitting in the container environment alongside the actual model-provider keys, the database connection string, and the virtual-key records. And, the part that makes this structurally different: it doubles as the HS256 secret used to sign session JWTs.

Read that again. The signing secret for every session token the proxy issues is a value published in a tutorial. If you never changed it, an attacker does not need to steal a session. They mint one, for any user they like, across the whole proxy, offline, with no request to your server until the forged token is already valid.

Wiz's telemetry puts LiteLLM in roughly one third of the cloud environments they see. It is the plumbing layer nobody puts on the crown-jewels list, because it got introduced by a platform team as "just a proxy so we can switch models without refactoring."

One character was enough

The pre-auth bug got the CVE and the headlines. CVE-2026-59822, CVSS 8.8, fixed in 1.84.0 on 25 April.

The flaw lives in user_api_key_auth_mcp.py. LiteLLM supports two ways of authenticating to its MCP layer, native LiteLLM keys and OAuth2 passthrough, and the handler could not tell a real upstream token from garbage. So it caught the 401 and quietly returned an empty auth object instead of failing:

except HTTPException as e:
    if e.status_code in (401, 403):
        validated_user_api_key_auth = UserAPIKeyAuth()  # bypass

The exploit is one request. Authorization: Bearer a. A single character. You get an HTTP 200 and an mcp-session-id header, and from there the ability to call MCP tools with arbitrary arguments. Which tools depends on config, and LiteLLM's docs recommend the allow_all_keys flag for "internal knowledge bases, calendar integrations, or other low-risk utilities." Your internal knowledge base is a low-risk utility right up until an unauthenticated stranger can query it.

Credit where it is due: Wiz was precise about the limits here. This bypass gets you MCP access only. It does not chain into the post-auth root execution they found separately. Half the coverage I read this week blurred those two together.

CISA added CVE-2026-59822 to the Known Exploited Vulnerabilities catalog on 2 September, with a federal remediation deadline of 16 September, which is tomorrow as I write this.

Where IMDSv2 stops helping you

Here is the part of the research with no CVE, no patch, and no plan for one.

LiteLLM's pass-through endpoints let an admin forward requests to an arbitrary target URL. There is no validation on that target. No check against private ranges, no check against localhost, no check against cloud metadata addresses. Register a route pointing at 169.254.169.254, walk the subpath, and read IAM credentials out of the instance metadata service.

The usual answer is "we run IMDSv2, token-required, we're fine." You are not. LiteLLM forwards any header prefixed with x-pass- after stripping the prefix, so x-pass-X-aws-ec2-metadata-token-ttl-seconds: 21600 arrives at IMDS as a perfectly legitimate token request. Wiz's assessment is blunt: this renders IMDSv2 protections ineffective. The prefix behaviour is documented. It works as designed.

So the chain reads: default key from a tutorial, admin on the config API, register a route to the metadata service, receive ASIA... credentials belonging to whatever role you attached to the pod. Then you are no longer attacking an AI proxy. You are inside the account, authenticated, with a role that a platform engineer scoped generously in month one because nothing was in production yet.

Sysdig's original LLMjacking research priced the narrower version of this outcome at over $46,000 per day when attackers max out stolen model access across regions. The cloud-credential version has no ceiling like that. It has a blast radius instead.

The detail almost nobody quoted

Wiz re-ran the scan in August and counted over 85,000 LiteLLM instances. They immediately discounted the number, because the majority of them "appear to be honeypots or test deployments."

Sit with that for a second. In six months, the internet-facing population of a specific AI gateway went from three thousand real deployments to eighty-five thousand, and most of the growth was defenders and researchers standing up fakes. The genuine attack surface got swamped by decoys, to the point where the researchers who found the bugs could no longer measure it.

That is deception working exactly as intended, at internet scale. Attacker reconnaissance stopped being reliable.

And it paid off in the one way that matters. Wiz saw CVE-2026-59822 exploited in their own honeypot on 7 July. The CVE was published on 8 July. The decoy caught real exploitation with single-character bearer tokens one day before the vulnerability was public knowledge. The same honeypots later recorded CVE-2026-42271, the CVSS 8.7 MCP test-endpoint command execution flaw Horizon3.ai reported in June, being used to install a cryptocurrency miner.

No signature existed. No EDR rule existed. There was nothing to tune, because the entire detection was "a system that has no legitimate users received a request."

Now ask the uncomfortable question. Those honeypots were on the public internet, where the noise floor is high and researchers expect scanning. Your LiteLLM gateway is probably on an internal subnet, reachable from every workload in the VPC, holding provider keys and a database connection string. Which of those two environments would produce a cleaner signal from a single unexpected request?

Internal decoys are strictly better than internet ones for exactly this reason, and almost nobody deploys them there. It is the same gap I wrote about in the shadow identity problem behind stolen AI sessions: the AI layer accumulated real privilege faster than it accumulated monitoring.

Whose bug is it, though

There is an honest disagreement running underneath this story, and it deserves more than a footnote.

LiteLLM's published security policy treats configuration mistakes, including failing to set a master key, as explicitly not in scope. By that reading, sk-1234 is not a vulnerability. It is a deployment error, and 191 gateways running with no key at all are 191 people who did not read the docs.

They are not wrong about the mechanics. They are wrong about the outcome. When one in ten internet-facing deployments lands in the same failure state, that is not a hundred unrelated mistakes, it is a default doing what defaults do. Shipping a memorable placeholder that also functions as your JWT signing secret is a design decision, not a user error.

The same tension shows up on CVE-2026-59821. Wiz demonstrated the guardrail path returning uid=0(root) gid=0(root) inside the gateway container. LiteLLM's advisory rates the identical issue 2.1, Low, on the grounds that it needs a high-privilege account. Both statements are true at once. They just answer different questions, and only one of them is the question a defender is asking.

Pick your side, but pick it knowing that "trusted administrator" is doing enormous load-bearing work in the vendor's threat model, and the first section of this post is a measurement of how often that trust is misplaced.

What I would do this week

Short list, ordered by how fast it pays off.

Change the master key. Today. Long random value, no upgrade required. One caveat that Wiz and the maintainers both flag: check whether a separate salt key is configured first, because the rotation procedure differs and doing it the wrong way can leave stored credentials unreadable.

Upgrade to 1.84.0 or later. If you cannot, block /mcp/ plus POST /mcp-rest/test/connection and POST /mcp-rest/test/tools/list at the proxy, and restrict POST /guardrails and PUT /guardrails/{guardrail_id} to admins.

Audit your pass-through endpoints and cut container egress. This one has no patch coming. Treat it as a permanent config responsibility. Narrow the IAM role the gateway runs under while you are in there.

Assume the patch did not evict anyone. Upgrading removes neither attacker-registered guardrails nor added SSH keys, and in-memory guardrail code survives until you restart the process. Rotate provider keys, the master key, and database credentials. If you have read why patching Artifactory does not evict anyone, this is the same lesson wearing a different logo: the fix closes the door, it does not clear the room.

Then plant something that has no reason to be touched. A decoy provider API key in /app/.env next to the real ones, because file-read payloads targeting .env and config.yaml are exactly what scanners go for. A fake virtual-key row in the database. A decoy service standing in for the gateway port on a host that runs nothing. A set of cloud mine credentials whose only purpose is to page you the instant they are used against your account.

None of that depends on knowing the next CVE number. That is the whole point. Automated credential harvesting has been an industrial pipeline for a while now, as the 2,975 keys the Zerofot scanner pulled in 48 days made clear, and a pipeline does not check whether a key is real before trying it. It just tries everything. Give it something to find that costs you nothing and tells you everything.

Wiz's closing argument is that AI gateways need to be treated as Tier-1 security assets rather than developer tools. I would go one step further. Your LiteLLM instance is a secrets store that happens to speak HTTP, and you would never let a secrets store sit on an internal network with no alerting on unexpected access. Book a walkthrough and we will show you what a decoy key in that container environment looks like the moment someone reads it.

M2

Neha

Cloud Security Architect, Mine2

Neha works on cloud and identity security at Mine2, covering SaaS, OAuth, and the credential-theft paths attackers favour in the cloud.

Share this article

Secure Your Network Today

Ready to implement advanced cyber deception in your organization? See how MINE2 can transform your threat detection capabilities.