Last updated: September 2026
Yes, an attacker with root on a Kubernetes node can obtain SPIFFE/SPIRE workload identities that do not belong to them. Unit 42 published the technique on September 10, 2026, and it is real: by faking the Linux cgroup metadata that the SPIRE agent reads during workload attestation, a root process can get the SPIRE agent to hand it a valid, short-lived SVID for a different workload running on the same node. That said, this is a post-exploitation move, not a break of SPIFFE’s cryptography, and it sits inside the trust model the SPIFFE project has documented for years: the node is a trust boundary, and once root on a node is gone, every identity scoped to that node is gone with it.
The short version:
- The target is SPIRE’s Kubernetes workload attestor, which identifies a calling process by parsing its cgroup path. That path is attacker-controllable if you have root.
- The blast radius is workloads co-located on the compromised node, not the whole cluster and not the SPIFFE trust domain’s private keys.
- It is not a CVE and not a novel protocol flaw. It is a demonstration of a known assumption most teams underestimate.
- The right response is node hardening, tighter co-location, and monitoring, the same controls that already limit a compromised-node blast radius in Kubernetes.
What Unit 42 actually demonstrated
The research is titled “The Machine With Many Faces: Post-Exploitation Identity Misuse in SPIFFE/SPIRE,” published by Unit 42 (Palo Alto Networks) in September 2026, with a companion open-source tool called Spooffe. The setup is a standard SPIRE deployment on Kubernetes, where SPIRE replaces long-lived secrets with short-lived cryptographic workload identities (SVIDs).
The claim is narrow and worth stating precisely. With root on a node running a SPIRE agent, an attacker can:
- Impersonate a co-located workload by spoofing the cgroup metadata SPIRE uses to identify it, then asking the local SPIRE agent for that workload’s SVID.
- Impersonate the SPIRE agent itself by pulling the agent’s key material out of process memory and talking to the SPIRE server directly.
Unit 42 states it has “not observed this technique exploited in the wild.” Nothing here lets a remote, unprivileged attacker mint identities. You need root on the box first.
How SPIRE workload attestation works, and why cgroups are the weak link
When a workload calls the SPIRE agent’s Workload API over a Unix domain socket, the agent has to answer one question: which workload is this, really? It cannot ask the caller, because a caller can lie. So SPIRE attests the caller using signals it reads from the operating system.
The Kubernetes workload attestor does this by taking the caller’s PID and reading /proc/<pid>/cgroup (or /proc/<pid>/mountinfo). A pod’s cgroup path on a modern node looks like this:
0::/kubepods.slice/kubepods-besteffort.slice/kubepods-besteffort-pod<pod_uid>.slice/cri-containerd-<container_id>.scope
SPIRE extracts the pod UID and container ID from that string, then queries the kubelet to look up the pod and produce selectors: the namespace, service account, pod name, container image, and so on. Registration entries in the SPIRE server say “a workload matching these selectors is allowed to have this SPIFFE ID,” and the agent issues the SVID when the selectors match.
Here is the part that matters. The attestor trusts the cgroup path as a truthful statement of identity, and it does very little to confirm the path is genuine. The SPIRE source is candid about this in a code comment on the container locator: the agent used to verify that the pod and container IDs were descendants of a real kubepods hierarchy, but “as of Kubernetes 1.21, cgroups namespaces are in use,” so the regex “has been relaxed to simply find the pod UID followed by the container ID.” In other words, the attestor scans for a pod-UID-shaped and container-ID-shaped substring. It does not prove the process is actually a member of that pod’s real cgroup.
That relaxation was a legitimate compatibility fix for cgroup namespaces. It also means the input SPIRE trusts is a string that root can write.
The cgroup spoof, step by step
The attack, as Unit 42 describes it, is short. On a node where you have root:
-
Pick a target workload, read its cgroup path, and note the pod UID and container ID.
-
Create a mock cgroup directory whose path mimics the target’s:
sudo mkdir -p /sys/fs/cgroup/kubepods-besteffort.slice.FAKE/kubepods-besteffort-pod[UID].slice/cri-containerd-[ID].scope -
Move your own process into that mock cgroup by writing its PID into
cgroup.procs:sudo echo $$ | sudo tee /sys/fs/cgroup/kubepods-besteffort.slice.FAKE/kubepods-besteffort-pod[UID].slice/cri-containerd-[ID].scope/cgroup.procs -
Call the SPIRE agent’s Workload API. It reads your process’s cgroup, sees the target’s pod UID and container ID, resolves the target’s selectors against the kubelet, matches a registration entry, and issues you the target’s SVID.
Unit 42 notes you do not even need the separate mock path: “writing the PID directly into the original cgroup path would have also worked. We used a separate cgroup only to avoid modifying the original workload’s runtime state.” The separate directory is a courtesy to keep the real workload running normally while you impersonate it.
The Spooffe tool automates the whole loop: it scans the node for running workloads, discovers their cgroup paths, replicates each as a mock cgroup for its own process, and queries the local agent to collect every SVID it can reproduce. The practical outcome is that a root process on the node can enumerate and obtain the identities of the workloads sharing that node.
Agent impersonation, the second mode
The cgroup spoof gets you individual workload SVIDs. Spooffe’s second mode goes after the SPIRE agent’s own identity. It dumps the agent’s private key from process memory (dump agentkey), then uses that key material to authenticate to the SPIRE server directly with --client-cert, --client-key, and --ca-cert. From there it can reach the server-side APIs the agent is entitled to, including listing entries and minting SVIDs for that agent’s scope.
There is a real limit here that the tool’s own documentation calls out. If the legitimate agent is still running, its normal certificate rotation creates a serial-number race, and a stolen agent SVID becomes unusable within minutes. Agent impersonation is most useful in a window where the real agent is down or being replaced, not as a durable foothold.
Is this a SPIFFE/SPIRE vulnerability?
Not in the usual sense, and it is worth being honest about that instead of dressing it up. There is no CVE, no forged signature, and no way to do this without already owning the node.
The SPIFFE project has said for years that workload attestation trusts the local node. The 2020 “Scrutinizing SPIRE Security” analysis (Moyer, Cappos, Gilman, Schiattarella) states plainly that the agent attests workloads using “locally-trusted workload attributes such as process/group ID or container runtime metadata” that “are read from the kernel or other trusted components on the local system,” and that node attestation is deliberately outside the scope of workload attestation. The SPIFFE/SPIRE security self-assessment makes the same point from the other direction, noting that by default the agent does not even verify the kubelet’s identity unless you set skip_kubelet_verification to false.
So the accurate framing is this: the cryptography and the protocol are doing what they claim. What Unit 42 demonstrated is that the trust anchor for workload attestation on a shared node is the node’s kernel, and if you own the kernel you own the identities. Unit 42’s own conclusion is the sober version: “organizations should assume that root-level access to a node grants access to all cryptographic identities scoped to it.”
Where the popular “zero trust” framing gets people into trouble is the implication that the system trusts nothing. It does trust something. It trusts the node it runs on to tell the truth about the processes on it. That is a reasonable design, but it is a trust relationship, and shared-tenancy nodes are where it gets tested.
How bad is it, really?
Bad enough to design around, not a five-alarm fire. Two points put it in proportion.
First, root on a node already exposes that node’s secrets by other means. A root attacker can read the service account token mounted for any pod on the node at /var/run/secrets/kubernetes.io/serviceaccount/token, read mounted Kubernetes Secrets, and inspect memory. The SPIFFE spoof is a cleaner way to obtain the same class of thing (a co-located workload’s identity), and the resulting SVID is a first-class cryptographic identity that peers accept across the mesh, which is what makes lateral movement tidy. It is not, however, granting access that a determined root attacker could not otherwise assemble for that node’s workloads.
Second, Kubernetes already ships the control that bounds this: the Node authorizer plus the NodeRestriction admission plugin limit a kubelet to reading Secrets, ConfigMaps, and volumes “related to pods bound to the kubelet’s node,” and to modifying only its own Node object and pods bound to it. With ServiceAccountNodeAudienceRestriction enabled, the Kubernetes docs note this “prevents a compromised node from obtaining tokens for arbitrary audiences.” The whole model assumes node compromise is contained to that node. SPIFFE/SPIRE should be threat-modeled the same way, and the Unit 42 work is a good prompt to actually do it.
Does this affect Istio and Linkerd too?
Unit 42’s write-up is specifically about SPIRE’s cgroup-based Kubernetes attestor, and it does not test service meshes. But the underlying principle generalizes, so it is worth reasoning through honestly.
Istio and Linkerd do not use cgroup attestation. In Istio, the istio-agent generates a key and CSR and sends it to istiod “with its credentials,” and istiod’s CA validates that credential before signing (per Istio’s security concepts documentation). In Linkerd, the proxy presents the pod’s Kubernetes ServiceAccount token to the identity component, which validates it before issuing a 24-hour certificate (per Linkerd’s automatic mTLS docs). That is a different, stronger attestation input than a cgroup path.
It is stronger, but it is not immune to the same root-on-node reality. The ServiceAccount token those meshes rely on lives on the node’s filesystem, and root can read any co-located pod’s token and request that pod’s certificate. Different mechanism, same conclusion: a hostile node can obtain the identities of the workloads it hosts. If you run SPIRE, Istio, or Linkerd, the node is in your trust boundary either way.
This is also a good moment to keep two different things separate. SPIFFE/SPIRE is about workload identity, the identity of a process or service. That is a distinct problem from user and application identity, which is what an identity provider like Keycloak handles, and from the machine-to-machine client credentials a service uses to call an API, which you can read about in our guide on machine-to-machine authentication with Keycloak. A workload can hold both a SPIFFE SVID for mesh mTLS and an OAuth token for a downstream API, attested and issued by completely different systems.
What to actually do about it
Nothing here calls for ripping out SPIFFE/SPIRE. It calls for treating the node as what it is.
- Harden the node and keep root scarce. Restrict who and what can gain root, block privileged containers and host mounts where you can, and treat any node-level RCE as an identity incident, not just a host incident. This is the primary control.
- Reduce co-location of high-value identities. The spoof only reaches workloads on the same node. Node pools, taints, and scheduling that keep sensitive workloads off shared best-effort nodes shrink what a single compromised node can impersonate.
- Use selectors that are hard to reproduce. The Kubernetes attestor can key on container image digests rather than tags, which are harder to forge than a namespace or pod name, though a determined root attacker on the node is still a root attacker. Prefer digest-based image selectors and avoid registration entries that match broadly.
- Turn on the Kubernetes controls that bound node compromise.
NodeRestriction, and where applicableServiceAccountNodeAudienceRestriction, are the analogous blast-radius limits for the service-account tokens sitting on the same nodes. - Monitor for the tell. Run Spooffe yourself as a validation exercise. Watch for unexpected cgroup creation under
/sys/fs/cgroup, processes writing tocgroup.procsfor pods they do not belong to, and SVID issuance patterns that do not line up with real workload placement. - Keep SVIDs short-lived and rotation aggressive. Short TTLs are already SPIRE’s default posture, and they are what turned the stolen-agent path into a minutes-long window rather than a durable one.
If you are running identity infrastructure on Kubernetes and want the broader hardening picture, our Keycloak on Kubernetes production deployment guide and the Keycloak security hardening checklist cover the node and cluster fundamentals that apply here regardless of which identity system you run.
Frequently asked questions
Is there a CVE for the SPIFFE/SPIRE cgroup spoofing issue?
No. Unit 42 published it as a post-exploitation research technique, not a vulnerability disclosure with a CVE. It requires root on the node and does not defeat SPIFFE’s cryptography, so it is a threat-model observation rather than a software flaw to patch.
Can a remote attacker exploit this without node access?
No. The technique requires root on a Kubernetes node running a SPIRE agent. A remote or unprivileged attacker cannot mint or steal SVIDs with it. Unit 42 also reports no in-the-wild exploitation.
Does this mean SPIFFE/SPIRE is insecure?
No. It means workload attestation on a shared node trusts the node’s kernel, which the SPIFFE project has documented since at least 2020. If the node is honest, the guarantees hold. The correct takeaway is to treat node compromise as compromise of every identity scoped to that node.
How is workload identity different from user identity?
Workload identity (SPIFFE/SPIRE) identifies a running process or service to other services, usually for mTLS. User and application identity is what an OAuth or OIDC provider like Keycloak issues for people and clients. They operate at different layers and a single service often holds both.
What is the single most effective mitigation?
Node hardening. Because the entire attack depends on root on the node, the controls that make node compromise rarer and more contained (restricting root, blocking privileged containers, NodeRestriction, careful workload placement) do the most to limit exposure.
Key takeaways
The Unit 42 research is a useful reality check, not a reason to abandon workload identity. A root-compromised Kubernetes node can spoof the cgroup metadata SPIRE reads and obtain SVIDs for co-located workloads, and it can dump the agent key for a short-lived server impersonation. This is contained to the compromised node, it is not a crypto or protocol break, and it matches a trust assumption SPIFFE has always documented. Design for it the way you already design for node compromise in Kubernetes: keep root scarce, keep sensitive workloads off shared nodes, use hard-to-forge selectors, and monitor the node for the signs.
Skycloak runs managed Keycloak, which is identity management for your users and applications rather than workload identity for your mesh. If that is the layer you are working on, start a free trial or talk to us.
Primary source: Unit 42 (Palo Alto Networks), “The Machine With Many Faces: Post-Exploitation Identity Misuse in SPIFFE/SPIRE,” September 2026, and the accompanying Spooffe tool. Background: the SPIFFE project’s “Scrutinizing SPIRE Security” (2020) and the SPIFFE/SPIRE security self-assessment.