Bifrost's MCP flaw shows the protocol still has no client-authentication story
Two critical vulnerabilities, one root cause, and the piece of MCP that is supposed to close this gap.
On September 14, JFrog's security research team disclosed CVE-2026-90898, a 9.8 in Bifrost, an open-source AI gateway that routes to more than twenty LLM providers and speaks MCP to manage tool-providing clients. The flaw let an unauthenticated caller send one HTTP request and run arbitrary commands on the gateway host. It was the second critical, unauthenticated RCE in Bifrost that month. Both traced back to the same design decision.
Two CVEs, one root cause
Both required the same two conditions: the instance was reachable over the network, and dashboard authentication had never been turned on, which is Bifrost's default state out of the box. The official Docker image made this worse by binding the management API to 0.0.0.0 instead of localhost, so a container run with a published port was internet-reachable by default.
What the request actually looked like
JFrog's advisory includes the proof of concept for CVE-2026-90898. It registers a stdio-type MCP client and gets command execution in the same call:
The detail worth sitting with is not the payload, it is the timing. Bifrost starts that program the moment the client is registered. There is no MCP handshake first, no capability negotiation, no tool call to authorize. Registration and execution are the same event.
Version 2.1.0 closes this specific hole by requiring a setup token, set via config.json or the BIFROST_SETUP_TOKEN environment variable, before anyone can claim the first admin account. That is a good fix for Bifrost. It is not a fix for the pattern.
Why this keeps happening
MCP defines tool providers and tool consumers in careful detail. It says much less about the management surface sitting in front of a server like Bifrost, the dashboard and API that decide which tool providers a gateway trusts in the first place. That surface is not really part of the MCP spec. It is ordinary application infrastructure that happens to sit next to an MCP-speaking service, and ordinary application infrastructure ships with sane defaults or it does not, entirely depending on the team that built it.
Worth being precise here, because it is easy to conflate two things that share a name. Dynamic Client Registration and Client ID Metadata Documents are about how an AI agent proves its identity to an OAuth authorization server before it receives a token, the pattern we covered in What 15,465 ungoverned MCP servers tell us about the authorization gap. Bifrost's /api/mcp/client endpoint is a different thing entirely: an admin operation for adding a new tool-providing server to the gateway's own configuration. Both get called registration. Fixing one does not fix the other.
That distinction matters more than it sounds like it should. It is tempting to read "another unauthenticated MCP endpoint" as a protocol gap waiting on a protocol-level fix. For this specific failure, there was no protocol gap to close. There was a management endpoint that needed to check for a session, and did not, because checking was a toggle instead of a default.
What would have actually stopped this
Neither CVE was a flaw in an OAuth flow or a client-identity spec. Both were a privileged HTTP endpoint with nothing in front of it, doing something dangerous the moment a request arrived. That has three separate answers, and all three sit above the MCP layer, in the kind of access control any admin API needs regardless of what protocol it happens to speak.
Require authentication by default, not as a setup step. Bifrost's own description of both root causes is identical: the management API ships with authentication disabled until someone turns it on. That is a defaults problem before it is anything else. An application built with AuthKit does not have an authentication-disabled state to ship in, every route behind it requires a real session or API key from the start, so there is no configuration step an operator can forget before the gateway becomes reachable.
Scope the action, not just the session. Being authenticated is not the same as being cleared to register a tool provider that can run arbitrary commands. That is a fine-grained authorization question, who specifically may do this privileged thing, not just who is logged in, and it is the distinction we covered in IBAC vs RBAC vs ABAC vs ReBAC: which access control model fits AI agents. A management API that treats "authenticated" and "authorized to register a client" as the same check will eventually let the wrong authenticated caller do the wrong privileged thing.
Check what the call does, not only who is making it. Even a correctly authenticated, correctly authorized admin account should give a system pause before it spawns /bin/sh -c on behalf of a client that was just created. That is a content and intent check, not an identity check, and it is what WorkOS Airlock evaluates: whether the specific action a caller is requesting is consistent with policy, before it executes, not only whether the caller is who they say they are. We walked through the mechanics in What is WorkOS Airlock? Intent-based access control for AI agents.
The pattern, not the product
Two ungoverned registries in the last piece, two unauthenticated management endpoints in this one. Neither is really a story about the vendor named in the headline. The fix in both cases sits outside the MCP layer entirely: authentication that is not optional, authorization scoped to the specific privileged action rather than to the session, and a policy check on what an action actually does before it runs. Every gateway that ships without those three, whether or not it speaks MCP, looks like this right up until someone sends the one request that proves it.