# Root Cause Analysis: CVE-2026-52831 Nuclio Cron Trigger Shell Command Injection

## Summary

Nuclio's Kubernetes controller generated Kubernetes CronJob containers for cron triggers by concatenating attacker-controlled cron event data into a single shell command and storing it as `Args: ["/bin/sh", "-c", curlCommand]`. A malicious `event.headers` key containing an unescaped double quote and shell separators breaks out of the intended `curl --header "key: value"` quoting and appends arbitrary shell commands. In this run, a real Nuclio controller binary processed a real `NuclioFunction` Kubernetes custom resource, generated a real Kubernetes CronJob, and a CronJob-derived pod executed attacker-controlled `echo` and `id` commands.

## Impact

- **Package/component affected:** Nuclio Kubernetes controller, specifically Kubernetes CronJob-based cron trigger generation in `pkg/platform/kube/functionres/lazy.go`.
- **Affected versions:** Nuclio versions at or before the vulnerable parent of fixed commit `3356b86a8bfab3f960aa420310ebff765df9dede`; the ticket states Nuclio 1.15.27 and earlier are affected.
- **Risk level and consequences:** Critical. A user who can create or update a Nuclio function with a malicious cron trigger can cause the cluster to create a CronJob whose pod runs arbitrary shell commands in the CronJob container context. This is product-path remote/API-triggered command execution via the Kubernetes/Nuclio API boundary.

## Impact Parity

- **Disclosed/claimed maximum impact:** Code execution / RCE through Nuclio cron trigger event headers or body in Kubernetes CronJob-based cron trigger processing.
- **Reproduced impact from this run:** Code execution in real Kubernetes CronJob pods generated by the Nuclio controller. The vulnerable pod logs include the attacker marker `CVE_PRODUCT_RCE` and `id` output (`uid=100(curl_user) ...`).
- **Parity:** `full`
- **Not demonstrated:** No attempt was made to chain from CronJob-container command execution to broader cluster privilege escalation. The reproduced impact matches the claimed command execution at the affected product boundary.

## Root Cause

In the vulnerable code path, Nuclio decoded cron trigger attributes from a `NuclioFunction` resource and built a shell command string for invoking the function:

- User-controlled headers were formatted as `--header "<headerKey>: <headerValue>"` and appended into one string.
- The final curl invocation was embedded in `Args: []string{"/bin/sh", "-c", curlCommand}` for the CronJob container.
- Because header keys were not escaped for shell context, a key such as `X-Exploit"; echo CVE_PRODUCT_RCE; id; echo "` terminates the intended quoted header and injects shell commands.
- The vulnerable parent commit used `/bin/sh -c`; the fixed commit switches to exec-form invocation, `Command: []string{"curl"}`, passes each curl argument as a separate argv entry, and uses `--data-raw` for the body so no shell interprets attacker data.

The fixed commit used for negative control is `3356b86a8bfab3f960aa420310ebff765df9dede` (`[Security] Fix cron trigger shell injection`). The reproduction script checks out and builds `3356b86a8bfa^` for the vulnerable path and `3356b86a8bfa` for the fixed path, and verifies the relevant patch hunk before running.

## Reproduction Steps

1. Use `bundle/repro/reproduction_steps.sh`.
2. The script:
   - Reuses the prepared Nuclio repository cache when available.
   - Resolves the vulnerable commit as `3356b86a8bfa^` and the fixed commit as `3356b86a8bfa`.
   - Builds the real Nuclio `cmd/controller` binary for both commits.
   - Creates fresh kind Kubernetes clusters for two vulnerable attempts and two fixed attempts.
   - Starts the real Nuclio controller binary inside each kind control-plane container.
   - Applies real `NuclioFunction` and `NuclioProject` custom resources.
   - Waits for the controller to generate a Kubernetes CronJob from the malicious cron trigger.
   - Creates a manual Job from that CronJob and captures the real pod logs.
3. Expected evidence:
   - Vulnerable attempts: CronJob JSON contains `args[0] == "/bin/sh"` and `args[1] == "-c"`, and pod logs contain `CVE_PRODUCT_RCE` and `uid=`.
   - Fixed attempts: CronJob JSON contains `command: ["curl"]`, does not contain `/bin/sh` or `-c`, and pod logs contain only the stub HTTP response `ok` with no attacker marker.

## Evidence

- `bundle/logs/reproduction_steps.log` — top-level run log for the final successful run.
- `bundle/repro/runtime_manifest.json` — structured runtime manifest showing `entrypoint_kind="endpoint"`, `service_started=true`, `healthcheck_passed=true`, and `target_path_reached=true`.
- `bundle/logs/vulnerable_attempt1/cronjob_pretty.json` and `bundle/logs/vulnerable_attempt2/cronjob_pretty.json` — vulnerable controller-generated CronJobs. They show the generated container args include `/bin/sh`, `-c`, and an injected shell command string containing `echo CVE_PRODUCT_RCE; id`.
- `bundle/logs/vulnerable_attempt1/pod.log` and `bundle/logs/vulnerable_attempt2/pod.log` — real CronJob-derived pod logs. Key excerpt:

```text
CVE_PRODUCT_RCE
uid=100(curl_user) gid=101(curl_group) groups=101(curl_group)
```

- `bundle/logs/fixed_attempt1/cronjob_pretty.json` and `bundle/logs/fixed_attempt2/cronjob_pretty.json` — fixed controller-generated CronJobs. They show `command: ["curl"]` and discrete args containing the malicious strings as data, not shell syntax.
- `bundle/logs/fixed_attempt1/pod.log` and `bundle/logs/fixed_attempt2/pod.log` — fixed negative control pod logs. They contain `ok` and do not contain `CVE_FIXED_SHOULD_NOT_RUN`.
- Environment details captured in `bundle/logs/reproduction_steps.log` include Go, Docker, kind, resolved commits, and built controller binary metadata.

## Recommendations / Next Steps

- Keep the fixed exec-form approach: never pass user-controlled cron trigger header keys, header values, or body through `/bin/sh -c`.
- Pass curl and all arguments as a command/argv vector, not a shell command string.
- Use `--data-raw` or an equivalent safe body handling mechanism to avoid file expansion or shell substitution primitives.
- Add regression tests that exercise malicious header keys, header values, and bodies through the controller/CronJob generation path and assert no shell is present in the resulting pod spec.
- Upgrade Nuclio deployments to a version containing fixed commit `3356b86a8bfab3f960aa420310ebff765df9dede` or later.

## Additional Notes

- Idempotency confirmation: `bundle/repro/reproduction_steps.sh` was run successfully twice consecutively after the final fixes.
- The script uses real Kubernetes objects and a real Nuclio controller binary, but it starts the controller directly in the kind control-plane container rather than installing the full Helm chart. This preserves the relevant production boundary: Kubernetes API/CRD watch -> Nuclio controller reconciliation -> generated Kubernetes CronJob -> real CronJob pod execution.
- A small busybox HTTP stub is deployed only so fixed exec-form curl has a reachable function service target and can complete without retry timeout. It is not used to simulate the vulnerable controller or CronJob generation behavior.
