Last updated: September 2026
CVE-2026-59822 is an authentication bypass in LiteLLM’s MCP Streamable HTTP endpoint: when LiteLLM key validation failed, an OAuth2 passthrough fallback substituted an empty UserAPIKeyAuth() object instead of rejecting the request, so any fabricated Bearer token produced an authenticated MCP session. It affects every version below 1.84.0 and is fixed in 1.84.0. CISA added it to the Known Exploited Vulnerabilities catalog on 2 September 2026 with a 16 September remediation deadline for federal civilian agencies.
The advisory rates it 8.8 High on CVSS 4.0, vector CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:L/VA:N/SC:N/SI:N/SA:N, while NVD scores the same issue 8.2 on CVSS 3.1, so your scanner may disagree with the advisory by half a point. It was reported by the researcher yaaras (GitHub Security Advisory GHSA-7488-6r32-c95q, “MCP Authentication Bypass via OAuth2 Passthrough Fallback”, 2026). Confidentiality is the impact rated High, which is the right emphasis for a component sitting on top of provider API keys, tool credentials and whatever the connected MCP servers can reach.
Key takeaways
- Any Bearer token, valid or not, opened an authenticated MCP session on LiteLLM before 1.84.0.
- The root cause is a fallback that treated a failed auth check as an anonymous but authenticated caller.
- The same pull request closed a second, separate bypass: a
.well-knownpublic-route check that matched anywhere in the URL, including the query string.- The patch shipped on 14 May 2026, seven weeks before the advisory and sixteen before the CISA listing, so version, not disclosure date, is what tells you whether you were exposed.
What exactly did CVE-2026-59822 allow?
The advisory states it plainly: “LiteLLM’s MCP Streamable HTTP endpoint could allow an unauthenticated attacker to establish an authenticated MCP session using an arbitrary Bearer token.” No valid LiteLLM virtual key was needed. An attacker who could reach the MCP route could list and call tools as though they had passed the gate.
The mechanism is a fallback with the wrong default. LiteLLM supports OAuth2 passthrough, where a token in the Authorization header is meant for an upstream MCP server rather than for LiteLLM itself. In the vulnerable code path, when the local key check failed, the fallback “could replace failed LiteLLM key validation with an empty UserAPIKeyAuth() object” rather than terminating the request.
An empty auth object is not the same thing as no auth object. Downstream code reads it as a caller who simply has no key limits attached: no budget, no allowed-models list, no team scoping. The request continues with the permissions of nobody in particular, which in practice means the permissions of the gateway.
The anti-pattern, in shape rather than in LiteLLM’s actual source, looks like this:
# Wrong: a failed check falls through to a default identity
try:
auth = validate_litellm_key(request)
except AuthError:
auth = UserAPIKeyAuth() # empty, but truthy downstream
# Right: the failure is the answer
try:
auth = validate_litellm_key(request)
except AuthError:
if not server_config.oauth2_passthrough_enabled:
raise HTTPException(status_code=401)
auth = passthrough_identity(request)
The difference is one branch. The passthrough path is entered because a server was configured for it, never because another check failed.
What else did the 1.84.0 fix close?
A second bypass in the same handler, which the advisory never mentions. The fix is pull request 26463, “fix(mcp): tighten public-route detection and OAuth2 fallback gating”, merged on 30 April 2026 and shipped in the 14 May 2026 release. It changes two things, not one.
The public-route check used to ask whether the string ".well-known" appeared anywhere in the request URL. Appending ?.well-known to any MCP route therefore marked it public. The fix narrows the test to the path component with request.url.path.startswith("/.well-known/"), so a query string cannot smuggle the marker.
The second change is the one the CVE describes, and it is gated exactly the way it should be. A helper named _target_servers_use_oauth2 now permits the empty-auth fallback only when every resolved target server carries an operator-configured auth_type of oauth2. Routes that match no known server pattern fail closed.
That matters for how you triage. If you were below 1.84.0 you were exposed to the query-string bypass whether or not you ever configured OAuth2 passthrough, so “we do not use passthrough” is not a reason to stay on an old version.
That shape of bug shows up wherever passthrough and local auth share one code path. The gateway has to decide whether a credential is for it or merely through it, and the safe answer when it cannot tell is a 401. Passthrough should be gated on an explicit per-server setting, not inferred from the failure of another check, which is precisely what _target_servers_use_oauth2 now enforces. If your own proxy has a branch that turns a rejection into a default identity, you have the same bug with a different CVE number.
Is CVE-2026-59822 actually being exploited?
CISA says yes. It added CVE-2026-59822 to the Known Exploited Vulnerabilities catalog on 2 September 2026 with a remediation date of 16 September 2026 for federal civilian executive branch agencies. The entry is titled “BerriAI LiteLLM Improper Authentication Vulnerability”, with ransomware campaign use recorded as Unknown. KEV entries require evidence of active exploitation rather than a high score alone.
Two details in the catalog are worth more than the listing itself. The required action now cites BOD 26-04, “Prioritizing Security Updates Based on Risk”, which CISA issued on 10 June 2026 to supersede the flat KEV clock of BOD 22-01. And CISA added a second auth-bypass-shaped flaw the same day with the same due date: CVE-2026-48710 in Starlette, HTTP request smuggling that lets an attacker inject paths into the host part, which the catalog note says can be chained with CVE-2026-42271. Gateways of this kind tend to be behind on more than one of these at a time.
Internet exposure is what turns the rating into an incident. LLM gateways get deployed fast, often on a public hostname so that hosted agents, IDE clients and CI jobs can reach them, and often before anyone writes down who owns them. With attack complexity Low and privileges required None, reachability is close to the entire risk calculation.
Why is an LLM gateway an identity boundary, not plumbing?
An LLM gateway holds three classes of secret at once: upstream provider keys, the credentials its MCP servers use to reach internal systems, and the prompt and response traffic itself. Anything that authenticates to it is asking for all three. That is the definition of an identity boundary, whatever the architecture diagram calls the box.
Teams tend to reason about these gateways as caching and routing infrastructure, so they inherit infrastructure-grade auth: a shared key in an environment variable, maybe an allowlist. Then MCP arrives and the same process starts brokering tool calls into ticketing systems, source control and databases, which widens the blast radius without anyone revisiting the auth model.
A useful test is to ask what an attacker gets from one successful request to the component. If the answer includes “a tool call against a system of record,” the component needs an authorization server in front of it, with per-client identity, audience-restricted tokens and revocation. A static key shared by every caller gives you none of those, and it cannot be revoked for one bad actor without breaking everyone.
The MCP specification itself moved this direction. The stateless MCP changes in the 2026-07-28 spec push servers toward per-request authorization rather than long-lived session trust, which only works if something is actually issuing and validating those tokens.
What do you patch, and in what order?
Upgrade to LiteLLM 1.84.0 or later first. The advisory’s own workaround for anyone who cannot upgrade immediately is blunt and correct: “If upgrading is not immediately possible, disable MCP routes or block access to /mcp/ and related MCP endpoints at your reverse proxy or API gateway.” Blocking the route is a real mitigation here because the bypass is specific to the MCP Streamable HTTP path.
Then work through the credential blast radius, in this order:
- Upgrade or block. 1.84.0 or later, or deny
/mcp/at the edge until you can. - Rotate every provider key the gateway held. OpenAI, Anthropic, Bedrock, Vertex, and anything else in the config. To be precise about why: the advisory’s stated impact is that an attacker can list and call configured MCP tools and reach the services behind them, not that provider keys are directly readable through this endpoint. You rotate anyway, because a bypassed auth check leaves no reliable record of what a session touched, and because a host old enough for this bug is usually behind on the other LiteLLM advisories from the same year.
- Rotate the credentials of every connected MCP server. The tools were reachable, so treat their service accounts as exposed too.
- Inventory your AI gateways. Count every process that terminates an
Authorizationheader and then calls something else on the caller’s behalf, not just the LiteLLM ones. - Cut network exposure. Most of these deployments do not need a public listener. Private networking plus an identity-aware proxy removes the Low-complexity remote path entirely.
- Check your logs for two patterns. Requests to MCP endpoints that carried a Bearer token which never matched a known key and still returned 200, and any MCP route whose query string contains
.well-known, which is the signature of the public-route bypass the same patch closed.
Key rotation is the step teams skip because it is annoying, and it is the one that matters most. The CVSS confidentiality rating of High reflects how much sits behind this component, which is the same reason rotation is not optional.
How do you put an authorization server in front of LiteLLM MCP routes?
Placement matters more than issuer here, so start with it. Issuing tokens from Keycloak changes nothing on its own: if LiteLLM’s own handler is the thing validating those tokens, the same fail-open branch bypasses them just as happily. Enforcement only leaves the buggy process when a separate policy enforcement point rejects the request first, which means an identity-aware proxy, an Envoy or Kong JWT filter, or oauth2-proxy sitting in front of the gateway and validating against Keycloak.
Once the check runs somewhere else, three properties limit what a legitimate credential is worth. None of them would have stopped this exploit, which used garbage tokens rather than stolen ones. They are blast-radius controls:
Audience restriction. RFC 8707 resource indicators let a client ask for a token bound to one MCP server, and the server rejects tokens minted for anything else. In Keycloak that is a resource parameter on the token request, backed by an audience mapper on a client scope under Client scopes in the admin console:
curl -X POST "https://id.example.com/realms/agents/protocol/openid-connect/token"
-d grant_type=client_credentials
-d client_id=coding-agent
-d client_secret="$AGENT_SECRET"
-d resource="https://mcp.example.com/github"
The MCP server then checks aud against its own identifier and rejects everything else, so a token stolen from one hop is useless at the next. The failure modes are covered in why a Keycloak-backed MCP server returns 401 on audience, and the backend verification steps apply unchanged when the caller is an agent.
Short-lived tokens with real revocation. Access tokens that expire in minutes, refresh tokens you can invalidate per client or per session. A static gateway key, by contrast, is valid until someone edits a config file and restarts a process.
Named clients instead of anonymous callers. Every agent, IDE and CI job gets its own client identity, so the audit log answers who called which tool. The client identity metadata document approach removes the registration friction that usually pushes teams back toward shared keys in the first place.
Worth being precise about scope: none of this would have patched LiteLLM. The bypass was in LiteLLM’s own handler, and a request that reached that handler would still have been mishandled. What an external enforcement point changes is which requests reach the buggy code at all, and what a credential is worth once they do, which makes defense in depth the honest claim rather than prevention.
The deeper fix is architectural. If the gateway is the only thing standing between the internet and your tools, every gateway bug is a full compromise. If the gateway validates tokens issued elsewhere, a gateway bug costs you the gateway. That is the trade the MCP server authorization pattern with Keycloak is built around.
What should teams building on MCP do differently now?
Adopt fail-closed as an explicit review rule for any auth code path. A failed check produces a rejection, never a default identity, never an empty credential object, never a fallback to a different scheme that happens to be more permissive. Write it into the code review checklist, because this class of bug survives tests: the happy path works, the rejection path also “works,” it just returns the wrong thing.
Gate passthrough on configuration. If a server is configured for OAuth2 passthrough, pass the token through, and if it is not, the presence of a Bearer token is not a reason to try a different scheme. Inferring between auth schemes is what creates the ambiguity these bugs live in.
Treat agent credentials as first-class identities with their own lifecycle. Agent authentication patterns in Keycloak and the broader agentic IAM picture heading into 2026 cover what that looks like when the caller is a process rather than a person. The token hygiene basics still apply, and JWT best practices has not changed just because the client is a model.
Frequently asked questions
Which LiteLLM versions are affected by CVE-2026-59822?
Every version below 1.84.0. GitHub Security Advisory GHSA-7488-6r32-c95q, published on 30 June 2026, lists affected versions as < 1.84.0 and patched as >= 1.84.0. The fix itself shipped earlier, in the 14 May 2026 release. If you cannot upgrade, the advisory recommends disabling MCP routes or blocking /mcp/ at your reverse proxy.
Is CVE-2026-59822 being exploited in the wild?
Yes. CISA added it to the Known Exploited Vulnerabilities catalog on 2 September 2026, which requires evidence of active exploitation, and set a 16 September 2026 remediation date for federal civilian agencies under BOD 26-04, the risk-based directive that replaced BOD 22-01 in June 2026. Non-federal operators should treat that date as the floor.
Does upgrading LiteLLM mean my provider keys are safe?
No. Upgrading closes the hole, it does not un-expose anything reached through it. The advisory describes tool enumeration and tool calls against connected services rather than direct key disclosure, but a bypassed session leaves no reliable audit trail. Rotate provider keys and the credentials of every MCP server the gateway could call.
Would an OAuth authorization server have prevented this bug?
Not the bug itself, which lived inside LiteLLM’s request handler. What audience-restricted, short-lived tokens change is the value of what an attacker obtains and how quickly you can revoke it. A stolen token bound to one resource and expiring in minutes is a much smaller incident than a static gateway key.
What does fail-closed mean for an MCP gateway?
It means a failed authentication check ends the request with a 401, with no fallback to a second scheme and no substitution of an empty credential object. Passthrough behavior is enabled by explicit per-server configuration only, never inferred from another check having failed.
Sources
- GitHub Security Advisory, “GHSA-7488-6r32-c95q, MCP Authentication Bypass via OAuth2 Passthrough Fallback”, retrieved 2026-09-21
- CISA, “Known Exploited Vulnerabilities Catalog”, entry for CVE-2026-59822 added 2026-09-02 with due date 2026-09-16, retrieved 2026-09-21
- CISA, “CISA Adds Seven Known Exploited Vulnerabilities to Catalog”, 2 September 2026, retrieved 2026-09-21
- BerriAI, LiteLLM pull request 26463 “fix(mcp): tighten public-route detection and OAuth2 fallback gating”, merged 30 April 2026, retrieved 2026-09-21
- BerriAI, LiteLLM release v1.84.0, 14 May 2026, retrieved 2026-09-21
- CISA, BOD 26-04 “Prioritizing Security Updates Based on Risk”, 10 June 2026, retrieved 2026-09-21
- IETF, RFC 8707 “Resource Indicators for OAuth 2.0”, 2020