TL;DR

  • Francisco Rosales of Manifold Security found a high-severity access control bypass (CVE-2026-46519, CVSS 8.8) in mcp-server-kubernetes, a project with 20,000 weekly npm downloads and 1.4K GitHub stars.

  • The three environment variables operators use to restrict tool access (including "read-only mode") are enforced at the discovery layer but not at the execution layer, meaning any client can invoke restricted tools directly.

  • In the worst case scenario (cluster-admin service account, multi-user HTTP deployment), this means full cluster compromise for anyone who can reach the endpoint.

  • Fixed in v3.6.0: if you're running an earlier version, update now. Full details below.

Three env vars, one missing check

mcp-server-kubernetes is one of the more popular community-built MCP servers out there, maintained by a two-person independent team at Flux159. It gives AI agents like Claude direct access to Kubernetes clusters. They can get pods, describe deployments, read logs, exec into containers, delete resources, and more. At 20,000 weekly npm downloads and 1.4K GitHub stars, it's a real piece of infrastructure that real teams are putting in front of their clusters.

The project exposes three environment variables for operators who want to restrict what's available:

  • ALLOW_ONLY_READONLY_TOOLS=true: limits the agent to read operations only

  • ALLOW_ONLY_NON_DESTRUCTIVE_TOOLS=true: hides destructive tools like kubectl_delete

  • ALLOWED_TOOLS=kubectl_get,kubectl_describe: explicit allowlist of permitted tool names

If you're deploying this over HTTP for multiple users or teams (which the project explicitly supports and documents), these variables are how you enforce least privilege. The monitoring team gets read-only. The contractor gets kubectl_get and nothing else.

Francisco (0xmagic0) found that none of these controls actually prevent anything. They filter which tools appear in tools/list (the MCP equivalent of asking "what can you do?"), but the execution handler tools/call has no equivalent check. Any client that knows a tool name can invoke it directly. Tool names aren't secret; they're in the README.

Env var

Filtered in tools/list

Filtered in tools/call

ALLOW_ONLY_READONLY_TOOLS

Yes

No

ALLOW_ONLY_NON_DESTRUCTIVE_TOOLS

Yes

No

ALLOWED_TOOLS=...

Yes

No

One curl, one deleted pod

You set ALLOW_ONLY_READONLY_TOOLS=true. Your agent, or any client connected to the endpoint, asks for the list of available tools and gets back eight read-only operations. kubectl_delete is not on the list.

Then you send this:

curl -s http://<HOST>:3003/mcp \

  -H 'Content-Type: application/json' \

  -H 'Accept: application/json, text/event-stream' \

  -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"kubectl_delete","arguments":{"resourceType":"pod","name":"test-pod","namespace":"default"}}}'

Response:

{"result":{"content":[{"type":"text","text":"pod \"test-pod\" deleted\n"}]}}

The pod is gone. The restriction did nothing.

Francisco confirmed this across all three modes against a live kind cluster. Same result every time. The MCP_AUTH_TOKEN / X-MCP-AUTH mechanism the project also supports controls who can reach the endpoint at all, but it doesn't change which tools an authenticated client can call. A contractor you've restricted to ALLOWED_TOOLS=kubectl_get can still exec into your pods.

Cluster-admin makes this a cluster takeover

The severity here scales with your service account. If the MCP server is running with cluster-admin (commonly seen in dev and staging environments), this bypass gives anyone who can reach the HTTP endpoint full cluster access: delete deployments, exec into containers, run arbitrary commands, access secrets.

The project documents multi-user HTTP deployment scenarios. It ships with Streamable HTTP and SSE transport support and includes examples for connecting Codex CLI, Gemini CLI, and in-cluster workloads. This isn't a local stdio tool where you're the only user. It's designed to be shared. The access control is the whole point of those env vars in that model, and it doesn't work.

The root cause is a single missing check. In src/index.ts, the tools/list handler filters tools correctly. The tools/call handler dispatches by tool name with no equivalent filter. Every tool is reachable unconditionally regardless of what the operator configured.

Fixed in v3.6.0 with one filter call

Fixed in v3.6.0 and above. The remediation is straightforward: apply the same filtering logic at the start of the execution handler before dispatching any tool call, returning an MCP error for any tool not permitted under the active configuration. The logic already existed; it just wasn't being called in both places.

We want to give a genuine shoutout to Suyog Sonwalkar (@Flux159), the project maintainer. We emailed the report on Thursday, May 14th. Suyog acknowledged it, shipped a fix, and published a new release the same day. He then requested a CVE through GitHub's advisory process and gave users a few days to update before publishing the GHSA. The whole thing was handled cleanly and fast. That kind of response from a maintainer is worth naming.

If you're running mcp-server-kubernetes prior to v3.6.0, update now. Full technical details, including the PoC and CVSS scoring, are in the published advisory: GHSA-cr22-wjx7-2w6m.

API-surface controls aren't controls

This finding sits in a category we're watching closely: security controls on MCP servers that exist at the API surface but aren't enforced at the execution layer. It's the kind of gap that's easy to miss because the feature works correctly from a user-experience standpoint. The restricted tools don't show up, the agent doesn't try to call them, everything looks fine. Until someone bypasses tools/list entirely, which takes one curl command.

For teams running AI agents in sensitive environments (and mcp-server-kubernetes is explicitly designed for production Kubernetes clusters), the runtime layer is where this actually matters. Your EDR sees HTTPS traffic. It doesn't see an agent invoking kubectl_delete on a cluster where that should be forbidden, because nothing in the logs looks unusual.

Manifold monitors agent behavior at runtime via an agentless OpenTelemetry setup. When an agent calls a tool it shouldn't have access to, that's visible in our telemetry regardless of what the access control layer claims to be doing. We watch what the agent actually does, not what it's been told it can do. That's the layer that catches this class of vulnerability in production.

And it starts with knowing what's in your agent stack to begin with. If you're using MCP servers, check them in Manifest, our free, open-access tool that indexes and scores MCP servers from the official Registry on lineage and safety signals. It's how teams catch supply chain risk in the MCP ecosystem before it lands in production.

One MCP server. 20,000 weekly downloads. Manifest indexes and scores over 7,700 more on supply chain risk. Check yours. Talk to Manifold.

SEE MANIFOLD IN ACTION

SEE MANIFOLD
IN ACTION

SEE MANIFOLD IN ACTION