← Back to Feed CACHED · 2026-10-14 09:27:21 · CACHE_KEY CVE-2026-107935
CVE-2026-107935 · CWE-22 · Disclosed 2026-10-09

Unauthenticated arbitrary file deletion via path traversal in gvisor-tap-vsock gvproxy /services/forwarder/expose

ASSESSED — NOISGATE
Vendor
—
—
—
Reassessed
—
—
—
Verdict: —
Do you agree?
01 · The Real Story

Like a hotel guest who can slide a note under the door that makes housekeeping shred whatever file you name

gvproxy is the network forwarder that podman machine runs on the host to give containers and VMs network connectivity. Its REST API endpoint /services/forwarder/expose accepts a socket path from the caller — any container in the VM — and passes it straight to os.Remove() followed by net.Listen("unix", path). No path validation, no authentication. A malicious container can send one HTTP POST to 192.168.127.1 and delete any file on the host owned by the gvproxy user, replacing it with a unix socket inode. Affected versions: gvisor-tap-vsock ≥ 0.4.0 through < 0.9.0. The fix shipped in v0.9.0 on October 8, 2026, with Red Hat backporting to gvisor-tap-vsock-0.7.3-5.el9_4.3. Every Red Hat product that ships gvisor-tap-vsock is listed: RHEL 8–10, OpenShift Container Platform 4, Podman Desktop, OpenStack Platform 18, and Edge Manager 1.

The vendor rates this CRITICAL at 9.3 with CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:C/C:N/I:H/A:H. The scope-change (S:C) is warranted — the attack crosses the container/VM-to-host boundary. But 9.3 overstates the real-world risk. The attack vector is adjacent network — you must already have code running inside a container on the target host's podman machine VM. That's post-initial-access. The impact is file deletion only — no data exfiltration (C:N), no arbitrary code execution, and the deleted file is replaced with a socket inode, not attacker-controlled content. gvproxy typically runs rootless, limiting damage to user-owned files. The canonical deployment of podman machine is developer workstations, not production infrastructure. HIGH at 7.1 is the right call.

"Container-to-host file deletion via gvproxy — real isolation bypass, but not the RCE the CVSS implies."
02 · The Attack Path

4 steps from start to impact.

STEP 01

Gain code execution inside a podman machine container or VM

The attacker must first achieve code execution within a container or VM managed by podman machine. This typically happens via a malicious container image (supply-chain attack), a compromised dependency pulled during a build, or exploitation of an application-layer vulnerability inside the container. This step is the primary friction point — the attacker is already post-initial-access.
Conditions required:
  • Target host runs podman machine with gvproxy active
  • Attacker has code execution inside a container or VM on that host
Where this breaks in practice:
  • Requires a prior compromise vector — malicious image, supply-chain attack, or app-layer vuln inside the container
  • Enterprise image registries with signing and scanning reduce the malicious-image vector significantly
Detection/coverage: Container image scanning (Trivy, Grype, Quay Clair) catches known-malicious images. Runtime security tools (Falco, Sysdig Secure) detect anomalous process execution inside containers.
STEP 02

Reach the gvproxy gateway API at 192.168.127.1

From inside the podman machine VM, the gvproxy gateway API is always accessible at 192.168.127.1 (the default gateway). The API listens on the VM-facing network interface with no authentication. Any process inside the VM can reach it via a standard HTTP request. No tooling is needed beyond curl or any HTTP library.
Conditions required:
  • gvproxy is running (always true when podman machine is active)
  • Network path to 192.168.127.1 is open (default configuration)
Where this breaks in practice:
  • None — this is the default, always-reachable gateway
Detection/coverage: Network monitoring inside the VM is uncommon. v0.9.0 adds audit logging for security-relevant API requests, but prior versions do not log these calls.
STEP 03

Send crafted POST to /services/forwarder/expose with traversed path

The attacker sends an HTTP POST to http://192.168.127.1/services/forwarder/expose with a JSON body specifying protocol: "unix" and a local path containing path traversal sequences (e.g., ../../../home/user/.ssh/authorized_keys). No standalone PoC is published, but the exploit is trivially constructable from the fix PR #681 — a single curl command suffices.
Conditions required:
  • gvisor-tap-vsock version < 0.9.0 (no protocol restriction, no path validation)
Where this breaks in practice:
  • The API endpoint and parameter names must be known — documented in the gvisor-tap-vsock source and easily discoverable
Detection/coverage: No detection coverage in versions < 0.9.0. v0.9.0 logs API calls and restricts protocols to tcp/udp by default.
STEP 04

gvproxy deletes the target file and creates a unix socket in its place

gvproxy calls os.Remove(path) on the attacker-supplied path, deleting the file, then calls net.Listen("unix", path) to create a unix socket at the same location. The deleted file is permanently destroyed. The replacement socket inode has no useful content for the attacker — this is a destructive, not a read or arbitrary-write primitive. Damage is limited to files owned by the user running gvproxy (typically the unprivileged desktop user in rootless podman).
Conditions required:
  • Target file exists and is owned by (or writable by) the gvproxy process user
Where this breaks in practice:
  • Rootless podman means gvproxy runs as the unprivileged user — cannot delete root-owned system files
  • Single file per request — mass deletion requires many requests
Detection/coverage: Host-level file integrity monitoring (AIDE, OSSEC, osquery) detects unexpected file deletions or inode-type changes. EDR products with file-system telemetry will log the unlink + bind syscall sequence from gvproxy.
03 · Compensating Control

1
HIGH 7.1→IGNORE 0.0
SEVERITY REDUCED
Patch to gvisor-tap-vsock ≥ 0.9.0 or apply distro backport — The definitive fix. v0.9.0 removes the os.Remove() call before socket creation, restricts the API to tcp/udp protocols by default (blocking unix), and adds optional Bearer token authentication. On RHEL 9.4 EUS, install gvisor-tap-vsock-0.7.3-5.el9_4.3 from RHSA-2026:12033. On Podman Desktop, update to a build that bundles gvisor-tap-vsock ≥ 0.9.0. Per the noisgate remediation SLA for HIGH, deploy within 180 days — but given the simplicity of the fix and low regression risk, prioritize for the next maintenance window.
2
HIGH 7.1→MEDIUM 5.0
SEVERITY REDUCED
Restrict untrusted container images via registry allowlisting and image signing — The attack requires code execution inside a container. If your environment only runs signed images from trusted registries (e.g., Quay with Cosign/Sigstore verification), the attacker's primary entry vector — malicious images — is eliminated. This doesn't protect against application-layer compromise inside legitimate containers, but dramatically reduces the attacker pool. Deploy within 30 days per the noisgate mitigation SLA for HIGH.
3
HIGH 7.1→LOW 2.0
SEVERITY REDUCED
Block container-to-gateway HTTP traffic via iptables rules inside the VM — Add iptables -A OUTPUT -d 192.168.127.1 -p tcp --dport 80 -j DROP inside the podman machine VM to prevent any container from reaching the gvproxy API. This breaks the attack path at step 2 entirely. However, this may interfere with legitimate port-forwarding functionality. Test in dev first. Deploy within 30 days per the noisgate mitigation SLA for HIGH.
4
HIGH 7.1→HIGH 6.5
Deploy file integrity monitoring on developer workstations — Use osquery, AIDE, or EDR file-system telemetry to alert on unexpected deletions of sensitive dotfiles (~/.ssh/*, ~/.kube/config, ~/.bashrc, ~/.gitconfig) or inode-type changes (regular file → socket). This is a detection control, not prevention — it won't stop the attack but ensures you know it happened. Useful as defense-in-depth while patching rolls out.
What doesn't work
  • Host-level firewall (iptables on the host's external interfaces): The gvproxy API traffic flows over vsock or a local Unix socket between the VM and gvproxy, not over host network interfaces. External firewall rules will not intercept it.
  • SELinux / AppArmor on the host: gvproxy itself performs the file deletion using its own security context. The process is allowed to call unlink() on user-owned files by design — there is no policy violation to catch.
  • Container seccomp / AppArmor profiles: These constrain processes *inside* the container. The vulnerable os.Remove() call happens in gvproxy on the *host*, outside the container's security boundary. Hardening the container's own syscall profile does not affect gvproxy.
04 · Intelligence Metadata

The supporting signals.

In-the-wild exploitationNo evidence. Not listed in CISA KEV. No campaigns, no threat actor attribution, no GreyNoise/Shadowserver scanning activity observed. The adjacent-network requirement makes mass exploitation impractical.
Proof-of-concept availabilityNo standalone PoC published. Not indexed on pocindex.io, no GitHub repos named CVE-2026-107935. However, the fix PR #681 by redbeam describes the exploit path in detail — endpoint, parameters, and impact — making weaponization trivial for anyone who reads it. Exploit complexity: one curl command.
EPSS0.00298 (20.7th percentile) — very low predicted exploitation probability, consistent with the adjacent-network constraint and absence of remote attack surface.
KEV statusNot listed as of 2026-10-14.
CVSS vector interpretationCVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:C/C:N/I:H/A:H — S:C reflects the container-to-host boundary crossing. C:N is accurate. AV:A in this context means *inside a container on the same host*, not the LAN. The 9.3 is mathematically correct but inflates real-world risk.
Affected versionsgvisor-tap-vsock ≥ 0.4.0, < 0.9.0 (~3 years of releases). All Red Hat products shipping gvisor-tap-vsock affected: RHEL 8–10, OCP 4, Podman Desktop, OSP 18.0, Edge Manager 1, Dev Spaces.
Fixed versionsUpstream: v0.9.0 (2026-10-08). RHEL 9.4 EUS backport: gvisor-tap-vsock-0.7.3-5.el9_4.3 via RHSA-2026:12033. Ubuntu: needs evaluation as of 2026-10-13.
Scanning / exposureNear-zero internet exposure. gvproxy API listens on 192.168.127.1 — a virtual gateway address inside the podman machine VM. Not bound to any host-external interface. Invisible to Shodan/Censys/FOFA scans. Attack surface is strictly container-local.
Disclosure timelineFix PR #681 opened 2026-10-02 → closed and split → PR #718 (socket cleanup) merged → PR #737 (API restriction) merged → v0.9.0 released 2026-10-08 → CVE published 2026-10-09.
Researcher / reporterDiscovered by Lucas Celant (Red Hat). Fix PRs authored by redbeam and cfergeau. Tracked internally as RHDESK-550.

Sources.

  1. Ubuntu Security – CVE-2026-107935
  2. Red Hat Errata – RHSA-2026:12033
  3. GitHub Fix PR #681 – Prevent arbitrary file deletion (RHDESK-550)
  4. GitHub PR #718 – Rework unix socket cleanup handling
  5. GitHub Release – gvisor-tap-vsock v0.9.0
  6. Strix AI – CVE-2026-107935 Analysis
  7. Tenable Plugin 307643 – RHEL 9 gvisor-tap-vsock
  8. Hol Guard – CVE-2026-107935 Detail
05 · The Call

Final Verdict
↓ DOWNGRADED to HIGH (7.1/10)

Why this verdict

  • Adjacent-network-only attack surface: The CVSS AV:A here means 'inside a container on the target host's podman machine VM,' not 'on the same LAN segment.' The attacker must already have code execution inside a container — this is a post-initial-access primitive, not a first-stage exploit. This is the single largest downward adjustment from the vendor's 9.3.
  • Destructive-only impact, no code execution or data theft: The primitive is file deletion + socket inode replacement. C:N is accurate. The attacker cannot read files, write arbitrary content, or execute code on the host. This caps the blast radius well below what a 9.3 CRITICAL implies.
  • Rootless execution context limits blast radius: gvproxy runs as the unprivileged desktop user in rootless podman. It cannot delete root-owned system files, kernel modules, or other users' data. Damage is limited to the current user's home directory and user-writable paths.
  • Role multiplier: The canonical deployment role for gvproxy/podman machine is developer workstations (macOS, Windows, Linux desktop) — estimated >70% of the installed base. On these hosts, the blast radius is single-user, single-host. gvisor-tap-vsock is *listed* as affected in OpenShift Container Platform 4 and OpenStack Platform 18, but gvproxy is NOT the production networking path in either product (OCP uses CRI-O + OVN-Kubernetes; OpenStack uses libvirt/OVS). gvproxy only runs when podman machine is explicitly started, which is uncommon on production OCP/OSP nodes. CI/CD hosts using podman machine for builds represent the most plausible high-value role (~5–10% of installs); a supply-chain attack inside a build container could delete CI host files, but the blast radius is still single-host, not fleet-scale or domain-scale. No high-value role produces domain takeover, fleet compromise, or supply-chain pivot.
  • Isolation bypass is inherently significant: Despite all friction, this IS a container-to-host boundary violation. Any vulnerability that lets untrusted container workloads affect the host file system crosses a fundamental trust boundary. This prevents downgrading below HIGH.

Why not higher?

CRITICAL would require either remote exploitability (AV:N) or a high-value-role deployment where successful exploitation leads to domain takeover, fleet compromise, or supply-chain pivot. None of these apply. The attack requires prior container compromise (post-initial-access), the impact is file deletion only (no RCE, no data exfiltration), gvproxy runs rootless, and the canonical deployment is developer workstations. The high-value roles where gvisor-tap-vsock is installed (OCP, OSP) don't use gvproxy in production networking paths.

Why not lower?

MEDIUM would understate the significance of a container-to-host isolation bypass. The attack is trivially simple once the attacker is inside a container (one HTTP request, no auth), the scope change is real, and deleting user files like ~/.ssh/authorized_keys, ~/.kube/config, or ~/.bashrc can enable follow-on attacks or cause meaningful disruption. The zero-friction path from container to host file deletion is too clean to dismiss as MEDIUM.

06 · Verification

Crowdsourced verification payload.

Run on any Linux host where podman machine or gvisor-tap-vsock may be installed. Execute as the user who runs podman (no root required). Example: bash check_cve_2026_107935.sh. Checks both RPM/dpkg package versions and running gvproxy binary metadata.

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/usr/bin/env bash
# CVE-2026-107935 Checker — gvisor-tap-vsock path traversal in gvproxy
# Output: VULNERABLE / PATCHED / UNKNOWN
# Requires: no special privileges (runs as the podman user)
set -euo pipefail

FIXED_UPSTREAM="0.9.0"
VERDICT="UNKNOWN"

version_gte() {
  # Returns 0 if $1 >= $2 (semantic version comparison)
  printf '%s\n%s' "$2" "$1" | sort -V -C
}

# Method 1: Check RPM package (RHEL/CentOS/Fedora/Rocky)
if command -v rpm &>/dev/null; then
  PKG_VER=$(rpm -q --queryformat '%{VERSION}-%{RELEASE}' gvisor-tap-vsock 2>/dev/null || true)
  if [[ -n "$PKG_VER" && "$PKG_VER" != *"not installed"* ]]; then
    echo "[*] RPM package found: gvisor-tap-vsock-${PKG_VER}"
    BASE_VER=$(echo "$PKG_VER" | grep -oP '^[0-9]+\.[0-9]+\.[0-9]+')
    if [[ -n "$BASE_VER" ]]; then
      if version_gte "$BASE_VER" "$FIXED_UPSTREAM"; then
        VERDICT="PATCHED"
        echo "[+] Version ${BASE_VER} >= ${FIXED_UPSTREAM}"
      else
        # Check for RHEL backport: 0.7.3-5.el9_4.3 or later
        if echo "$PKG_VER" | grep -qP '0\.7\.3-[5-9].*\.el9.*\.[3-9]'; then
          VERDICT="PATCHED"
          echo "[+] RHEL backport detected: ${PKG_VER}"
        else
          VERDICT="VULNERABLE"
          echo "[-] Version ${BASE_VER} < ${FIXED_UPSTREAM}"
        fi
      fi
    fi
  else
    echo "[*] gvisor-tap-vsock RPM not installed"
  fi
fi

# Method 2: Check dpkg (Ubuntu/Debian)
if [[ "$VERDICT" == "UNKNOWN" ]] && command -v dpkg &>/dev/null; then
  DEB_VER=$(dpkg -s golang-github-containers-gvisor-tap-vsocks 2>/dev/null | grep '^Version:' | awk '{print $2}' || true)
  if [[ -n "$DEB_VER" ]]; then
    echo "[*] Debian package found: ${DEB_VER}"
    BASE_VER=$(echo "$DEB_VER" | grep -oP '^[0-9]+\.[0-9]+\.[0-9]+')
    if [[ -n "$BASE_VER" ]]; then
      if version_gte "$BASE_VER" "$FIXED_UPSTREAM"; then
        VERDICT="PATCHED"
      else
        VERDICT="VULNERABLE"
      fi
    fi
  fi
fi

# Method 3: Check running gvproxy process
if pgrep -x gvproxy &>/dev/null; then
  GVPROXY_PID=$(pgrep -x gvproxy | head -1)
  GVPROXY_BIN=$(readlink -f /proc/"${GVPROXY_PID}"/exe 2>/dev/null || true)
  echo "[*] gvproxy is running (PID ${GVPROXY_PID})"
  if [[ -n "$GVPROXY_BIN" ]]; then
    echo "[*] Binary: ${GVPROXY_BIN}"
    EMBEDDED_VER=$(strings "$GVPROXY_BIN" 2>/dev/null | grep -oP 'gvisor-tap-vsock/v\K[0-9]+\.[0-9]+\.[0-9]+' | head -1 || true)
    if [[ -n "$EMBEDDED_VER" ]]; then
      echo "[*] Embedded version: ${EMBEDDED_VER}"
      if version_gte "$EMBEDDED_VER" "$FIXED_UPSTREAM"; then
        VERDICT="PATCHED"
      else
        VERDICT="VULNERABLE"
      fi
    fi
  fi
  if [[ "$VERDICT" == "UNKNOWN" ]]; then
    echo "[!] gvproxy is running but version could not be determined"
  fi
else
  echo "[*] gvproxy is not currently running"
fi

echo ""
echo "=== RESULT: ${VERDICT} ==="
case "$VERDICT" in
  VULNERABLE) echo "Action: Update gvisor-tap-vsock to >= ${FIXED_UPSTREAM} or apply distro backport."; exit 1 ;;
  PATCHED)    echo "No action required for CVE-2026-107935."; exit 0 ;;
  *)          echo "Could not determine status. Manually verify gvisor-tap-vsock version."; echo "If podman machine is not used, this host is not affected."; exit 2 ;;
esac