high

CVE

CVE-2026-59822

CWE

CWE-287, CWE-306

Affected Surface

  • LiteLLM `litellm < 1.84.0`
  • LiteLLM proxy deployments that expose MCP Streamable HTTP routes such as `/mcp/{server}` or `/{server}/mcp` to untrusted networks
  • Connected MCP servers and downstream services reachable through those LiteLLM-managed MCP routes

CISA added CVE-2026-59822 to the Known Exploited Vulnerabilities catalog on 2 September 2026. That timing matters more than the June disclosure date. The bug was already serious on paper. The KEV entry means defenders now have public confirmation that attackers are not treating it as theoretical.

The affected component is LiteLLM’s MCP Streamable HTTP auth path. In litellm < 1.84.0, the code tried to support two different meanings for the same Authorization: Bearer ... header:

  1. a normal LiteLLM API key
  2. an OAuth2 token that should be passed through to an upstream MCP server

The dangerous part was not the idea of passthrough by itself. It was the fallback rule the implementation used after a failed LiteLLM auth check.

The vulnerable auth path

The advisory, NVD record, and patch all line up on the same control flow inside litellm/proxy/_experimental/mcp_server/auth/user_api_key_auth_mcp.py.

Before 1.84.0, the relevant branch effectively looked like this:

elif oauth2_headers:
    try:
        validated_user_api_key_auth = await user_api_key_auth(
            api_key=litellm_api_key, request=request
        )
    except HTTPException as e:
        if e.status_code in (401, 403):
            validated_user_api_key_auth = UserAPIKeyAuth()
    except ProxyException as e:
        if str(e.code) in ("401", "403"):
            validated_user_api_key_auth = UserAPIKeyAuth()

That is the whole trust failure.

A caller could send an arbitrary Bearer token, trigger a 401 or 403 from the normal LiteLLM key validator, and still receive an empty UserAPIKeyAuth() object instead of a hard rejection. The code path was meant to preserve OAuth2 passthrough for upstream MCP servers. In practice it let failed auth collapse into anonymous success.

The result was:

Authorization: Bearer attacker-controlled-garbage
-> LiteLLM tries normal API-key validation
-> validation fails with 401 or 403
-> fallback creates empty UserAPIKeyAuth()
-> request continues into MCP tooling

That is why the CVE is better understood as an auth-boundary failure than as a narrow parser bug. The request did not need a valid LiteLLM key. It only needed to look enough like the code’s OAuth2 compatibility case to reach the fallback.

Why the passthrough logic was too broad

LiteLLM had a real reason to accept upstream OAuth2 tokens for MCP servers that are configured to use OAuth2. The problem is that the vulnerable code did not prove the target server was one of those cases before downgrading a failed local auth check into a permitted session.

The patch in commit 73869f0 makes that missing proof explicit:

if status in (401, 403) and MCPRequestHandler._target_servers_use_oauth2(
    path=request.url.path, mcp_servers=mcp_servers
):
    validated_user_api_key_auth = UserAPIKeyAuth()
else:
    raise

That change matters for two reasons.

First, the fallback is now gated on the actual target server configuration, not only on the presence of an Authorization header plus a failed auth attempt.

Second, the patch fails closed when the target server cannot be resolved or when any selected server is not configured with auth_type == oauth2. The new helper logic extracts server names from paths such as /mcp/{server} and /{server}/mcp, then checks every target through the global MCP server manager before allowing passthrough.

In other words, the fixed flow is:

failed LiteLLM auth
-> identify target MCP server(s)
-> verify every target uses auth_type=oauth2
-> only then allow anonymous local session plus upstream token passthrough

That is a much narrower rule, and it is the rule the vulnerable version should have enforced from the start.

Why AppSec teams should care

LiteLLM often sits close to sensitive control-plane actions. A compromised request path does not stop at model inference. Depending on how the deployment is wired, reachable MCP tooling may expose:

  • ticketing and knowledge-system connectors
  • source-control and CI/CD actions
  • cloud or internal admin APIs
  • file or shell-like operations proxied through MCP

The CVE does not guarantee code execution on the LiteLLM host by itself. What it does guarantee is unauthorized access to whatever MCP surface the LiteLLM instance was trusted to broker. In many environments that is already enough to turn a nominal “gateway bug” into a broader internal-control-plane incident.

This is also why CVE-2026-59822 belongs beside earlier LiteLLM research on the March PyPI compromise and the broader TeamPCP playbook, even though the root cause here is different. Those articles were about hostile code reaching a trusted AI gateway environment. This one is about a trusted AI gateway accepting hostile callers.

What changed in 1.84.0

The security fix was not just “raise on 401.” The patch tightened the entire decision point around when LiteLLM is allowed to treat a Bearer token as opaque upstream OAuth2 material instead of as a local authentication failure.

The regression tests added with the patch show the intended boundary:

  • fallback is still allowed when the target server is explicitly configured for OAuth2
  • fallback is blocked when the target server uses api_key, basic, or another non-OAuth2 auth mode
  • fallback is blocked when the target server cannot be resolved at all
  • multi-target requests fail closed if any target is not OAuth2-backed

That test coverage is useful because it tells defenders the bug was not only “wrong exception handling.” The real issue was missing target-aware authorization logic.

Exposure and response guidance

Start with scope:

python3 - <<'PY'
import litellm
print(litellm.__version__)
PY

rg -n '/mcp/|x-mcp-servers|auth_type' config* docker-compose* .env* kubernetes helm .github 2>/dev/null

If the installed version is below 1.84.0 and the instance exposes MCP routes to any untrusted network segment, treat the deployment as externally reachable control-plane infrastructure.

Immediate actions:

  1. Upgrade to litellm >= 1.84.0.
  2. If you cannot upgrade immediately, block /mcp/ and related MCP routes at the reverse proxy or API gateway.
  3. Review MCP server definitions and inventory what actions or data each connected server exposed through LiteLLM.
  4. Audit access logs for unexpected unauthenticated or lightly authenticated requests to MCP paths during the exposure window.
  5. Rotate credentials reachable through any connected MCP tool that may have been invoked from an untrusted session.

If you have logs that record request paths and auth outcomes, pay special attention to sequences where a bearer-auth attempt that should have failed was followed by successful MCP tool enumeration or invocation. The advisory does not publish a canned IOC list, so environment-specific request telemetry matters more than filename hunting here.

What changed in the last three days

The code bug is older than this week’s briefing window. The priority change is not. CISA’s KEV addition on 2 September moved CVE-2026-59822 from “important to patch” into the smaller set of open-source issues with public evidence of exploitation. For AI gateways that expose MCP to internal users, contractors, or the public internet, that should change both patch priority and incident-response assumptions.

From research to remediation

Check whether this pattern exists in your codebase

Turn this research into a remediation workflow. Scan dependencies and package manifests for similar supply-chain risk, then prioritize fixes with reachability context.

References