Published
- 19 min read
Your AI Gateway Control Plane Is a Command Port
Books by the author
Compare all 5As an Amazon Associate I earn from qualifying purchases. Buying through these links costs you nothing extra and helps pay for the blog.
A gateway sits in the middle of your AI stack. Applications send requests to it; the gateway chooses a model provider, applies budgets and policy, and holds the credentials needed to make those calls. That central position is useful. It also means the gateway’s management port is much closer to a root console than an ordinary settings page.
Bifrost gave us a sharp example this month. A caller who could reach its unauthenticated management interface could register a local Model Context Protocol client, which is a program the gateway starts on its own machine. The registration request became a command launch. No model had to be tricked, and no chat prompt was involved.
The repair is available. The more durable lesson is larger than one package: whenever a service can add tools, plugins, connectors, or local processes, its control plane belongs inside the same security boundary as the code it can start. A login screen helps. A private network path, a narrow service identity, restrained credentials, and evidence from the period before the patch finish the job.
What happened, and what did not
On 14 September 2026, the CVE Program published CVE-2026-90898, assigned by JFrog. The record describes Bifrost versions of the HTTP transport before 2.1.0 as affected. Bifrost is an open-source gateway that can route requests among model providers and expose Model Context Protocol, or MCP, connections to applications.
JFrog’s technical advisory rates the issue critical. The CVE score is 9.8 out of 10 because a network caller needs no account or user interaction once the vulnerable management endpoint is reachable. Confidentiality, integrity, and availability can all be affected. That score describes technical capability under the stated conditions; it does not prove that every Bifrost installation was exposed to the internet.
The vulnerable operation registered a stdio MCP client through Bifrost’s management API. In plain English, stdio means the gateway starts a local program and talks to it through the program’s standard input and output streams. The feature is legitimate. Many MCP tools are local processes, and somebody has to tell the gateway which program to start.
The missing boundary was authentication. Bifrost’s governance authentication setting was disabled by default, according to the CVE record. On that path, an unauthenticated request could supply a program and its arguments. Bifrost started it as the gateway’s operating-system user as soon as the client was added. The software did not wait for an MCP handshake to establish that the program was a working tool server.
Bifrost’s maintainers merged the repair on 2 September. The fixed handler returns HTTP 403 when an unauthenticated caller tries to register a local-process client. The patch also blocks unauthenticated registration of MCP connections aimed at private, loopback, link-local, or otherwise non-public destinations. Those destinations remain available to authenticated administrators because local and private MCP servers are normal uses of the product.
The first release carrying the repair is Bifrost HTTP transport 2.1.0, published on 8 September 2026. By 23 September, version 2.2.2 was available. Teams should follow the product’s supported upgrade path rather than treating 2.1.0 as a ceiling.
There is an important limit on the story. A remote attacker still needed a route to the management API. The Hacker News reported on 22 September that the stock binary binds the interface to localhost by default, while the official container binds to all interfaces. A container port bound to all interfaces is reachable outside the container only when the deployment publishes or otherwise routes that port. Maxim, the company behind Bifrost, therefore disputed the practical severity for deployments kept on a private network.
Both statements can be true. The vulnerable function offered command execution without checking identity, which justifies urgent engineering attention. Some deployments may still have had another wall in front of it. Your response should establish which wall your deployment actually had, not argue from either party’s generic picture.
As of 24 September 2026, the public reporting cited here does not show CVE-2026-90898 in CISA’s Known Exploited Vulnerabilities catalogue, and it does not document confirmed exploitation of this Bifrost flaw. Absence from that list is not a clean bill of health. It means the response should be evidence-led rather than theatrical: update, map exposure, inspect the earlier window, rotate what could have leaked, and record the result.
Why an MCP registration can become code execution
The name “client registration” sounds administrative and harmless. Picture the actual sequence instead. An operator tells the gateway, “Add a tool server by running this program with these arguments.” The gateway saves the definition, starts the child process, and communicates with it. Starting the process is already the privileged action.
MCP does not create this risk by itself. Any system that registers executable plugins, build hooks, job runners, shell-backed tools, or local connectors has the same shape. The management request carries a description of work; the service turns that description into an operating-system process. If the request arrives without a trustworthy identity and authorization decision, the word “register” merely hides a remote command channel.
The Bifrost sequence was especially direct. According to the CVE description, the process started when the client was added, before a protocol handshake. A malicious program did not have to behave like a valid MCP server. It only had to be accepted as something Bifrost should launch.
Consider a typical internal deployment. A gateway container can reach three model providers, an observability collector, and a database used for logs or budgets. Its environment or configuration contains provider keys. The container may run as an unprivileged user, which is good, but that user still has precisely the access needed for the gateway’s job. Code running as that user can often read those credentials and make the same outbound connections.
This is why “the container is not root” is an incomplete answer. Running as a non-root account reduces the damage an intruder can do to the host. It does not protect secrets intentionally made readable by the application account. It also does not stop false model requests, altered routing rules, stolen logs, or access to every internal service the gateway was allowed to call.
The official container’s appuser account matters for host containment, but the useful question is narrower: what could appuser read and reach on your installation on 13 September? That inventory might include mounted configuration files, environment variables, cloud workload credentials, provider keys, internal DNS names, proxy access, and log storage. A generic severity score cannot answer it.
The repair correctly places an authentication check before the dangerous registration paths. It also adds network-destination checks for unauthenticated HTTP and server-sent event connections. The merged change explains that a caller could otherwise point the gateway at local services or cloud metadata addresses. That second path is server-side request forgery: the attacker asks a trusted server to make a request the attacker cannot make directly.
Authentication is necessary here because authenticated administrators need to connect local tools and private services. A blanket ban on private addresses would break the product’s main use. The sound design is to reserve these operations for a tightly controlled administrative identity, then keep the administrative endpoint off ordinary application paths.
That last distinction matters. An application needs the gateway’s inference endpoint so it can request a model response. It does not need the endpoint that creates tools, changes providers, or installs plugins. Giving both endpoints the same listener, route, and network audience turns a narrow application dependency into an administrative trust relationship.
The control plane is part of the runtime boundary
Infrastructure teams already separate database traffic from database administration. An application can send parameterized queries through one identity; a smaller group can create users or change replication settings through another path. AI gateways deserve the same treatment.
Call the ordinary request path the data plane. It carries model prompts, responses, tool calls, and usage records. Call the configuration path the control plane. It adds providers, sets budgets, manages keys, registers MCP clients, and changes policy. The data plane handles work. The control plane decides what work is possible.
A control-plane mistake can therefore outrank a prompt-injection bug. Prompt injection usually tries to persuade a model or agent to misuse capabilities it already has. An unauthenticated tool-registration endpoint changes the capability set itself. It can add a new process at the point where tools are defined, without asking the model for cooperation.
That difference changes how you test the system. Model red-team prompts will not find a missing access check on a management route. Evaluation scores will not show that a container port was published by a Helm value or cloud load balancer. Agent permission prompts cannot help if the attacker speaks directly to the gateway that creates those permissions.
The useful review starts with routes and identities. Which hostnames expose inference? Which expose administration? Can a workload identity that sends a model request also create an MCP client? Can a developer laptop reach the management listener through the same shared ingress? Does a monitoring check call the endpoint without credentials and accidentally prove that anonymous access is expected?
Then inspect the operating-system boundary. Which user starts the child process? Which files can it read? Which directories can it write? What Linux capabilities remain? Is the root filesystem read-only? Which sockets and networks can the container reach? These controls do not excuse a missing login. They decide how far a failure travels after one access check breaks.
Finally, inspect the secret boundary. An AI gateway often centralises keys for many providers because central routing is its purpose. That convenience makes the gateway an attractive point of collection. Provider credentials should therefore carry the smallest scopes and budgets the provider supports. A key that only permits model inference with a bounded monthly spend is less useful to an intruder than an account-wide key that can manage projects and billing.
The Secure Harness uses the phrase “autonomy inside a harness” for coding agents, but the same model applies here. A gateway is allowed to start tools because that ability is useful. The harness is the set of enforceable limits around who can request it, where the request may arrive, what process starts, what the process can read, and where it can connect.
A dashboard setting is one strap in that harness. It cannot carry the whole load.
Patch first, then examine the earlier window
Upgrading is the first move because every minute spent designing a perfect architecture leaves the known path open. Confirm the version of the HTTP transport actually running, not the version in a repository file or an image tag you intended to deploy. A mutable tag, failed rollout, pinned digest, or forgotten replica can leave old code behind.
The minimum repaired line for this issue is 2.1.0, according to the CVE and release record. If your normal upgrade target is newer, use the current supported release and read its migration notes. Record the image digest or package version from each running instance after rollout. “Deployment succeeded” is weaker evidence than “every pod reports a fixed artifact.”
Turn on management authentication even after updating. The patch blocks the specific dangerous operations when authentication was bypassed, but a management API should not depend on individual handlers remembering which operations are dangerous. Strong credentials at the control-plane entrance give future endpoints a safer default.
Next, remove the management listener from untrusted routes. If ordinary applications, public clients, or broad employee networks do not need it, they should have no network path to it. Prefer a private administrative service, authenticated ingress, or access proxy restricted to the small operator group that performs configuration. Keep inference traffic on a separate route when the product and deployment model allow it.
A firewall rule or private service should be verified from both sides. Test that an approved administrative host can reach the authenticated endpoint. Test that an application workload and an external vantage point cannot. A diagram saying “internal” is not evidence that a cloud security group, Kubernetes Service, reverse proxy, or tunnel implements the boundary.
The harder work starts if the vulnerable management interface may have been reachable before the repair. The absence of a known public exploit does not prove your instance received no hostile request. Internet scanners find unusual services quickly, and internal callers can also be untrusted. Treat this as a bounded incident review, not automatic proof of compromise.
Choose an exposure window. Start at the earliest time the affected Bifrost version ran with authentication disabled and the management route reachable from the audience you are investigating. End when the fixed build and the new access boundary were both active. If logs do not extend to the beginning, state the gap rather than silently shortening the window.
Within that window, inspect management requests that create or change MCP clients. Look for unexpected client names, local-process connection types, strange process paths, unusual source addresses, bursts of 4xx or 2xx responses, and changes outside known maintenance periods. Compare the records with deployment events and authorised administrator activity.
Process evidence adds another angle. Container runtime, endpoint, or audit logs may show child processes started by the gateway account. Network telemetry may show the gateway contacting destinations outside its ordinary provider and observability set. File-integrity or image-layer records may reveal writes in directories that are normally quiet. Cloud audit logs may show provider-key use from new addresses or unusual workloads.
Do not let the search collapse into a single indicator. A clean HTTP access log is reassuring only if that log covered the management route, retained successful requests, and could not be altered by the same process. A clean process log helps only if child-process collection was enabled. The honest conclusion may be “we found no suspicious activity in these three sources, but process execution was not logged before 18 September.”
If exposure was plausible, rotate credentials readable by the gateway. The JFrog advisory recommends rotating virtual keys and provider API keys for instances that ran with authentication disabled and an exposed management API. Include adjacent secrets mounted into the same process or available through its workload identity.
Rotation means replacing the value and invalidating the old one. Merely creating a second key leaves the suspect credential alive. Check provider audit records after revocation so you know the former key stopped working and the new key is used only by expected instances.
A practical response sequence
A short incident checklist is useful here because order matters. You want to close the known path before spending hours collecting perfect evidence, but you also want enough timestamps and logs to understand what was exposed.
-
Name every running instance and owner. Inventory clusters, virtual machines, developer environments, preview stacks, and forgotten test gateways. Record the HTTP transport version, image digest, management binding, authentication state, and person responsible for each one. If an instance cannot be attributed, isolate it until somebody can explain why it exists.
-
Preserve the relevant records. Save management access logs, gateway application logs, container runtime events, process telemetry, network-flow records, cloud audit logs, and deployment history for the exposure window. Export before short-retention systems roll over. Note which sources were unavailable.
-
Deploy a repaired release. Move every affected instance to Bifrost HTTP transport 2.1.0 or a newer supported version. Confirm the running artifact on every replica. Remove stale replicas and old jobs rather than assuming the scheduler will eventually replace them.
-
Require a real administrative identity. Enable governance authentication and use a credential that is not shared with ordinary inference clients. Store it in the deployment’s secret manager, give it to the narrow operator path, and test that an anonymous management request receives a refusal.
-
Narrow the network route. Stop publishing the management listener to the public internet or the general application network. Restrict it to approved administrative sources. Verify denial from an unapproved workload and from outside the trusted network.
-
Review the earlier window. Reconcile MCP client registrations and configuration changes against authorised work. Search for unusual child processes, outbound destinations, file writes, and credential use. Preserve findings and gaps in one incident note so “no evidence found” keeps its proper scope.
-
Rotate exposed credentials when the route was reachable. Replace model-provider keys, Bifrost virtual keys, and other secrets the gateway process could read. Revoke old values, confirm the new deployment uses the replacements, and review provider-side use during the exposure window.
-
Reduce the next incident’s reach. Run the gateway as a non-root user, keep the filesystem read-only where practical, mount only required secrets, remove unnecessary Linux capabilities, and restrict outbound traffic to required providers and internal services. Set provider budgets and scopes that match this gateway’s real job.
-
Create a closure receipt. Capture the fixed versions, digests, authentication test, denied network tests, rotated-key identifiers, exposure-window dates, reviewed log sources, findings, and remaining blind spots. A ticket marked “patched” is a status. This receipt is evidence.
This sequence separates containment from confidence. Steps three through five close the known route. Steps six and seven deal with the possibility that somebody used it before closure. Steps eight and nine make the next response smaller and easier to prove.
There is one operational trap: do not expose the management endpoint temporarily just to make a test convenient. Run verification from an approved administrative source and denial tests from existing untrusted positions. A security test should not recreate the condition it is trying to remove.
Turn the lesson into an architecture rule
A one-off patch will age. An architecture rule can catch the next product with a different name for the same capability. Use this one: any endpoint that can add executable tools, plugins, hooks, or connectors is an administrative command surface.
That rule should trigger four requirements before deployment. The endpoint needs authentication tied to a named administrative identity. Its network audience must be smaller than the audience for ordinary application requests. The service account behind it must have restrained file, secret, and network access. Its changes and child processes need logs kept long enough for an investigation.
Apply the rule during design review, not after the package appears in a scanner. Ask vendors and internal teams whether a “connector” starts a process, downloads code, loads a shared library, contacts a supplied URL, or reads credentials. Product language often separates these features. The operating system does not.
The rule also helps with default settings. A feature that can start code should fail closed when authentication is absent. Setup friction is preferable to an anonymous command surface. Local development can use an explicit development mode bound to loopback, while shared and production environments require credentials before the server accepts administrative traffic.
Configuration scanners can enforce part of this. Flag a management service exposed through a public load balancer, an authentication switch set to false, a container port published on all host interfaces, or a gateway service account carrying broad cloud permissions. These checks are ordinary infrastructure policy. They do not require a model judge.
Runtime checks cover the facts configuration misses. Alert when the gateway starts a child process outside its approved tool set, when its management route receives a request from an application subnet, or when it reaches a new outbound destination. Baselines need maintenance, but a small allowlist for a central gateway is often easier to operate than a vague “detect anything malicious” rule.
Provider-side limits deserve equal attention. Split credentials by environment and gateway instance where cost permits. Give each key a budget and only the model access it needs. That makes audit trails useful: a call made with the staging gateway’s key has a clear owner, and revoking one environment does not stop production.
None of these controls is a magic wall. Authentication can be stolen. Private networks can contain compromised workloads. Non-root processes can still read application secrets. Egress rules can be too broad. The point is to make one missed check stop at the next boundary instead of travelling through every system the gateway touches.
That is also why severity debates should not consume the response. Whether the flaw feels like a 9.8 in your environment depends on reachability and the gateway account’s access. You can measure both. If the interface was unreachable from untrusted networks, preserve that proof. If it was reachable, close it and inspect the window. Architecture settles the argument better than adjectives.
The receipt you should keep
Six months from now, the useful artifact will not be a screenshot of a vulnerability scanner. It will be a compact record showing what ran, who could reach it, what changed, and what you checked.
Start the receipt with scope: instance names, owners, environments, affected versions, and exposure-window dates. Add the final version and immutable image digest for each instance. Record when the rollout completed and how you confirmed there were no old replicas.
Attach the access tests. An unauthenticated request to the management route should be refused. An approved administrator should still be able to perform required work. An application workload and an external test position should have no network route to the administrative listener. Save timestamps and source locations so another engineer can repeat the checks.
List credential actions without storing secret values. Record provider key identifiers, virtual-key identifiers, rotation times, revocation confirmation, and the services that adopted the replacements. If a key was not rotated because the gateway could not read it, document the evidence for that decision.
Summarise the look-back with precise language. For example: “We reviewed gateway access logs, Kubernetes audit events, and provider usage from 1 September 09:00 UTC through 24 September 14:10 UTC. We found no unapproved MCP registrations or provider calls. Child-process telemetry was not enabled before 12 September, so process activity in the first eleven days could not be independently checked.” That sentence is more useful than “no compromise found.”
End with durable changes and open gaps. Perhaps the team split the management Service from inference ingress, enabled authentication, restricted outbound destinations, and added child-process logging. Perhaps two developer installations remain outside central inventory. Give those gaps owners and dates rather than burying them in prose.
Bifrost’s patch closes a specific unauthenticated path. The lasting repair is recognising what the endpoint always was. A system that can register a local tool can start code; a system that can start code has a command surface; and a command surface needs identity, a narrow route, a restrained process, and a record you can inspect later.
Keep those four parts together. Then an AI gateway can remain a useful centre of policy without becoming a single request away from controlling everything it was built to connect.
For one practical security email per month, join the newsletter using the signup on this site.
Sources
- CVE Program: CVE-2026-90898 record, accessed 2026-09-24
- CVE Program API: CVE-2026-90898 record data, accessed 2026-09-24
- JFrog Security Research: Bifrost unauthenticated remote code execution through MCP stdio registration, accessed 2026-09-24
- Maxim Bifrost: Pull request 6757, MCP authentication and SSRF checks, accessed 2026-09-24
- Maxim Bifrost: Merge commit for MCP authentication and SSRF checks, accessed 2026-09-24
- Maxim Bifrost: HTTP transport 2.1.0 release, accessed 2026-09-24
- The Hacker News: Critical Bifrost AI Gateway flaw lets attackers run commands without credentials, accessed 2026-09-24