Skip to content

Our research

CVE-2026-104776: File Read via kubectl_patch in mcp-server-kubernetes Explained

By Lucas Weber, CyberSec42 · Updated 28 Oct 2026

Schematic of an MCP server sitting between an AI client and a target system

CVE-2026-104776 is a vulnerability in the open-source project mcp-server-kubernetes: the kubectl_patch tool accepted a file path in its patchFile parameter and had kubectl read that file on the server, even when the server was running over a network transport. The four sibling tools with a comparable path parameter already rejected exactly that; kubectl_patch was missing the check. The GitHub advisory rates the issue CVSS 7.1 (high), lists all versions up to and including 4.1.0 as affected and 4.1.1 as fixed, and credits CyberSec42 as the reporter.

In short.

Background

What the server does and which transports it supports.

Go to section

The vulnerability

The mechanism in plain words and in detail.

Go to section

Who was affected

Versions and deployment modes.

Go to section

The fix

What changed and what operators should do.

Go to section

Timeline

Publicly documented dates only.

Go to section

The underlying pattern

When one tool lacks a check its siblings have.

Go to section

Key facts

ItemDetail
IdentifiersCVE-2026-104776 (assigned), GHSA-6963-p4fp-2wxw
Productmcp-server-kubernetes (npm, repository Flux159/mcp-server-kubernetes)
WeaknessServer-side arbitrary file read; CWE-73 “External Control of File Name or Path”
SeverityCVSS 3.1: 7.1, high (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:N)
Affectedall versions up to and including 4.1.0, only when running over SSE or Streamable HTTP
Fixed4.1.1, released 27 July 2026
PublishedGitHub advisory on 2 October 2026; the CVE record at MITRE was not yet published as of 28 October 2026
CreditReported by CyberSec42 (GitHub: lwebmedia)

Background: what mcp-server-kubernetes is

The Model Context Protocol (MCP) is an open standard that lets AI assistants call tools. mcp-server-kubernetes is an MIT-licensed open-source MCP server that, in the words of its repository, provides Kubernetes management commands. It translates tool calls from an AI client into kubectl and helm invocations such as kubectl_get, kubectl_apply or kubectl_patch, and it acts with whatever Kubernetes credentials are present on its host.

What matters here is the transport. The default is stdio: the AI client launches the server as a local process, so caller and operator are the same person on the same machine. Optionally, the environment variables ENABLE_UNSAFE_SSE_TRANSPORT or ENABLE_UNSAFE_STREAMABLE_HTTP_TRANSPORT turn the server into a network service. The project’s advanced documentation describes both options, including a Docker example, and recommends adding header authentication via MCP_AUTH_TOKEN for production use.

On a network transport, one principle applies that the project itself spells out in its source code: a file path supplied by a caller resolves on the server host, not on the caller’s machine. That is why the maintainers blocked path parameters on network transports in two pull requests in July 2026 (#332 and #346), covering kubectl_create, kubectl_apply, kubectl_delete and Helm chart install and upgrade. For general guidance on hardening such servers, see our guide to securing MCP servers; this article covers the specific case.

How we reviewed it

The finding comes from a source-only review of the public repository. According to the advisory, no third-party deployment of mcp-server-kubernetes, no Kubernetes cluster, no kubeconfig and no other third-party system was accessed, scanned or exploited. We reproduced the divergent behavior only on our own machine against the compiled code, without any network request and without a cluster. The report was submitted confidentially through the repository’s private vulnerability reporting on GitHub.

The vulnerability

In plain words

Picture an office where visitors hand in forms. For four types of form there is a rule: outside visitors may not refer to “the document in cabinet drawer 3”; they have to bring their own papers. The fifth form type lacked that rule. A visitor could point to a drawer, and the clerk would take the document out and work with it. If it did not fit the form, the clerk’s reply quoted parts of it back.

That is how kubectl_patch behaved up to version 4.1.0. The cabinet is the server’s file system, and the drawer is the patchFile parameter.

In detail

The kubectl_patch tool accepts a change either as inline data (patchData) or as a path to a file (patchFile). It passed the path on to kubectl as --patch-file, and kubectl runs on the server host with the server’s privileges. The sibling tools call isRemoteTransport() right before that step and reject the path when the server runs over the network. kubectl-patch.ts did not make that call. A second, general safeguard in the project does inspect every argument passed to kubectl, but according to the advisory it only checks the names of certain flags, not the value that follows. It therefore offered no protection for the path.

The advisory describes two ways content could flow back. If the file is not valid JSON or YAML, kubectl fails to parse it, and the error message, including context from the file, was returned verbatim to the caller. If the file is valid, which is plausible for many configuration and credential files, its content is applied as a patch to a Kubernetes resource. The caller could then read that resource in full through kubectl_get.

Reading the vector: PR:L means a caller needs low privileges, here a valid X-MCP-AUTH header value if the operator has set MCP_AUTH_TOKEN. C:H reflects the loss of confidentiality, and I:L the limited integrity impact of the unintended patch. We recalculated the 7.1 base score using the formula in the CVSS specification. The advisory itself notes that the score would be higher without a token, around 8.2, and that an operator who exposes a network transport without a token already gives every reachable caller access to powerful cluster tools. Both scores fall into the high band; the lower one was reported.

Schematic flow

Caller passes a server path MCP server SSE / HTTP Sibling tools reject the path kubectl_patch reads the file path check in place up to 4.1.0 no check
On a network transport the sibling tools already rejected server paths. kubectl_patch lacked the check up to 4.1.0; from 4.1.1 the same rule applies.
  1. The operator starts mcp-server-kubernetes with SSE or Streamable HTTP. Kubernetes credentials are present on the host.
  2. A caller who can reach the endpoint, and who holds the auth header if one is configured, calls kubectl_patch with a path on the server host as patchFile.
  3. The server does not check the transport and hands the path to kubectl, which opens the file with the server’s privileges.
  4. If the file is not a valid patch, the returned error message contains context from the file. If it is valid, its content ends up in a resource that can be read through kubectl_get.

We deliberately publish no exploit code and no sample request. The description is enough to assess your own deployment and to follow the fix.

Who was affected

The advisory lists the npm package mcp-server-kubernetes in all versions up to and including 4.1.0. In the 4.1.0 source, kubectl-patch.ts contains no call to isRemoteTransport(); from 4.1.1 it does. That function decides whether the server runs over the network solely by looking at the two environment variables for SSE and Streamable HTTP.

Deployment modeAssessment up to 4.1.0
stdio (default, local process)Not affected. The caller is the operator on their own machine, and the fix does not change this behavior
SSE or Streamable HTTP with MCP_AUTH_TOKEN setAffected for anyone who can reach the endpoint and holds a valid auth header
SSE or Streamable HTTP without MCP_AUTH_TOKENAffected for anyone who can reach the endpoint
With ALLOW_ONLY_READONLY_TOOLS=trueNot reachable according to the advisory, because kubectl_patch is not on the allowed list. ALLOW_ONLY_NON_DESTRUCTIVE_TOOLS=true, by contrast, does not exclude the tool

How serious the risk was in a given setup depends on who could reach the endpoint and on which files were present on the server host. The advisory names a mounted kubeconfig, a pod’s service account token and the process environment as typical targets.

The fix and what operators should do now

What changed in 4.1.1

Pull request #355 extends the existing rule to kubectl_patch: when the server runs over SSE or Streamable HTTP, patchFile is rejected with an error that points callers to patchData. The parameter description in the tool schema now states the restriction explicitly, just as it does for the sibling tools. Behavior in stdio mode is unchanged. The fix also extends the existing test file for path parameters on network transports to cover kubectl_patch under both transport variables.

The test is the lasting part: it closes the coverage gap that allowed kubectl_patch to drift from its siblings in the first place.

Recommendations for operators

The following steps are our recommendations, not requirements from the maintainers.

StepAction
1. Check the versionUpgrade to 4.1.1 or later. The advisory lists 4.1.1 as the first fixed version.
2. Check the transportFind out whether ENABLE_UNSAFE_SSE_TRANSPORT or ENABLE_UNSAFE_STREAMABLE_HTTP_TRANSPORT was set. If neither was, the path described here did not exist.
3. Rotate credentialsIf a network transport was reachable by callers you do not fully trust: rotate kubeconfig credentials and service account tokens, and replace secrets held in the process environment.
4. Shield the endpointSet MCP_AUTH_TOKEN, do not expose the endpoint unprotected and terminate TLS in front of it, as the project documentation recommends for production.
5. Limit the toolsEnable only the tools you actually need, for example via ALLOW_ONLY_READONLY_TOOLS or ALLOWED_TOOLS.
6. Limit privilegesGive the server only the cluster permissions its enabled tools require, and keep unrelated secrets off its host.

Timeline

Only dates that can be verified from public sources are listed.

DateEventSource
13 Jul 2026Pull request #332: path parameters of kubectl_create blocked on network transportsGitHub commit
18 Jul 2026Pull request #346: same rule for kubectl_apply, kubectl_delete and HelmGitHub commit
26 Jul 2026Release 4.1.0, the last affected versionGitHub release, npm
27 Jul 2026Source review at the 4.1.0 state, per the advisoryGitHub advisory
27 Jul 2026Fix merged (pull request #355), release 4.1.1GitHub, npm
2 Oct 2026GHSA-6963-p4fp-2wxw published with CVE-2026-104776GitHub advisory
28 Oct 2026CVE record at MITRE not yet publishedQuery of the CVE Services API

The fixed version was therefore available more than two months before the vulnerability was publicly described.

The underlying pattern: when one tool lacks a check its siblings have

CVE-2026-104776 is not a new kind of bug. The maintainers had recognized the risk, named it and fixed it in four places. The gap was the fifth place, which the follow-up sweep missed. We call this sibling asymmetry: several tools take the same shape of input, but only some of them validate it. MCP servers are prone to it because each tool tends to be its own file with its own input handling, and safeguards are often added tool by tool.

In our walkthrough of the OWASP MCP Top 10, the case touches class 10 (insecure file access) and class 7 (credentials that can leak) above all. There is also an element of class 4: a safeguard that sees every argument but only checks flag names can create an impression of complete protection. For MCP server developers, four rules follow:

For operators, the flip side: an MCP server on a network transport is a network service with access to your cluster and to its host’s file system. It deserves the same treatment as any other API that holds secrets: authentication, least privilege and a deliberately short tool list. You will find more publicly documented findings on our research page.

Thanks to the maintainers

We thank the maintainers of mcp-server-kubernetes for the coordinated collaboration. The report went in confidentially through GitHub’s private vulnerability reporting. The maintainers implemented the fix with tests, shipped the corrected version well ahead of disclosure and published the advisory with a CVE ID and credit to CyberSec42. The project also documents its security decisions in a way that is easy to follow: the reasoning behind the path restriction sits as a comment right in the code and in the pull request descriptions.

Do all tools in your MCP server enforce the same checks?

We assess MCP servers and AI agents within a scope agreed in writing: whether safeguards apply equally to every tool, which files and credentials a tool call can reach, how the transports are secured and what a caller can actually achieve. Every finding comes with reproducible evidence and a concrete remediation proposal. Learn more under AI pentest & MCP security.

Request an AI pentest

CyberSec42 is an independent technical security assessment, not an accredited certification body, and does not provide legal advice. CyberSec42 is not affiliated with the maintainers of mcp-server-kubernetes.

Frequently asked questions

What is CVE-2026-104776?

A vulnerability in the MCP server mcp-server-kubernetes. Its kubectl_patch tool let callers read files on the server host through the patchFile parameter, even over network transports where the sibling tools already rejected such paths. The GitHub advisory rates it CVSS 7.1 (high).

Which versions are affected?

According to the advisory, all versions up to and including 4.1.0. The issue is fixed in 4.1.1, released on 27 July 2026. Upgrade to 4.1.1 or later.

Am I affected if I run the server over stdio?

No. The check only applies when the server runs over SSE or Streamable HTTP. In stdio mode the caller is the operator on their own machine, and the fix changes nothing there. You should still upgrade, because the deployment mode may change later.

Why is there no entry on cve.org yet?

The CVE ID has been assigned and is listed in the GitHub advisory. The corresponding record at MITRE was not yet published when we checked on 28 October 2026. Until then, the GitHub advisory is the authoritative source for versions and rating.

Has the vulnerability been exploited?

Public sources say nothing about that. Our review was a source-only analysis in which no third-party system was contacted.

Further reading

Sources