Skip to content

Podman kube play symlink host-write boundary (GHSA-wp3j-xq48-xpjw)

Source: GitHub Security Advisories updated 2026-05-19.

Signal

GHSA-wp3j-xq48-xpjw / CVE-2025-9566 describes a high-severity Podman kube play flaw: when kube play uses ConfigMap or Secret volume mounts and the same volume is started more than once, a container can plant a symlink during the first run. Later kube play runs may follow that symlink while writing ConfigMap/Secret data, overwriting a host file path chosen by the attacker. The attacker controls the target path, while the bytes written come from the operator-supplied YAML.

Affected ranges listed by GitHub:

  • github.com/containers/podman/v5 <= 5.6.0; fixed in 5.6.1.
  • github.com/containers/podman/v4 <= 4.9.5; no first patched v4 version listed in the advisory.

Why it matters

Container orchestration helpers often treat ConfigMaps, Secrets, and existing volumes as administrative plumbing. This bug is durable because it crosses three boundaries at once: untrusted container filesystem state, operator-supplied Kubernetes YAML, and host filesystem writes. A local or workload-level actor does not need to choose the file contents to cause damage; forcing trusted Secret or ConfigMap content into a sensitive host path can still break service integrity, corrupt config, or create an availability incident.

Triage

  1. Inventory systems where Podman kube play runs Kubernetes YAML with ConfigMap or Secret volume mounts, especially recurring jobs, lab automation, CI runners, and developer workstations.
  2. Upgrade Podman v5 deployments to 5.6.1 or later. Treat v4 deployments as requiring vendor/backport confirmation or workflow removal until fixed packages are verified.
  3. Avoid podman kube play with ConfigMap or Secret volume mounts on untrusted or reused volumes until patched.
  4. Inspect reused Podman volumes touched by untrusted containers for symlinks and hardlinks before replaying YAML.
  5. Hunt for unexpected host file mtimes or contents after repeated kube play starts, especially files plausibly targeted by symlink paths such as service configs, authorized keys, cron/systemd fragments, app config, or writable host paths.

Defensive pattern

  • Treat volumes reused across container starts as attacker-controlled state, not as a clean deployment target.
  • Before writing ConfigMap, Secret, archive, or copy payloads into a volume, resolve the final path from a trusted directory descriptor and reject symlinks, hardlinks, device files, absolute paths, and parent traversal.
  • Prefer fresh, private deployment volumes for each untrusted run; if reuse is required, scrub or recreate them from trusted state.
  • Keep orchestration helpers least-privileged: avoid running container-to-host file population paths with broader host write permission than needed.

October 9 follow-up: gvproxy unauthenticated expose endpoint deletes host files (GHSA-hp8g-9vjx-j62m / CVE-2026-107935, critical, CVSS 9.3)

gvproxy — the network forwarder in containers/gvisor-tap-vsock that backs Podman Machine, podman machine, Red Hat Desktop/CRC-style VM runners — exposed an unauthenticated /services/forwarder/expose endpoint that takes a caller-supplied socket path and calls os.Remove(socketPath) before net.Listen("unix", …) with no path validation (fix PR #718, merged 2026-09-29: all os.Remove pre-listen cleanup calls deleted and replaced by close-on-exit). Anyone who can reach the forwarder's control API can delete arbitrary files on the host running gvproxy — anyone, because the whole purpose of the component is bridging the untrusted guest VM to the host network stack. Third container-tooling host-boundary leg this quarter after this page's kube play symlink write and the June 5 Netavark DNS-confusion page: same product family, same re-sweep rule.

Operator reading:

  • Destructive-sink-from-unvalidated-path pattern: the pre-delete-before-listen idiom (os.Remove(path); net.Listen(path)) appears across socket/lock/pid handlers. Grepping any local HTTP control plane for os.Remove/os.RemoveAll/unlink fed from a request field finds standing file-deletion primitives; the path never needs to be the file you want to read — deleting unit files, sockets, or lock files is the impact.
  • Unauthenticated local control-plane inventory: gvproxy's forwarder API has no auth at all. Per the July 8 browser-to-loopback methodology (and the DeepSeek Harness Host-gate leg folded there), enumerate what each container-network helper (gvproxy, podman machine, kind, minikube, WSL relay) exposes on vsock/tcp from guest reachability, then map which endpoints mutate host state. A forwarder that can open ports is also, by design, an SSRF/pivot helper — test its admin verbs, not just its forwarding verbs.
  • Validation shape: prove only with a disposable marker file outside any real path (point expose at a temp canary socket path you pre-create, observe deletion), never against a shared machine's sockets or unit files.

Cross-reference: pre-listen os.Remove is the same "cleanup step trusts caller input" genealogy as the shared-temp lz4-java hijack (April 30 page) — one deletes, one reuses; both are local-IPC control-plane paths most scans never touch because the listener isn't on a "real" port.

References