{"id":"CVE-2026-104795","state":"PUBLISHED","title":"Insights-runtime-extractor: insights-runtime-extractor: container escape via privileged binary execution","description":"The insights-runtime-extractor runs as a privileged DaemonSet (`hostPID: true`)\nthat scans container processes for runtime fingerprinting. When scanning a\ncontainer, the coordinator:\n\n1. **fork()s** a child process\n2. **setns()** into the target container's PID and mount namespaces\n3. **fchdir()** back to an orphaned FD pointing at the extractor's own root\n   filesystem (where `/crio.sock` is hostPath-mounted)\n4. Calls **only `seteuid(target_uid)`** — changing the effective UID but leaving\n   the **real UID and saved-set-UID at 0** and **retaining the permitted\n   capability set**\n5. The `check_no_privileged_perms()` guard inspects only the Effective capability\n   set (so it passes), and is **skipped entirely when the target runs as uid 0**\n6. The `VersionExecutable` fingerprint invokes `fpr_kind_executable` with\n   `process.command_line[0]` — the target's argv[0], read from\n   `/proc/<pid>/cmdline` and **fully controlled by the workload**\n7. `fpr_kind_executable` calls `exec.Command(executable, \"--version\").Output()`\n   — executing the **workload's own binary** inside the workload's mount\n   namespace while **ruid=0 in the host user namespace**\n\nThe executed process can call `setuid(0)` to restore full root with\n`CAP_SYS_ADMIN`, and inherits the orphaned cwd which resolves into the extractor\ncontainer's filesystem containing the host CRI-O socket.\n\n## Affected Code\n\n### 1. Insufficient privilege drop (Rust — extractor coordinator)\n\n**File:** `extractor/src/insights_runtime_extractor.rs`\n\n```rust\n// Lines 139-146 — seteuid-only drop, guard skipped for root containers\njoin_process_namespaces(process.pid)?;\nchange_dir(current_dir);\nswitch_user(*process.uid)?;\nif *process.uid != 0 {\n    perms::check_no_privileged_perms()\n        .expect(\"Must not have privileged permissions to run fingerprints\");\n}\nfingerprint::run_fingerprints(&config, out_dir, &process);\n```\n\n```rust\n// Lines 182-185 — only effective UID changed; ruid/suid stay 0\nfn switch_user(uid: u32) -> Result<(), ScannerError> {\n    debug!(\"... Becoming user: {uid}\");\n    seteuid(uid.into()).map_err(|e| ScannerError::Errno(e))\n}\n```\n\n### 2. Execution of untrusted binary (Go — fingerprint)\n\n**File:** `fingerprints/pkg/utils/file.go`\n\n```go\n// Lines 75-80 — executes a path taken verbatim from workload's argv[0]\nfunc GetExecutableVersionOutput(executable string) (string, error) {\n    out, err := exec.Command(executable, \"--version\").Output()\n    if err != nil {\n        return \"\", err\n    }\n    return string(out), nil\n}\n```\n\n### 3. Workload-controlled path forwarded (Rust — version_executable)\n\n**File:** `version_executable.rs`\n\n```rust\n// Lines 29-34 — workload-controlled command_line[0] forwarded to fingerprint\nreturn Some(vec![\n    fpr_kind_executable,\n    out_dir.to_string(),\n    String::from(&process.command_line[0]),\n    String::from(&version_executable.runtime_kind_name),\n]);\n```\n\n## Attack Pattern\n\n**Attacker:** Any tenant able to schedule a pod (unprivileged, any namespace)\n**Victim:** The node running the insights-runtime-extractor DaemonSet\n**Trigger:** Automatic — the DaemonSet scans all container processes on the node\n\n**Attack sequence:**\n\n1. Attacker creates a pod whose process name matches a configured\n   versioned-executable pattern (`node`, `python`, `python3`, `MainThread`,\n   or contains `java`)\n2. The pod's main binary (at the path matching argv[0]) is a malicious\n   executable that calls `setuid(0)` to restore root\n3. When the insights operator triggers a scan, the DaemonSet forks, enters the\n   attacker's mount namespace, and executes the attacker's binary with ruid=0\n4. The attacker's code regains full root with `CAP_SYS_ADMIN` in the host user\n   namespace\n5. The inherited cwd contains the host CRI-O socket → full node compromise","publishedAt":"2026-10-14T10:55:17.144Z","updatedAt":"2026-10-30T04:26:30.832Z","severity":{"score":8.8,"label":"High","version":"3.1","vector":"CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H","source":"redhat"},"assigner":"redhat","products":["Red Hat Red Hat OpenShift Container Platform 4.19","Red Hat Red Hat OpenShift Container Platform 4.20","Red Hat Red Hat OpenShift Container Platform 4.21","Red Hat Red Hat OpenShift Container Platform 4.22","Red Hat Red Hat OpenShift Container Platform 5"],"affected":[{"vendor":"Red Hat","product":"Red Hat OpenShift Container Platform 4.19","packageName":"openshift4/insights-runtime-extractor-rhel9","defaultStatus":"affected","versions":[{"version":"1792771524","status":"unaffected","lessThan":"*","versionType":"rpm"}],"collectionURL":"https://catalog.redhat.com/software/containers/","cpes":["cpe:/a:redhat:openshift:4.19::el9"]},{"vendor":"Red Hat","product":"Red Hat OpenShift Container Platform 4.20","packageName":"openshift4/insights-runtime-extractor-rhel9","defaultStatus":"affected","versions":[{"version":"1792849665","status":"unaffected","lessThan":"*","versionType":"rpm"}],"collectionURL":"https://catalog.redhat.com/software/containers/","cpes":["cpe:/a:redhat:openshift:4.20::el9"]},{"vendor":"Red Hat","product":"Red Hat OpenShift Container Platform 4.21","packageName":"openshift4/insights-runtime-extractor-rhel9","defaultStatus":"affected","versions":[{"version":"1792008935","status":"unaffected","lessThan":"*","versionType":"rpm"}],"collectionURL":"https://catalog.redhat.com/software/containers/","cpes":["cpe:/a:redhat:openshift:4.21::el9"]},{"vendor":"Red Hat","product":"Red Hat OpenShift Container Platform 4.22","packageName":"openshift4/insights-runtime-extractor-rhel9","defaultStatus":"affected","versions":[{"version":"1792844435","status":"unaffected","lessThan":"*","versionType":"rpm"}],"collectionURL":"https://catalog.redhat.com/software/containers/","cpes":["cpe:/a:redhat:openshift:4.22::el9"]},{"vendor":"Red Hat","product":"Red Hat OpenShift Container Platform 5","packageName":"openshift5/insights-runtime-extractor-rhel9","defaultStatus":"affected","collectionURL":"https://access.redhat.com/downloads/content/package-browser/","cpes":["cpe:/a:redhat:openshift:5"]}],"references":["https://access.redhat.com/errata/RHSA-2026:83702","https://access.redhat.com/errata/RHSA-2026:89198","https://access.redhat.com/errata/RHSA-2026:89341","https://access.redhat.com/errata/RHSA-2026:89655","https://access.redhat.com/security/cve/CVE-2026-104795","https://bugzilla.redhat.com/show_bug.cgi?id=2543917"],"weaknesses":["CWE-250"],"ingestedAt":"2026-10-30T04:30:05.894Z","source":{"repository":"CVEProject/cvelistV5","path":"cves/2026/104xxx/CVE-2026-104795.json","commit":"c05ea29574fc006043e09814ef25bbcec9d994f8","baselineCommit":"556c9d3a8cd17e218bb8e452ba7cd619a384ff47"},"raw":{"dataType":"CVE_RECORD","dataVersion":"5.2","cveMetadata":{"cveId":"CVE-2026-104795","state":"PUBLISHED","datePublished":"2026-10-14T10:55:17.144Z","dateUpdated":"2026-10-30T04:26:30.832Z","assignerShortName":"redhat","assignerOrgId":"53f830b8-0a3f-465b-8143-3b8a9948e749","dateReserved":"2026-10-02T13:07:13.820Z"},"containers":{"cna":{"title":"Insights-runtime-extractor: insights-runtime-extractor: container escape via privileged binary execution","descriptions":[{"lang":"en","value":"The insights-runtime-extractor runs as a privileged DaemonSet (`hostPID: true`)\nthat scans container processes for runtime fingerprinting. When scanning a\ncontainer, the coordinator:\n\n1. **fork()s** a child process\n2. **setns()** into the target container's PID and mount namespaces\n3. **fchdir()** back to an orphaned FD pointing at the extractor's own root\n   filesystem (where `/crio.sock` is hostPath-mounted)\n4. Calls **only `seteuid(target_uid)`** — changing the effective UID but leaving\n   the **real UID and saved-set-UID at 0** and **retaining the permitted\n   capability set**\n5. The `check_no_privileged_perms()` guard inspects only the Effective capability\n   set (so it passes), and is **skipped entirely when the target runs as uid 0**\n6. The `VersionExecutable` fingerprint invokes `fpr_kind_executable` with\n   `process.command_line[0]` — the target's argv[0], read from\n   `/proc/<pid>/cmdline` and **fully controlled by the workload**\n7. `fpr_kind_executable` calls `exec.Command(executable, \"--version\").Output()`\n   — executing the **workload's own binary** inside the workload's mount\n   namespace while **ruid=0 in the host user namespace**\n\nThe executed process can call `setuid(0)` to restore full root with\n`CAP_SYS_ADMIN`, and inherits the orphaned cwd which resolves into the extractor\ncontainer's filesystem containing the host CRI-O socket.\n\n## Affected Code\n\n### 1. Insufficient privilege drop (Rust — extractor coordinator)\n\n**File:** `extractor/src/insights_runtime_extractor.rs`\n\n```rust\n// Lines 139-146 — seteuid-only drop, guard skipped for root containers\njoin_process_namespaces(process.pid)?;\nchange_dir(current_dir);\nswitch_user(*process.uid)?;\nif *process.uid != 0 {\n    perms::check_no_privileged_perms()\n        .expect(\"Must not have privileged permissions to run fingerprints\");\n}\nfingerprint::run_fingerprints(&config, out_dir, &process);\n```\n\n```rust\n// Lines 182-185 — only effective UID changed; ruid/suid stay 0\nfn switch_user(uid: u32) -> Result<(), ScannerError> {\n    debug!(\"... Becoming user: {uid}\");\n    seteuid(uid.into()).map_err(|e| ScannerError::Errno(e))\n}\n```\n\n### 2. Execution of untrusted binary (Go — fingerprint)\n\n**File:** `fingerprints/pkg/utils/file.go`\n\n```go\n// Lines 75-80 — executes a path taken verbatim from workload's argv[0]\nfunc GetExecutableVersionOutput(executable string) (string, error) {\n    out, err := exec.Command(executable, \"--version\").Output()\n    if err != nil {\n        return \"\", err\n    }\n    return string(out), nil\n}\n```\n\n### 3. Workload-controlled path forwarded (Rust — version_executable)\n\n**File:** `version_executable.rs`\n\n```rust\n// Lines 29-34 — workload-controlled command_line[0] forwarded to fingerprint\nreturn Some(vec![\n    fpr_kind_executable,\n    out_dir.to_string(),\n    String::from(&process.command_line[0]),\n    String::from(&version_executable.runtime_kind_name),\n]);\n```\n\n## Attack Pattern\n\n**Attacker:** Any tenant able to schedule a pod (unprivileged, any namespace)\n**Victim:** The node running the insights-runtime-extractor DaemonSet\n**Trigger:** Automatic — the DaemonSet scans all container processes on the node\n\n**Attack sequence:**\n\n1. Attacker creates a pod whose process name matches a configured\n   versioned-executable pattern (`node`, `python`, `python3`, `MainThread`,\n   or contains `java`)\n2. The pod's main binary (at the path matching argv[0]) is a malicious\n   executable that calls `setuid(0)` to restore root\n3. When the insights operator triggers a scan, the DaemonSet forks, enters the\n   attacker's mount namespace, and executes the attacker's binary with ruid=0\n4. The attacker's code regains full root with `CAP_SYS_ADMIN` in the host user\n   namespace\n5. The inherited cwd contains the host CRI-O socket → full node compromise"}],"affected":[{"vendor":"Red Hat","product":"Red Hat OpenShift Container Platform 4.19","packageName":"openshift4/insights-runtime-extractor-rhel9","defaultStatus":"affected","versions":[{"version":"1792771524","status":"unaffected","lessThan":"*","versionType":"rpm"}],"collectionURL":"https://catalog.redhat.com/software/containers/","cpes":["cpe:/a:redhat:openshift:4.19::el9"]},{"vendor":"Red Hat","product":"Red Hat OpenShift Container Platform 4.20","packageName":"openshift4/insights-runtime-extractor-rhel9","defaultStatus":"affected","versions":[{"version":"1792849665","status":"unaffected","lessThan":"*","versionType":"rpm"}],"collectionURL":"https://catalog.redhat.com/software/containers/","cpes":["cpe:/a:redhat:openshift:4.20::el9"]},{"vendor":"Red Hat","product":"Red Hat OpenShift Container Platform 4.21","packageName":"openshift4/insights-runtime-extractor-rhel9","defaultStatus":"affected","versions":[{"version":"1792008935","status":"unaffected","lessThan":"*","versionType":"rpm"}],"collectionURL":"https://catalog.redhat.com/software/containers/","cpes":["cpe:/a:redhat:openshift:4.21::el9"]},{"vendor":"Red Hat","product":"Red Hat OpenShift Container Platform 4.22","packageName":"openshift4/insights-runtime-extractor-rhel9","defaultStatus":"affected","versions":[{"version":"1792844435","status":"unaffected","lessThan":"*","versionType":"rpm"}],"collectionURL":"https://catalog.redhat.com/software/containers/","cpes":["cpe:/a:redhat:openshift:4.22::el9"]},{"vendor":"Red Hat","product":"Red Hat OpenShift Container Platform 5","packageName":"openshift5/insights-runtime-extractor-rhel9","defaultStatus":"affected","collectionURL":"https://access.redhat.com/downloads/content/package-browser/","cpes":["cpe:/a:redhat:openshift:5"]}],"references":[{"url":"https://access.redhat.com/errata/RHSA-2026:83702","name":"RHSA-2026:83702","tags":["vendor-advisory","x_refsource_REDHAT"]},{"url":"https://access.redhat.com/errata/RHSA-2026:89198","name":"RHSA-2026:89198","tags":["vendor-advisory","x_refsource_REDHAT"]},{"url":"https://access.redhat.com/errata/RHSA-2026:89341","name":"RHSA-2026:89341","tags":["vendor-advisory","x_refsource_REDHAT"]},{"url":"https://access.redhat.com/errata/RHSA-2026:89655","name":"RHSA-2026:89655","tags":["vendor-advisory","x_refsource_REDHAT"]},{"url":"https://access.redhat.com/security/cve/CVE-2026-104795","tags":["vdb-entry","x_refsource_REDHAT"]},{"url":"https://bugzilla.redhat.com/show_bug.cgi?id=2543917","name":"RHBZ#2543917","tags":["issue-tracking","x_refsource_REDHAT"]}],"metrics":[{"other":{"content":{"value":"Important","namespace":"https://access.redhat.com/security/updates/classification/"},"type":"Red Hat severity rating"}},{"cvssV3_1":{"attackComplexity":"LOW","attackVector":"LOCAL","availabilityImpact":"HIGH","baseScore":8.8,"baseSeverity":"HIGH","confidentialityImpact":"HIGH","integrityImpact":"HIGH","privilegesRequired":"LOW","scope":"CHANGED","userInteraction":"NONE","vectorString":"CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H","version":"3.1"},"format":"CVSS"}],"problemTypes":[{"descriptions":[{"cweId":"CWE-250","description":"Execution with Unnecessary Privileges","lang":"en","type":"CWE"}]}],"providerMetadata":{"shortName":"redhat","orgId":"53f830b8-0a3f-465b-8143-3b8a9948e749","dateUpdated":"2026-10-30T04:26:30.832Z"},"datePublic":"2026-10-14T09:47:53.272Z","x_redhatCweChain":"CWE-250: Execution with Unnecessary Privileges","workarounds":[{"lang":"en","value":"The vulnerability requires a\ncode fix to implement a complete privilege drop (setting all three UID/GID\nfields, clearing all Linux capability sets, and setting `PR_SET_NO_NEW_PRIVS`)\nbefore executing any fingerprint binary."}],"timeline":[{"lang":"en","time":"2026-09-30T12:50:08.063Z","value":"Reported to Red Hat."},{"lang":"en","time":"2026-10-14T09:47:53.272Z","value":"Made public."}],"x_generator":{"engine":"cvelib 1.8.0"}},"adp":[{"title":"CISA ADP Vulnrichment","metrics":[{"other":{"type":"ssvc","content":{"timestamp":"2026-10-14T15:25:50.103511Z","id":"CVE-2026-104795","options":[{"Exploitation":"none"},{"Automatable":"no"},{"Technical Impact":"total"}],"role":"CISA Coordinator","version":"2.0.3"}}}],"providerMetadata":{"shortName":"CISA-ADP","orgId":"134c704f-9b21-4f2e-91b3-4a467353bcc0","dateUpdated":"2026-10-14T15:26:53.109Z"}}]}}}