# [CRIT] [GHSA / CRITICAL] CVE-2026-44180: Jupyter Enterprise Gateway: ContainerProcessProxy._enforce_prohibited_ids Bypass

**Source:** GitHub Security Advisories
**Published:** 2026-06-03
**Article:** https://github.com/advisories/GHSA-chq7-94j8-cj28

## Threat Profile

Jupyter Enterprise Gateway: ContainerProcessProxy._enforce_prohibited_ids Bypass

### Summary

Jupyter Enterprise Gateway has a prohibited UID and GID feature that by default prevents launching kernels with UID or GID 0 (root).
This can be bypassed. It is possible to launch kernels with a prohibited UID and/or GID by using a specially crafted `KERNEL_UID` or `KERNEL_GID` value.

The feature is described in the documentation: 

https://github.com/jupyter-server/enterprise_gateway/blob/152c20f162f…

## Indicators of Compromise (high-fidelity only)

- **CVE:** `CVE-2026-44180`

## MITRE ATT&CK Techniques

- **T1190** — Exploit Public-Facing Application
- **T1611** — Escape to Host
- **T1068** — Exploitation for Privilege Escalation
- **T1610** — Deploy Container
- **T1053.003** — Scheduled Task/Job: Cron

## Kill chain phases observed

_(none detected from narrative keywords)_

## Recommended hunts

### Jupyter Enterprise Gateway /api/kernels POST with KERNEL_UID/GID body (CVE-2026-44180)

`UC_135_1` · phase: **exploit** · confidence: **Medium** · AI-generated for this article

**Splunk SPL (CIM):**
```spl
| tstats summariesonly=t count, values(Web.http_user_agent) as user_agents, values(Web.dest) as dest_hosts from datamodel=Web where Web.http_method=POST Web.url="*/api/kernels*" by Web.src, Web.url, _time span=1m | `drop_dm_object_name(Web)` | rename src as client_ip | sort - _time
```

### Enterprise Gateway service account creates Jupyter kernel pod as root (CVE-2026-44180 outcome)

`UC_135_2` · phase: **exploit** · confidence: **High** · AI-generated for this article

**Splunk SPL (CIM):**
```spl
| tstats summariesonly=t count, values(All_Changes.object) as pod_names, values(All_Changes.src) as src_ips from datamodel=Change where All_Changes.action=created All_Changes.object_category=pod All_Changes.user="*enterprise-gateway*" by All_Changes.user, _time span=5m | `drop_dm_object_name(All_Changes)` | join type=inner pod_names [ search index=k8s_audit sourcetype="kube:apiserver:audit" verb=created objectRef.resource=pods "user.username"="*enterprise-gateway*" ("requestObject.spec.securityContext.runAsUser"=0 OR "requestObject.spec.securityContext.runAsGroup"=0 OR "requestObject.spec.containers{}.securityContext.runAsUser"=0) | rename objectRef.name as pod_names | table pod_names, requestObject.spec.securityContext.runAsUser, requestObject.spec.securityContext.runAsGroup, sourceIPs{} ] | sort - _time
```

### Jupyter kernel pod created with hostPath volume by enterprise-gateway SA

`UC_135_3` · phase: **actions** · confidence: **High** · AI-generated for this article

**Splunk SPL (CIM):**
```spl
| tstats summariesonly=t count from datamodel=Change where All_Changes.action=created All_Changes.object_category=pod All_Changes.user="*enterprise-gateway*" by All_Changes.object, All_Changes.user, _time span=5m | `drop_dm_object_name(All_Changes)` | join type=inner object [ search index=k8s_audit sourcetype="kube:apiserver:audit" verb=created objectRef.resource=pods "user.username"="*enterprise-gateway*" "requestObject.spec.volumes{}.hostPath.path"=* | rename objectRef.name as object | eval host_paths=mvjoin('requestObject.spec.volumes{}.hostPath.path', ",") | table object, host_paths, sourceIPs{} ] | sort - _time
```

### Cron/persistence file written on Kubernetes worker node from container runtime context

`UC_135_4` · phase: **install** · confidence: **Medium** · AI-generated for this article

**Splunk SPL (CIM):**
```spl
| tstats summariesonly=t count, values(Filesystem.process_name) as procs, values(Filesystem.user) as users from datamodel=Endpoint.Filesystem where (Filesystem.file_path IN ("/etc/crontab","/etc/anacrontab") OR Filesystem.file_path="/etc/cron.d/*" OR Filesystem.file_path="/etc/cron.daily/*" OR Filesystem.file_path="/etc/cron.hourly/*" OR Filesystem.file_path="/etc/cron.weekly/*" OR Filesystem.file_path="/etc/cron.monthly/*" OR Filesystem.file_path="/var/spool/cron/*") Filesystem.action IN ("created","modified","written") by Filesystem.dest, Filesystem.file_path, _time span=5m | `drop_dm_object_name(Filesystem)` | search dest IN ("*worker*","*node*","*k8s*","*kube*") OR procs IN ("runc","containerd-shim","containerd-shim-runc-v2") | sort - _time
```

**Defender KQL:**
```kql
DeviceFileEvents
| where Timestamp > ago(1d)
| where ActionType in ("FileCreated","FileModified","FileRenamed")
| where FolderPath startswith "/etc/cron."
     or FolderPath == "/var/spool/cron"
     or FolderPath startswith "/var/spool/cron/"
     or (FolderPath == "/etc" and FileName in ("crontab","anacrontab"))
| where InitiatingProcessAccountName !endswith "$"
| join kind=leftouter (DeviceInfo | summarize arg_max(Timestamp, OSPlatform, MachineGroup, AdditionalFields) by DeviceId) on DeviceId
| where OSPlatform in ("Linux","Ubuntu","RedHat","CentOS","Debian","SUSE")
| where InitiatingProcessFolderPath has_any ("/run/containerd","/var/lib/docker","/var/lib/containerd","/usr/bin/runc","/usr/sbin/runc")
   or InitiatingProcessFileName in~ ("runc","containerd-shim","containerd-shim-runc-v2","crun","kata-runtime")
   or InitiatingProcessParentFileName in~ ("runc","containerd-shim","containerd-shim-runc-v2","crun")
| project Timestamp, DeviceName, FolderPath, FileName, InitiatingProcessFileName, InitiatingProcessParentFileName, InitiatingProcessFolderPath, InitiatingProcessCommandLine, InitiatingProcessAccountName
| order by Timestamp desc
```

### IOC-driven hunts (use shared templates)

These are standard IOC-substitution hunts — the canonical SPL and KQL live once in [`_TEMPLATES.md`](../_TEMPLATES.md), so we don't repeat the same boilerplate on every CVE / hash / network-IOC briefing.

- **Asset exposure — vulnerability matches article CVE(s)** ([template](../_TEMPLATES.md#asset-exposure)) — phase: **recon**, confidence: **High**
  - CVE(s): `CVE-2026-44180`


## Why this matters

Severity classified as **CRIT** based on: CVE present, 5 use case(s) fired, 5 technique(s) inferred. Read the full article for actor attribution, tooling details, and any defanged IOCs in the body that aren't visible in the RSS summary.
