CVE-2026-104795 Insights-runtime-extractor: insights-runtime-extractor: container escape via privileged binary execution

High 8.8 Published Updated

A privileged container escape allows attackers to execute arbitrary code as root on the host by exploiting insufficient privilege drops in the insights-runtime-extractor.

Exploited in the wild
Not known
Login needed
Any signed-in user
Attackable
Local or same network only
Victim action needed
Not needed
Fix
None listed

What is CVE-2026-104795?

CVE-2026-104795 is a high-severity vulnerability in Red Hat OpenShift Container Platform 4.19, published on 14 Oct 2026. It can only be exploited from the same machine or local network, with no action from the victim.

Official description

The insights-runtime-extractor runs as a privileged DaemonSet (`hostPID: true`) that scans container processes for runtime fingerprinting. When scanning a container, the coordinator:

1. **fork()s** a child process 2. **setns()** into the target container's PID and mount namespaces 3. **fchdir()** back to an orphaned FD pointing at the extractor's own root filesystem (where `/crio.sock` is hostPath-mounted) 4. Calls **only `seteuid(target_uid)`** — changing the effective UID but leaving the **real UID and saved-set-UID at 0** and **retaining the permitted capability set** 5. The `check_no_privileged_perms()` guard inspects only the Effective capability set (so it passes), and is **skipped entirely when the target runs as uid 0** 6. The `VersionExecutable` fingerprint invokes `fpr_kind_executable` with `process.command_line[0]` — the target's argv[0], read from `/proc/<pid>/cmdline` and **fully controlled by the workload** 7. `fpr_kind_executable` calls `exec.Command(executable, "--version").Output()` — executing the **workload's own binary** inside the workload's mount namespace while **ruid=0 in the host user namespace**

The executed process can call `setuid(0)` to restore full root with `CAP_SYS_ADMIN`, and inherits the orphaned cwd which resolves into the extractor container's filesystem containing the host CRI-O socket.

## Affected Code

### 1. Insufficient privilege drop (Rust — extractor coordinator)

**File:** `extractor/src/insights_runtime_extractor.rs`

```rust // Lines 139-146 — seteuid-only drop, guard skipped for root containers join_process_namespaces(process.pid)?; change_dir(current_dir); switch_user(*process.uid)?; if *process.uid != 0 { perms::check_no_privileged_perms() .expect("Must not have privileged permissions to run fingerprints"); } fingerprint::run_fingerprints(&config, out_dir, &process); ```

```rust // Lines 182-185 — only effective UID changed; ruid/suid stay 0 fn switch_user(uid: u32) -> Result<(), ScannerError> { debug!("... Becoming user: {uid}"); seteuid(uid.into()).map_err(|e| ScannerError::Errno(e)) } ```

### 2. Execution of untrusted binary (Go — fingerprint)

**File:** `fingerprints/pkg/utils/file.go`

```go // Lines 75-80 — executes a path taken verbatim from workload's argv[0] func GetExecutableVersionOutput(executable string) (string, error) { out, err := exec.Command(executable, "--version").Output() if err != nil { return "", err } return string(out), nil } ```

### 3. Workload-controlled path forwarded (Rust — version_executable)

**File:** `version_executable.rs`

```rust // Lines 29-34 — workload-controlled command_line[0] forwarded to fingerprint return Some(vec![ fpr_kind_executable, out_dir.to_string(), String::from(&process.command_line[0]), String::from(&version_executable.runtime_kind_name), ]); ```

## Attack Pattern

**Attacker:** Any tenant able to schedule a pod (unprivileged, any namespace) **Victim:** The node running the insights-runtime-extractor DaemonSet **Trigger:** Automatic — the DaemonSet scans all container processes on the node

**Attack sequence:**

1. Attacker creates a pod whose process name matches a configured versioned-executable pattern (`node`, `python`, `python3`, `MainThread`, or contains `java`) 2. The pod's main binary (at the path matching argv[0]) is a malicious executable that calls `setuid(0)` to restore root 3. When the insights operator triggers a scan, the DaemonSet forks, enters the attacker's mount namespace, and executes the attacker's binary with ruid=0 4. The attacker's code regains full root with `CAP_SYS_ADMIN` in the host user namespace 5. The inherited cwd contains the host CRI-O socket → full node compromise

Weakness: CWE-250

Which versions are affected by CVE-2026-104795?

How do I fix CVE-2026-104795?

No fix has been published for CVE-2026-104795 yet. Limit exposure of the affected software until one is available.

Is CVE-2026-104795 being exploited?

There is no known exploitation of CVE-2026-104795 in the wild and no public exploit code.

Sources

Also known as GHSA-98f3-7g2j-289q.

Is CVE-2026-104795 in your software?

Upload an SBOM and sbomify checks it against every vulnerability here, every day.

Check your SBOMs for free