Bifrost CVE-2026-90898: unauthenticated RCE because a stdio MCP client registration starts the command immediately (CVSS 9.8, JFrog, Sep 14, 2026)
Summary
JFrog Security Research (Yuval Moravchick, published September 14, 2026, JFSA-2026-001686326) documents CVE-2026-90898 (CVSS 9.8, critical) in Bifrost (github.com/maximhq/bifrost, an open-source AI gateway/LLM router): its management API lets anyone register an MCP client over HTTP, and a stdio client registration is nothing more than a command plus args — which Bifrost starts immediately inside the gateway process the moment the client is added. No MCP handshake, no authentication (management auth defaults to governance.auth_config.is_enabled=false, i.e. every caller is a local admin), no confirmation. One unauthenticated POST /api/mcp/client runs arbitrary code as the Bifrost process user (appuser on the official image). The HTTP request may time out waiting for the MCP handshake — the timeout does not mean the command failed to start. Fixed in transports/v2.1.0 (unauthenticated stdio registration now returns 403); transports/v2.0.0 and the entire 1.6.x line through 1.6.11 remain vulnerable. Same command-to-subprocess boundary as the recurring MCP stdio pattern; Bifrost is the AI-gateway instance of it, one step worse than Chainlit's sibling flaw because the process launch is unconditional on arrival.
Tags
- tools
- Bifrost
- maximhq
- CVE-2026-90898
- CVE-2026-86242
- JFSA-2026-001686326
- MCP
- Model Context Protocol
- stdio
- command injection
- unauthenticated RCE
- AI gateway
- LLM gateway
- CVSS 9.8
- JFrog Security Research
- AI agent tooling
Vulnerability mechanics
- Surface: the Bifrost management HTTP API (binary default
localhost:8080, commonly exposed).POST /api/mcp/clientaccepts a JSON body withconnection_type: "stdio", astdio_configobject (command+args), andtools_to_execute. - Boundary failure: with governance auth off (the shipped default), there is no authentication on the management API at all. The server treats any caller as a local admin.
- Execution primitive: stdio MCP clients are defined as a program to spawn. Bifrost launches the program when the client is added, before any MCP handshake completes — so the attacker's
/bin/sh -c '<payload>'runs as the Bifrost process user even though the POST itself appears to fail/time out. Published PoC:command: "/bin/sh",args: ["-c", "echo PROVEN > /tmp/bifrost-mcp-rce; sleep 60"]→ marker file written as the service user. - Fix: PR #6757 / commit
12e1703in transports/v2.1.0 — unauthenticated stdio MCP client registration returns 403 when dashboard authentication is disabled or unconfigured; authenticated admins can still add stdio clients. The fix is not backported: 1.6.x ≤ 1.6.11 and v2.0.0 stay vulnerable.
Defender heuristics
- Version-audit the whole line: ≥2.1.0 is fixed; v2.0.0 and 1.6.x through 1.6.11 are not. A "we're on 2.x" answer is not a pass.
- Auth is the interim control: set
governance.auth_config.is_enabled: truewith strong administrator credentials, and keep the management listener off untrusted networks (this flaw makes the management API a remote-code endpoint when reachable). - Treat an exposed pre-2.1.0 instance that ran with auth disabled as compromised: rotate every virtual key and provider credential the gateway holds — an AI gateway concentrates API keys for LLM providers, and in some deployments cloud credentials.
- Hunt artifacts: unexpected child processes of the Bifrost/gateway process (shells, downloaders, interpreters) shortly after
/api/mcp/clientPOSTs; review access logs forPOST /api/mcp/clientfrom non-administrative source ranges, especially requests that time out (the success signal is the timeout). - Pattern-level: this is the MCP stdio command-execution boundary again (see related pages: Chainlit CVE-2026-45018 allowlist-name-only bypass, marimo notebook-metadata MCP command). The durable rule: an MCP stdio
commandfield reachable over the network is arbitrary code execution — gate the registration endpoint itself, not the command string.
Sibling flaw: CVE-2026-86242 custom-plugin HTTP-path RCE (Sep 6, 2026, Or Peles)
Nine days before the stdio flaw, JFrog's Or Peles published a second unauthenticated RCE in the same product — CVE-2026-86242 (CVSS 8.1, JFSA-2026-001684572): Bifrost HTTP transport before 2.0.0 accepts an enabled custom plugin whose path is an HTTP URL through unauthenticated POST /api/plugins (same auth-default-off management API). The shared-object loader treats an http-prefixed path as a download URL, writes the body to a temporary .so, and passes it to Go's plugin.Open; on success Init runs immediately as the Bifrost process user. Loadability gate: the plugin must match the host Go version, OS, architecture, and linkage, and plugin.Open only succeeds on dynamically linked builds (make build DYNAMIC=1, which the vendor requires for custom Go plugins) — on the published statically linked Docker image the same request degrades to SSRF ("Dynamic loading not supported"). The stock bifrost-http binary binds localhost:8080; the official image binds 0.0.0.0 but is static. Fixed in transports/v2.0.0 (PR #5763 / commit e0057ff: refuse create/update of non-builtin plugin paths when the request was let through by disabled/unconfigured dashboard auth + SSRF hardening); the 1.6.x line through 1.6.11 lacks the fix. Practical read: Bifrost exposed two distinct unauthenticated code-execution surfaces in one month on the same management API — treat "which CVE did we fix" as a version-audit question (2.1.0 covers both), and note that both fixes share one design decision: refuse dangerous registrations because the caller was only let through by auth being off.
Related pages
- MCP stdio command-execution boundary
- Chainlit MCP CVE-2026-45018 / CVE-2026-45019
- Marimo CVE-2026-75149 MCP command injection
- Wiz "Off Guard" LiteLLM MCP bypass → cloud compromise
- @zereight/mcp-gitlab CVE-2026-61560: unauthenticated SSE transport + arbitrary file read exfiltrates the GitLab PAT (same week, the credential-theft twin of these RCE flaws)
Sources
- JFrog Security Research advisory: Bifrost is vulnerable to Unauthenticated Remote Code Execution via MCP Stdio Client Registration (CVE-2026-90898, JFSA-2026-001686326)
- Fix: maximhq/bifrost PR #6757 · commit 12e1703 · transports/v2.1.0 release
- CVE record: CVE-2026-90898