A LiteLLM Enterprise proxy will leak its master key to a request with no API key. Upgrade to 1.106.5 (GHSA-w4c7-34wj-hqm8)

4 min read

How to fix GHSA-w4c7-34wj-hqm8: upgrade litellm to 1.106.5, 1.105.6, 1.104.8 or 1.103.10, restart, then rotate LITELLM_MASTER_KEY. An unauthenticated request could make an Enterprise-licensed LiteLLM proxy read its own process environment and send it to an attacker host. CVSS 10.0.

BREAKING: A LiteLLM Enterprise proxy will leak its master key to a request with no API key. Upgrade to 1.106.5 (GHSA-w4c7-34wj-hqm8)
On this page

A LiteLLM proxy running with an Enterprise license can be made to read a file off its own disk and send the contents to a server the attacker picks, from a request that carries no API key at all. Read /proc/self/environ that way and the attacker walks off with LITELLM_MASTER_KEY and every provider key in the environment. BerriAI published the advisory, GHSA-w4c7-34wj-hqm8, on Oct 27 at 4:33 PM ET and rates it critical, CVSS 10.0. No CVE ID yet.

The fixed builds went to PyPI about an hour before the advisory: 1.103.10, 1.104.8, 1.105.6 and 1.106.5. Their release notes file the change under "Logging and observability" and say "No action needed to upgrade." That line is about config compatibility. If you run Enterprise, you need the upgrade tonight.

How to fix

Upgrade to the fixed build on your train, then restart the proxy:

pip install --upgrade "litellm[proxy]==1.106.5"   # or 1.105.6 / 1.104.8 / 1.103.10 on older trains
# Docker
docker pull ghcr.io/berriai/litellm:v1.106.5

Do not reach for 1.107.0. That is the release that shipped a credential stealer on Oct 21, and PyPI no longer serves any files for it. 1.106.5 is the newest clean stable build. Each release page carries a cosign verify command; run it, and pin the image by digest.

Then treat the master key as burned if the proxy was reachable by anyone you do not trust:

  • Rotate LITELLM_MASTER_KEY and the provider API keys that sat in the proxy's environment.
  • If you never set LITELLM_SALT_KEY, LiteLLM uses the master key to encrypt the model credentials it stores in its database. Follow LiteLLM's rotation docs instead of just swapping the env var, or those stored credentials stop decrypting.
  • BerriAI's own defense-in-depth list: load the master key from a secret manager instead of the process environment, set a separate LITELLM_SALT_KEY, and limit the proxy's outbound traffic to the provider endpoints you actually use.

What the patch changes

The fix is PR #48599, titled fix(security)!: build proxy-only failure logs from an allowlist. When the proxy rejects a request (bad key, rate limit, budget, guardrail), it still writes a failure log. Before the fix, that log was built straight from the raw request body. So the caller, with no valid key, could set the logging fields that normally belong to the operator.

Two of those fields are the whole story. LiteLLM supports per-request logging parameters such as langfuse_host, langsmith_base_url, gcs_bucket_name and gcs_path_service_account. The PR says a rejected request "can send that log to its own Langsmith or Langfuse host" and "can also pick the GCS bucket and service account". A service-account path is a file the proxy opens. A logging host is where the proxy sends data. Put those two in the caller's hands and you have the read-a-file, ship-it-out chain the advisory describes.

After the patch, failure logs for rejected requests keep only model, messages, input, prompt, user, stream and litellm_call_id, plus tags and guardrail details from metadata. The GCS logger only uses the bucket and service account it was configured with. The same PR also stops callers from forging guardrail cost on keys with allow_client_pricing_override.

The advisory adds that in some configurations, once the attacker holds the master key, they can run arbitrary Python as root. The master key is full admin on the proxy, so plan for that case.

Check your proxy

Two questions: which version, and is a license loaded. The license comes from the LITELLM_LICENSE environment variable.

docker exec litellm sh -c 'pip show litellm | grep ^Version; [ -n "$LITELLM_LICENSE" ] && echo "enterprise license set"'

If that prints a version below the fixed build on your train and "enterprise license set", you were exposed. To look for use, search anything that recorded request bodies (WAF, API gateway, LiteLLM's own spend or failure logs) for gcs_path_service_account, langfuse_host or langsmith_base_url on requests that got a 401. Legit clients almost never send those. Also check egress from the proxy host for HTTPS to anything other than your model providers and your configured Langfuse or LangSmith.

Who is not in scope

  • Open source LiteLLM proxies with no Enterprise license. BerriAI says the vulnerable code paths only load when a license is active.
  • Apps that import the litellm Python SDK and never run the proxy server. The advisory is about the proxy's LLM routes.
  • Anyone already on 1.103.10, 1.104.8, 1.105.6 or 1.106.5.

What this is not

This is not another poisoned release like 1.107.0. The packages were fine; the bug was in how the proxy logged requests it had already refused. The advisory reports no exploitation, and CISA has not listed it.

It does rhyme with LiteLLM's own week, though. The 1.107.0 compromise started with a master key for LiteLLM's internal agent platform that leaked and was never revoked. A master key in a process environment is one file read away from the internet. If your AI gateway holds every provider key you own, it deserves the same egress rules as your payment service.

Credit: Dylan Ong at Karmasec found it first; Cyrill Bannwart of Compass Security reported it independently.

References

All articles

Keep exploring

The engineering desk continues across the ecosystem: security research on shipping agents safely, and plugins that put the standards to work.