The gateway accepted any token
On September 2, CISA added seven exploited flaws to the KEV catalog. Three are AI infrastructure, the first batch where AI makes up nearly half. Read the LiteLLM entry: its MCP endpoint admitted an unauthenticated request carrying any Bearer token at all, because a failed key check fell through to an empty auth object, and the caller could then list and invoke every tool the gateway was wired to. Bromure Agentic Coding holds the same authority behind a hypervisor and a vsock, with no listening port, no header to forge and no fallback branch.
You built the gateway so that no single laptop would hold every key. It worked, and it held every key. Then its front door accepted a Bearer token somebody invented.
On September 2, CISA added seven vulnerabilities to the Known Exploited Vulnerabilities catalog. Two SonicWall SMA1000 bugs, a Sangoma Switchvox SQL injection, a JFrog Artifactory authentication bypass, an OS command injection in Kestra, an HTTP smuggling flaw in Starlette, and an improper-authentication flaw in BerriAI's LiteLLM.
Three of those seven are AI and ML infrastructure. Forkast called it the first KEV batch where AI components make up nearly half the additions, the kind of milestone that earns a headline and then gets filed. Look at which AI infrastructure it is and the batch deserves more than filing. All three of them sit in the middle: the components you deploy so that your agents and the resources they touch stop talking to each other directly. Start with the LiteLLM entry.
The fallback branch
LiteLLM is an AI gateway: one proxy that sits between your agents and the model providers, holds the provider keys so nobody else has to, enforces budgets and rate limits, writes the logs, and now fans out to Model Context Protocol servers so that a team's agents share one MCP endpoint instead of each developer wiring up their own.
CVE-2026-59822, published on July 8 and carrying a CVSS of 8.8 in GitHub's advisory, lives on that MCP endpoint. One sentence of the advisory carries the whole story:
the fallback path could replace failed LiteLLM key validation with an empty
UserAPIKeyAuth()object.
The MCP Streamable HTTP endpoint supported OAuth2 passthrough, so that a token meant for an upstream MCP server could be carried through the gateway rather than validated against LiteLLM's own key store. That is a reasonable feature, and it needs a branch: try the LiteLLM key first, and take the passthrough path when the key is not what arrived.
You reach that branch by failing. Send an Authorization header containing any
string at all, key validation rejects it because the string is not a key, and the
handler builds an empty UserAPIKeyAuth() and carries on with it. Your request
now holds an authenticated MCP session belonging to nobody. From there you
enumerate every MCP tool the gateway was configured with and call them: internal
applications, databases, cloud consoles, development systems, whatever the team
had connected. The flaw affects every version before 1.84.0. CISA's remediation
deadline for federal agencies is September 16, and LiteLLM's advice for anyone
who cannot upgrade today is to block /mcp/ at the reverse proxy in front of
it.
The other three broke in the same function
Read the rest of the batch and you get something more useful than the AI-versus-not headline.
Starlette, CVE-2026-48710, nicknamed BadHost. Starlette is the ASGI toolkit
under FastAPI, which a large share of Python AI services, LiteLLM included, are
built on. A crafted Host header injects a path into the host
portion of the request, which shifts how the URL is reconstructed, which means
path-based authentication middleware evaluates one route while the application
serves another. CISA's entry states the result: authentication bypass, when the
authentication depends on the reconstructed URL's path. It carries a CVSS of 6.5,
the lowest score in the batch and the one that says least about the consequence.
LiteLLM shipped its
own companion fix for the same shape
in 1.84.0, describing it as "a crafted Host header could make the proxy's auth
gate evaluate a different route from the one it served", and told operators whose
proxy had been exposed to rotate their keys and audit the management logs.
JFrog Artifactory, CVE-2026-82329, CVSS 9.8. Improper authentication under
the default configuration: a "phantom" join key that lets an unauthenticated
attacker forge administrator tokens. watchTowr documented exploitation in the wild
on September 1, four days after disclosure, with attackers minting admin
credentials and enumerating users. This is the artifact repository, the host
that answers npm install and pip install for the whole organization.
Kestra, CVE-2026-49869. OS command injection reachable by an unauthenticated remote attacker, who can create and execute arbitrary workflows with no credentials at all. The orchestrator does what an orchestrator does, on behalf of somebody who never signed in.
Four products, four different codebases, and the same broken function in each: the one that decides whether this request is allowed to be here. An empty auth object. A reconstructed path. A default join key. In Kestra's case, no check at all on the route that runs things.
What the attackers did next was boring, and the boredom is the tell for volume work. The Hacker News collected the observed behavior: reverse shells, XMRig miners, credential enumeration, and the theft of API keys and LLM provider credentials. Microsoft summarized it:
The observed objectives were consistent. Across the cases, telemetry showed credential collection, durable access mechanisms, and resource monetization, even though the execution path differed by product.
The gateway was the right idea, and this is its bill
The AI gateway is one of the better ideas of the last two years, and most teams arrived at it for sound reasons.
Before the gateway, every developer's coding agent held a provider key in an environment variable, every developer wired up their own MCP servers with their own tokens, and nobody could answer what any of it had spent or touched. Putting a gateway in the middle fixes all of that at once. One place holds the provider keys and the MCP configuration, and writes the log. Rotating a key becomes a single operation, and so does cutting off a departing employee. The industry converged on this for good reason.
The bill is that you have built a network service whose whole purpose is holding the authority for everyone, and it decides who you are with a function. Functions have branches, and one branch handles the case where the first thing you tried did not work.
LiteLLM did not invent that shape. Every gateway has a front door, every front door has an authentication function, and an authentication function that supports two credential schemes has a path it takes when the first one fails. The reach sitting behind that door is deliberate: concentrating it is the product. So when a gateway gets into trouble, everything it holds is already in the room.
The usual conclusion drawn from an incident like this is "go back to per-developer keys," which is worse on every measure you can take. Keep centralizing. The question worth arguing about is where the centralized thing sits, and whether it has to answer requests from strangers in order to do its job.
Where Bromure puts the same job
Bromure Agentic Coding runs each coding agent in a hardware-virtualized Linux VM on your own Mac, and every security control sits on the host side of that boundary. The controls are the same list a gateway offers: hold the credentials, mediate the MCP servers, classify what the agent does with your infrastructure, keep the record. Nothing on any network can reach the component enforcing them.
There is no front door. The guest's HTTPS never leaves over the network. It
tunnels over a virtio socket, vsock port 8443, to the host proxy, and the manual
is blunt about the topology: the VM has no other route to the network. The proxy
holds no listening port that your LAN, your corporate network or the internet can
address. It never asks who is calling, because one thing sits on the other end
of that socket and the hypervisor decides what that thing is. No Authorization
header, no key store, no scheme negotiation, and so no branch to take when the
first scheme fails.
The MCP bearer token is a fake before it ever reaches the agent. For
HTTP-transport MCP servers configured in a workspace, the real bearer token stays
encrypted on the Mac. The agent's config gets a brm-mcp_… placeholder. The
settings pane labels that field Never sent to VM — swapped by proxy, and the
host proxy substitutes the real value on the wire, scoped exact-or-subdomain to
that server's host and no other. The proxy also answers the server's OAuth and
OIDC discovery paths with 404, so Claude Code treats the server as
pre-authenticated instead of attempting a browser flow the VM could never
complete. LiteLLM's fallback stood on that same passthrough surface. Here the
workspace holds no credential to fumble.
Every operation gets its own decision. A gateway settles the question at the
door: pass it, and everything behind it is yours. Bromure's Guardrails classify
the agent's calls inside the proxy, across Kubernetes, AWS, git forges, container
registries and databases, and apply a per-service write policy. New workspaces
default to Prompt before write, so reads flow and every mutation pauses for a
host-side dialog showing the literal operation: the exact SQL, or METHOD /path.
Read-only blocks every mutation. Ask before use gates the credential
itself, with grants measured in minutes. A forged session still cannot kubectl delete its way through anything, because the second decision happens on your Mac
and owes nothing to how the first one went.
Default deny answers reachability, in both directions. The workspace's egress firewall is an ordered rule table with a default for unmatched traffic. Set it to Deny and the VM reaches the hosts you listed and nothing else, on any protocol. Two components outside the guest enforce that: the virtual switch matches every flow by destination IP and DNS-snooped hostname, and the proxy matches again by TLS server name. Edits reach running sessions with no reboot. In the other direction, NAT mode keeps the VMs off your physical LAN, and nothing outside opens a connection to them unless you publish a service on purpose. The scanners that swept up those exposed gateways get no answer from a Mac.
Whatever a compromised gateway sends back is untrusted input. This part
outlives the CVE. Once a gateway belongs to somebody else, model output, tool
results and error strings all arrive from an attacker, on the highest-privilege
wire in the stack: the one the agent is built to act on. Bromure's source-code
detector scores tool_result spans in the agent's outbound AI traffic with a
local PromptGuard model, on-device, before the model acts on them, and can log,
ask or block; a block returns HTTP 451 and the model never sees the content.
The exfiltration leg fails closed. Every credential in a workspace is a deterministic fake with one legitimate destination. The proxy scans every outbound request for a fake headed somewhere it was not minted for; when it finds one it refuses the request without forwarding a byte, pauses the VM and raises an alert, logged as a red Credential brokering row in the Security Timeline. Because only the fake was ever in reach, the real credential does not need rotating.
If you run a gateway today
Upgrade LiteLLM to 1.84.0 or later; if you cannot, block /mcp/ at the
reverse proxy in front of it. Then follow LiteLLM's own advice from the
Host-header fix and treat an exposed proxy as an exposed key store: rotate the
provider keys it held, audit the management logs. Federal agencies have until
September 16 on CVE-2026-59822, which is a reasonable date to borrow.
The rule that shrinks the question
In the workspace's Guardrails pane, set Unmatched traffic to
Deny and list what the job needs: allow web api.github.com,
allow web registry.npmjs.org, default deny. A workspace that is not
allowed to reach an internal gateway cannot be used to walk through one, and
saving pushes the policy to live sessions without a restart.
Hold the secret, do not check it
One line in Bromure's own architecture notes is worth rereading after a week like this one:
Bypassing the boundary gains an attacker nothing, because the boundary is not where secrets are checked — it is the only place secrets exist.
A gateway is a place where credentials get checked: a request arrives, a function inspects it, and that function's verdict is the only thing standing between the caller and the keys. Checks have edge cases and fallback paths. Checks earn a CVE, a KEV entry and a federal deadline, then earn another two months later on a different branch of the same function.
A wire boundary is a place where credentials are. Nothing arrives to be
inspected, so no verdict can go wrong. The real token sits encrypted on a Mac,
the workspace holds a brm- placeholder worth nothing anywhere, and the
substitution happens on a socket only one hypervisor can write to.
We have written variations of this three times in six weeks: an egress proxy that trusted a hostname the agent could write, a command guard reading bash differently than bash does, and three coding agents whose bypasses all ended at a real credential in a process. Each time, the failing component was doing an honest job of evaluating something, and that is the constant. Evaluation is a weaker primitive than absence, and we keep handing evaluation the work that absence does for free.
Centralizing your agents' authority was the right call. Put the centralized thing where nobody can send it a request. Install Bromure Agentic Coding and give each agent a boundary with no front door.