Skip to main content
cd ../config-traps
risk/register/hostpath-policy-prefix-checks-miss-the-run-symlink.html
Kubernetes Volume Securitycritical severityKubernetes

hostPath Policy Prefix Checks Miss the /run Symlink

Severity
critical
Reviewed
20 Jul 2026
Remediation
~20 minutes
Overview

An admission policy written against /var/run/docker.sock does nothing if the node's /var/run is a symlink to /run, because a pod can mount /run/docker.sock directly and the same socket becomes reachable under a path string the policy never inspected. Namespace-scoped exemptions and standard RBAC reviews will not catch this on Kubernetes nodes running systemd-based distributions.

Operational summary

At a glance

Symptom
A pod mounts hostPath.path: /run/docker.sock, bypassing a policy written against /var/run/docker.sock, and gains the container runtime socket unchecked.
Likely cause
Admission policy allowedHostPaths matches only the literal /var/run/docker.sock string without resolving the /var/run to /run symlink.
Impact
The pod obtains root-equivalent access to the node runtime, reads every co-located pod's secrets, and pivots across the entire node.
Verification signal
Re-run the detection test and a controlled negative-path test.
Safe correction
Enumerate all canonical path aliases in policy or, preferably, block hostPath volumes entirely via the restricted PodSecurity Standard.
Rollback or recovery
Restore the exported configuration if the new control blocks required production traffic, then narrow the policy before redeployment.

The Trap

Host path prefix matching that treats /var/run and /run as unrelated strings. Most systemd-managed Linux distributions ship /var/run as a symbolic link to /run, created by tmpfiles.d at boot. Kernel-level path resolution treats /var/run/docker.sock and /run/docker.sock as the identical inode, but a Kubernetes admission controller performing string-prefix comparison on volumes[].hostPath.path sees two unrelated values. Any policy authored solely against /var/run/docker.sock leaves /run/docker.sock, and by extension /run/containerd/containerd.sock, entirely unchecked.

The Default State

Kyverno’s community restrict-host-path-mount policy, and most hand-rolled OPA Gatekeeper ConstraintTemplates, ship with an allowedHostPaths pathPrefix list containing literal strings such as /var/run/secrets or /var/run/docker.sock. Neither Kyverno nor Gatekeeper resolves symlinks before evaluating the pattern; the JMESPath or rego comparison operates on the raw string supplied in the PodSpec. kubelet itself performs no canonicalisation either, so a container requesting hostPath.path: /run/docker.sock is admitted and bind-mounted exactly as written, regardless of what the same file is called elsewhere on disk.

The Blast Radius

A pod that passes every existing hostPath guardrail mounts /run/docker.sock, obtains a working Docker Engine API socket, and issues a privileged container create against the host runtime. From there the attacker gains root on the node, reads kubelet’s client certificate and any other pod’s secrets mounted on that node, and pivots laterally through every workload co-located on the same host. Security teams who audited their cluster and confirmed docker.sock was blocked under /var/run remain unaware that the exact same capability was reachable one directory alias away, and standard policy-as-code test suites that only assert against the documented path never exercise the bypass.

The Lead Mechanic Fix

Enumerate every canonical alias explicitly rather than trusting a single prefix. In Kyverno, replace a single pathPrefix entry with an anyPattern block listing both forms:

spec.validationFailureAction: Enforce, with rule.validate.anyPattern covering path: “/var/run/docker.sock” and path: “/run/docker.sock”, plus the equivalent pair for containerd.sock and crictl’s runtime endpoint. Better still, remove hostPath as an option entirely by setting pod-security.kubernetes.io/enforce: restricted at namespace level, since the restricted PodSecurity Standard rejects the hostPath volume type outright rather than trying to enumerate forbidden paths. Where a workload genuinely needs runtime introspection, replace the raw socket mount with a scoped CSI ephemeral volume or a sidecar exposed via a Unix domain socket proxy that enforces its own authorisation, so no policy has to keep pace with the node’s filesystem layout.

03

Apply the safer control

Before you change production

Confirm the affected scope, export the current configuration, and test the replacement control in a non-production environment first.

Control to implement

Enumerate all canonical path aliases in policy or, preferably, block hostPath volumes entirely via the restricted PodSecurity Standard.

Validate the vendor-specific syntax in official documentation before applying it.

04

Verify, roll back or escalate

Verify

Re-run the detection test and a controlled negative-path test. Confirm the unsafe behaviour is blocked while approved traffic still succeeds.

Rollback

Restore the exported configuration if the new control blocks required production traffic, then narrow the policy before redeployment.

Escalate

Escalate when the blast radius is uncertain, the control cannot be tested safely, or remediation requires an outage or security exception.

After remediation

Further reading stays below the corrective workflow and is selected by platform, category and shared technical keywords.

Discover more

Connected KBY resources