CVE-2026-44181 - Jupyter Enterprise Gateway Jinja2 SSTI RCE

Jupyter Enterprise Gateway versions before 3.3.0 allow user-controlled KERNEL_* environment values to reach Jinja2 template rendering for Kubernetes kernel manifests. A value that is treated as template source can execute Python code in the Enterprise Gateway process before a kernel pod is created.

The impact is larger than a single notebook server. Enterprise Gateway often runs with Kubernetes service-account permissions to create pods, services, config maps, persistent volumes, claims, and related resources. Remote code execution in that process can expose the service-account token, schedule privileged workloads, read cluster secrets where RBAC permits it, and pivot from notebook infrastructure into the worker cluster.

When to use it

Use this recipe when a repository, notebook platform, or Kubernetes-backed Jupyter Enterprise Gateway deployment lets user-controlled KERNEL_* values reach Jinja2 manifest templates. It is aimed at source-code remediation, SSTI prevention, Kubernetes service-account blast-radius reduction, and audit evidence that kernel launch metadata is data, not template source.

Inputs

  • jupyter_enterprise_gateway version, kernel spec templates, Jinja2 renderer, service account policy, namespace policy, and deployment config.
  • Source paths that render kernel manifests, pass KERNEL_* values into templates, create Kubernetes resources, or log rendered templates/errors.
  • Regression fixtures for Jinja expressions, Python object traversal markers, benign env values, escaped values, and expected reject/render behavior.
  • Boundary evidence: Enterprise Gateway process privileges, Kubernetes permissions, generated manifests, logs, secrets, and impacted kernels.

Affected versions

  • Vulnerable package: jupyter_enterprise_gateway >=2.0.0rc2, <3.3.0
  • Fixed package: jupyter_enterprise_gateway 3.3.0+
  • Affected surface: Enterprise Gateway Kubernetes kernel manifest rendering
  • Affected input shape: user-influenced KERNEL_* environment values that become Jinja2-rendered manifest variables
  • Related recipes: CVE-2026-44180 covers prohibited UID/GID bypass; CVE-2026-44182 covers YAML injection in the same manifest-rendering boundary

Indicator-of-exposure

  • The repository depends on, vendors, builds, or deploys jupyter_enterprise_gateway >=2.0.0rc2, <3.3.0.
  • Enterprise Gateway is used with Kubernetes process proxies, JupyterHub, shared notebook clusters, ML workbenches, agent notebook workspaces, or remote kernel services.
  • Kernel launch requests can pass env values from notebook users, tenants, uploaded notebooks, model output, CI jobs, support tools, or automation.
  • Templates or wrappers render KERNEL_POD_NAME, KERNEL_NAMESPACE, KERNEL_WORKING_DIR, KERNEL_UID, KERNEL_GID, image names, volume names, or other KERNEL_* values through Jinja2.
  • The Enterprise Gateway pod can create Kubernetes resources, read secrets, mount PVCs, reach internal services, or access cloud credentials.

Quick checks:

rg -n "jupyter_enterprise_gateway|enterprise-gateway|enterprisegateway|kernel-pod.yaml.j2|Jinja2|jinja|Template\\(|Environment\\(|KERNEL_POD_NAME|KERNEL_NAMESPACE|KERNEL_WORKING_DIR|KERNEL_UID|KERNEL_GID|launch_kubernetes|processproxies" .
python -m pip show jupyter_enterprise_gateway
pip freeze | rg "^jupyter-enterprise-gateway==|^jupyter_enterprise_gateway=="
rg -n "jupyter[_-]enterprise[_-]gateway|EnterpriseGateway|kernel-pod.yaml.j2|KERNEL_|serviceAccount|RoleBinding|ClusterRoleBinding|secrets|persistentvolumes|hostPath|privileged" Dockerfile* docker-compose*.yml pyproject.toml requirements*.txt environment*.yml charts k8s deploy .devcontainer .github .

Windows:

rg -n "jupyter_enterprise_gateway|enterprise-gateway|enterprisegateway|kernel-pod.yaml.j2|Jinja2|jinja|Template\\(|Environment\\(|KERNEL_POD_NAME|KERNEL_NAMESPACE|KERNEL_WORKING_DIR|KERNEL_UID|KERNEL_GID|launch_kubernetes|processproxies" .
python -m pip show jupyter_enterprise_gateway
pip freeze | rg "^jupyter-enterprise-gateway==|^jupyter_enterprise_gateway=="
rg -n "jupyter[_-]enterprise[_-]gateway|EnterpriseGateway|kernel-pod.yaml.j2|KERNEL_|serviceAccount|RoleBinding|ClusterRoleBinding|secrets|persistentvolumes|hostPath|privileged" Dockerfile* docker-compose*.yml pyproject.toml requirements*.txt environment*.yml charts k8s deploy .devcontainer .github .

Do not send SSTI probes, evaluate template expressions, read service-account tokens, or test command execution against live Enterprise Gateway services.

Remediation strategy

  • Upgrade every controlled Enterprise Gateway runtime, Python lock, image, Helm chart, deployment manifest, SBOM, and runbook to jupyter_enterprise_gateway 3.3.0+.
  • If this repository owns Enterprise Gateway forks, wrappers, custom process proxies, or kernel manifest rendering, make untrusted KERNEL_* values data only. They must never be compiled or re-rendered as Jinja2 template source.
  • Prefer structured Kubernetes object construction plus YAML-safe serialization over string templating for user-influenced fields.
  • Reject or escape Jinja delimiters, block markers, control characters, newlines where the target field is scalar-only, duplicate env keys, and values that cannot be represented safely as the expected Kubernetes type.
  • Scope the Enterprise Gateway service account to only the resources and namespaces required for kernel launch. Avoid broad secret, persistent-volume, rolebinding, and cluster-wide permissions.
  • If untrusted users could launch kernels before the fix, treat the Enterprise Gateway pod and service account as potentially compromised.

The prompt

You are remediating CVE-2026-44181 / GHSA-f49j-v924-fx9w, a critical Jupyter
Enterprise Gateway Jinja2 server-side template injection where user-controlled
`KERNEL_*` values can be evaluated during Kubernetes kernel manifest rendering.
Produce exactly one output:

- A reviewer-ready PR/change request that upgrades Enterprise Gateway, prevents
  untrusted `KERNEL_*` data from being evaluated as Jinja2 template source,
  reduces Kubernetes service-account blast radius, refreshes generated
  artifacts, and documents operator cleanup, or
- TRIAGE.md if this repository does not control an affected Enterprise Gateway
  runtime, fork, wrapper, kernel template, image, or deployment.

## Rules

- Scope only CVE-2026-44181 / GHSA-f49j-v924-fx9w and directly related
  Enterprise Gateway Kubernetes manifest rendering, service-account hardening,
  and kernel-launch input validation.
- Also check whether the same Enterprise Gateway deployment is affected by
  CVE-2026-44180 and CVE-2026-44182, but do not broaden into unrelated Jupyter
  issues unless they share the same manifest-rendering boundary.
- Treat service-account tokens, Kubernetes secrets, notebook files, PVC
  contents, dataset mounts, cloud credentials, Git credentials, SSH keys,
  cluster inventory, pod logs, and user environment variables as sensitive.
- Do not send SSTI payloads, execute template expressions, run OS commands,
  read service-account tokens, schedule privileged pods, or inspect live
  secrets.
- Do not print or commit rendered manifests that include secrets, real
  environment variables, token paths, notebook output, pod logs, or cluster
  credentials.
- Do not rely on Jinja sandboxing, deny-lists, UI-only validation, or network
  perimeter controls as the only fix.
- Do not auto-merge.

## Steps

1. Inventory every repository-controlled Enterprise Gateway reference:
   Python manifests, lockfiles, Conda files, Dockerfiles, JupyterHub images,
   Helm charts, Kubernetes manifests, Terraform, Ansible, CI images,
   kernelspecs, kernel pod templates, SBOMs, generated dependency reports,
   platform runbooks, forks, launch wrappers, and custom process proxies.
2. Determine every resolved `jupyter_enterprise_gateway` version. A target is
   vulnerable if it resolves to `>=2.0.0rc2, <3.3.0`.
3. Search for Jinja2 and kernel manifest rendering paths:
   `kernel-pod.yaml.j2`, `launch_kubernetes`, `Template(`, `Environment(`,
   `render`, `safe_render`, `KERNEL_POD_NAME`, `KERNEL_NAMESPACE`,
   `KERNEL_WORKING_DIR`, `KERNEL_UID`, `KERNEL_GID`, and custom `KERNEL_*`
   substitutions.
4. Determine who can influence kernel launch environment: notebook users,
   tenants, agents, uploaded notebooks, model output, CI jobs, support users,
   API clients, or administrators only.
5. Inventory Enterprise Gateway RBAC and namespace policy: service accounts,
   roles, rolebindings, cluster roles, secret permissions, pod creation,
   service creation, PVC/PV access, hostPath allowance, privileged workloads,
   and namespace admission controls.
6. If this repository does not control an affected Enterprise Gateway runtime,
   stop with `TRIAGE.md` listing checked files, runtime owner if known, and
   required fixed version `jupyter_enterprise_gateway 3.3.0+`.
7. Upgrade all controlled Enterprise Gateway packages and images to `3.3.0+`.
   Regenerate Python locks, Conda files, image digests, Helm render output,
   SBOMs, dependency reports, and docs that pin vulnerable versions.
8. Where this repository owns rendering code, make the manifest boundary fail
   closed:
   - treat request-supplied `KERNEL_*` values as data, never template source;
   - avoid second-pass template rendering of any user-influenced value;
   - construct Kubernetes resources as typed objects or dictionaries before
     YAML serialization where practical;
   - reject template delimiters, block markers, control characters, duplicate
     env keys, and non-scalar values in scalar fields;
   - return non-secret validation errors.
9. Harden service-account and pod policy:
   - remove secret, PV/PVC, rolebinding, and cluster-wide permissions not
     required for kernel launch;
   - use namespace-scoped roles where possible;
   - require restricted pod security for untrusted kernel namespaces;
   - deny privileged pods, hostPath mounts, host networking, and privilege
     escalation unless a named exception is approved.
10. Add reviewer-safe tests:
    - vulnerable Enterprise Gateway versions are absent from manifests and
      images;
    - user-influenced `KERNEL_*` values are rendered as literal data, not
      evaluated as templates;
    - delimiter-like and newline-containing fixture strings are rejected or
      escaped without executing code;
    - rendered test manifests contain only expected object kinds;
    - service-account manifests have least-privilege permissions.
11. Add a PR body section named `CVE-2026-44181 operator actions` that states:
    - Enterprise Gateway versions before and after;
    - which users, agents, or systems could pass kernel env values;
    - whether the same deployment is also affected by CVE-2026-44180 or
      CVE-2026-44182;
    - which service accounts, namespaces, PVCs, secrets, and cluster resources
      may have been reachable before the patch;
    - whether service-account token rotation, pod restart, image rebuild,
      namespace audit, log review, or secret rotation is required;
    - which validation commands passed.
12. Run available validation: package install, lockfile integrity, unit tests,
    manifest-render tests, Kubernetes RBAC tests, policy tests, image build,
    deployment rendering, SBOM refresh, dependency/security scans, and platform
    smoke tests that do not execute template payloads.
13. Use PR title:
    `fix(sec): remediate CVE-2026-44181 in Enterprise Gateway`.

## Stop conditions

- No affected Enterprise Gateway runtime, image, fork, wrapper, process proxy,
  kernel template, or deployment is controlled by this repository.
- Enterprise Gateway is supplied only by another team, managed notebook
  service, or external image; document owner and required fixed version in
  `TRIAGE.md`.
- A fixed Enterprise Gateway version cannot be consumed without a broader
  notebook-platform migration.
- Product requirements intentionally evaluate user-supplied kernel environment
  values as templates; document the required product/security decision.
- Verification would require SSTI execution, command execution, live secret
  access, service-account token reads, or privileged pod scheduling.
- Validation fails for unrelated pre-existing reasons; document those failures
  instead of broadening scope.

Output contract

  • A reviewer-ready PR or change request that upgrades Enterprise Gateway, removes untrusted template evaluation, adds SSTI regression tests, reduces service-account reach, and documents rollout validation.
  • Or a TRIAGE.md file that lists inspected files, owner, observed version, template boundary, process/Kubernetes privileges, required fix, and residual risk.
  • The output must include exact validation commands and must not execute template payloads against production, expose secrets, or create cluster resources outside safe fixtures.

Verification - what the reviewer looks for

  • No controlled lockfile, image, SBOM, package manifest, or deployment target resolves jupyter_enterprise_gateway to a vulnerable version.
  • User-controlled KERNEL_* data cannot be compiled, rendered, or re-rendered as Jinja2 template source.
  • Tests use inert fixture strings and prove rendering behavior without executing code or exposing secrets.
  • Enterprise Gateway service accounts are namespace-scoped and least privilege for kernel launch.
  • Operator notes cover possible service-account compromise, token rotation, namespace review, pod cleanup, image rebuilds, and related CVE checks.

Watch for

  • Updating Python requirements while Helm charts, JupyterHub images, kernelspecs, or generated SBOMs still ship an old Enterprise Gateway.
  • Escaping only one field while other KERNEL_* values still pass through the same Jinja2 render path.
  • Adding a deny-list for a few template markers while preserving second-pass rendering of untrusted strings.
  • Leaving the Enterprise Gateway service account able to read secrets or create broad cluster resources after the RCE is fixed.
  • Tests that include real service-account tokens, pod logs, notebook data, or command output.

References