hostPath Mounts: The docker.sock Escape Hatch
A hostPath volume mapping /var/run/docker.sock into a pod grants effective node root regardless of container privilege settings. CI runners and monitoring DaemonSets ship this by default while PSA restricted sits unenforced, letting one compromised build job chroot onto the host, steal the kubelet certificate, and reach cluster-admin-equivalent access across every namespace on that node.
Operational summary
At a glance
- Symptom
- Compromised build job or DaemonSet writes to mounted docker.sock to spawn a privileged container
- Likely cause
- hostPath volume mounting /var/run/docker.sock with unenforced Pod Security Admission profile
- Impact
- Node-wide root access, stolen kubelet credentials, cloud IAM metadata, and every pod's service account tokens on that node.
- Verification signal
- Re-run the detection test and a controlled negative-path test.
- Safe correction
- Enforce PSA restricted on build namespaces, block docker.sock hostPath via Kyverno, use kaniko or rootless BuildKit instead.
- Rollback or recovery
- Restore the exported configuration if the new control blocks required production traffic, then narrow the policy before redeployment.
The Trap
A hostPath volume that maps /var/run/docker.sock into a pod. This turns up in CI runner charts (GitLab Runner, Jenkins agent), monitoring DaemonSets that shell out to Docker for metadata, and DinD-based build jobs that need to spin sibling containers without paying the nested-daemon tax.
The Default State
Helm values for these charts ship with volumes: hostPath: path: /var/run/docker.sock and type: "", meaning no path-type validation runs at admission time. The container itself often sets privileged: false, so it looks safe on a security scan. Pod Security Admission, if labelled at all, is frequently left at the privileged profile or unlabelled entirely, because teams disabled the old PodSecurityPolicy during the 1.25 migration and never replaced it. Baseline and restricted PSA profiles explicitly forbid hostPath volumes, but nobody enforces that on the namespace where the runner lives.
The Blast Radius
Socket access is functionally root on the node, regardless of the container’s own capability set. Any process that can write to that socket can run docker run -v /:/host --privileged alpine chroot /host, which lands a shell in the host filesystem. From there it reads the kubelet’s client certificate and kubeconfig under /var/lib/kubelet, pulls the cloud instance metadata endpoint at 169.254.169.254 for the node’s IAM role, and harvests every other pod’s projected service account token sitting in /var/lib/kubelet/pods/*/volumes/kubernetes.io~projected. One compromised build job now has cluster-admin-equivalent reach across every namespace scheduled on that node, and because the daemon is shared, it can spin containers on behalf of any workload the node hosts, not just the one that leaked the credential.
The Lead Mechanic Fix
Enforce PSA restricted on any namespace running build or agent workloads: kubectl label ns ci pod-security.kubernetes.io/enforce=restricted --overwrite. Restricted rejects hostPath volumes outright. Back that with an explicit deny for anyone tempted to relax the label, using a Kyverno ClusterPolicy with a validate rule matching spec.volumes[].hostPath.path against /var/run/docker.sock and /var/lib/docker, set to failureAction: Enforce. Replace DinD build steps with kaniko or rootless BuildKit, which build OCI images without a daemon socket at all. Audit existing exposure with kubectl get pods -A -o json | jq '.items[] | select(.spec.volumes[]?.hostPath.path=="/var/run/docker.sock")' and rotate any node that shows a hit, since the kubelet certificate on that node must be treated as burned.
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.
Fix commands and configuration
kubectl label ns ci pod-security.kubernetes.io/enforce=restricted --overwritespec.volumes[].hostPath.path/var/run/docker.sockVerify, 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.