CRITICAL
ServiceAccount/csr-fixtures/sa-csr-mint
→
the system:masters group
score 9.4
1 hop
View finding →
ServiceAccount `sa-csr-mint` in namespace `csr-fixtures` reaches the system:masters group in 1 hop via CSR self-approval: forging a cluster identity.
CSR self-approval: forging a cluster identity csr_approve
The combination of create on certificatesigningrequests AND update/patch on certificatesigningrequests/approval at cluster scope lets the holder have the cluster CA sign an x509 client cert carrying any Subject DN they choose. The apiserver maps the certificate's CN onto the username it authorizes and each O onto a group, for any cert signed by a CA in --client-ca-file. It never checks whether that identity is one Kubernetes would have issued — so CN=system:serviceaccount:kube-system:<sa> authenticates as that ServiceAccount even though Kubernetes itself never issues certificates to ServiceAccounts.
Pick the claim carefully. O=system:masters is the famous version and the one modern clusters block: CertificateSubjectRestriction (default-on since 1.19) rejects that Organization for the kubernetes.io/kube-apiserver-client signer. The Common Name is unrestricted, so the route that works is claiming an existing privileged identity — a kube-system ServiceAccount such as clusterrole-aggregation-controller, or a control-plane user like system:kube-controller-manager.
Note the second gate on the approval side: since 1.19 the CertificateApproval admission plugin also requires the approver to hold the approve verb on the CSR's signers resource. A subject with only the two CSR verbs has a latent escalation that goes live the moment the signer verb is added or the plugin is disabled.
This is a permanent backdoor primitive: cert validity is whatever the signer applies (often a year), Kubernetes has no revocation list, and removing the RBAC grant does not invalidate an issued cert — only a CA rotation does.
From ServiceAccount/csr-fixtures/sa-csr-mint
Permission granted create certificatesigningrequests + update certificatesigningrequests/approval
Gives the attacker can submit a CSR claiming a privileged identity (a kube-system ServiceAccount CN, or system:masters where CertificateSubjectRestriction is off) and self-approve it, minting a CA-signed client cert
CRITICAL
ServiceAccount/rbac-fixtures/sa-impersonate
→
the system:masters group
score 9.4
1 hop
View finding →
ServiceAccount `sa-impersonate` in namespace `rbac-fixtures` reaches the system:masters group in 1 hop via Impersonation of system:masters.
Impersonation of system:masters impersonate_system_masters
The impersonate verb on groups with no resourceNames (or with resourceNames that list system:masters) lets the holder send requests as the hard-coded system:masters group. The kube-apiserver short-circuits authorization for that group, so every API call succeeds regardless of RBAC.
This is the worst-case impersonation grant: it bypasses the cluster's entire RBAC layer rather than borrowing another principal's permissions.
From ServiceAccount/rbac-fixtures/sa-impersonate
Permission granted impersonate groups
Gives the attacker can impersonate the system:masters group, bypassing all RBAC
Survives cutting the crb-impersonate binding (2 hops)
This route reaches the same target without the crb-impersonate binding, so removing this subject from that binding alone does not close it. The Remediation for this finding may name a broader fix that closes both.
Step 1 of 2 Steal node IAM role via IMDS imds_node_role_pivot
EC2-backed EKS worker nodes attach an IAM role to the instance and expose its credentials at the link-local IMDS endpoint 169.254.169.254. Pods inherit the host's network unless a NetworkPolicy denies egress to that IP, so a compromised pod can curl IMDS, parse out the node-role credentials, and act in AWS as the node.
The node role is typically broader than any single workload's IRSA role: it can pull from ECR, describe EC2 instances, and is often given additional grants for cluster-autoscaler / EBS-CSI / external-dns. This is a credential-theft chain (SSRF to cloud creds) rather than a Kubernetes RBAC chain.
From ServiceAccount/rbac-fixtures/sa-impersonate
Permission granted IMDS reachable, IRSA unbound
Gives the attacker pod rbac-fixtures/imp-app-5f78d6bb9d-bxmxv falls back to node IAM role via IMDS
Step 2 of 2 Control-plane PKI theft control_plane_pki_theft
Root on a node is serious anywhere, but root on a control-plane node is game over. The cluster's certificate authority private key sits at /etc/kubernetes/pki/ca.key. With it an attacker signs a client certificate carrying O=system:masters entirely offline, and the API server accepts it because that group short-circuits authorization.
No RBAC object changes, so no audit event records the grant. Recovery means rotating the cluster CA, not merely deleting a binding.
From ServiceAccount/rbac-fixtures/sa-impersonate
Permission granted root on a schedulable control-plane node
Gives the attacker can read /etc/kubernetes/pki/ca.key and forge an O=system:masters client certificate offline
CRITICAL
ServiceAccount/rbac-fixtures/sa-token-create
→
the system:masters group
score 9.3
2 hops
View finding →
ServiceAccount `sa-token-create` in namespace `rbac-fixtures` reaches the system:masters group in 2 hops via TokenRequest minting → CSR self-approval: forging a cluster identity.
Step 1 of 2 TokenRequest minting token_request
The create verb on serviceaccounts/token mints a fresh, valid token for any ServiceAccount in scope, with no pod required. Cleaner than the pod-creation route and harder to spot in audit logs.
From ServiceAccount/rbac-fixtures/sa-token-create → ServiceAccount/csr-fixtures/sa-csr-mint
Permission granted create serviceaccounts/token
Gives the attacker can mint tokens for ServiceAccount csr-fixtures/sa-csr-mint
Step 2 of 2 CSR self-approval: forging a cluster identity csr_approve
The combination of create on certificatesigningrequests AND update/patch on certificatesigningrequests/approval at cluster scope lets the holder have the cluster CA sign an x509 client cert carrying any Subject DN they choose. The apiserver maps the certificate's CN onto the username it authorizes and each O onto a group, for any cert signed by a CA in --client-ca-file. It never checks whether that identity is one Kubernetes would have issued — so CN=system:serviceaccount:kube-system:<sa> authenticates as that ServiceAccount even though Kubernetes itself never issues certificates to ServiceAccounts.
Pick the claim carefully. O=system:masters is the famous version and the one modern clusters block: CertificateSubjectRestriction (default-on since 1.19) rejects that Organization for the kubernetes.io/kube-apiserver-client signer. The Common Name is unrestricted, so the route that works is claiming an existing privileged identity — a kube-system ServiceAccount such as clusterrole-aggregation-controller, or a control-plane user like system:kube-controller-manager.
Note the second gate on the approval side: since 1.19 the CertificateApproval admission plugin also requires the approver to hold the approve verb on the CSR's signers resource. A subject with only the two CSR verbs has a latent escalation that goes live the moment the signer verb is added or the plugin is disabled.
This is a permanent backdoor primitive: cert validity is whatever the signer applies (often a year), Kubernetes has no revocation list, and removing the RBAC grant does not invalidate an issued cert — only a CA rotation does.
From ServiceAccount/csr-fixtures/sa-csr-mint
Permission granted create certificatesigningrequests + update certificatesigningrequests/approval
Gives the attacker can submit a CSR claiming a privileged identity (a kube-system ServiceAccount CN, or system:masters where CertificateSubjectRestriction is off) and self-approve it, minting a CA-signed client cert
CRITICAL
ServiceAccount/nodeid-fixtures/nodeid-joiner
→
the system:masters group
score 9.2
3 hops
View finding →
ServiceAccount `nodeid-joiner` in namespace `nodeid-fixtures` reaches the system:masters group in 3 hops via Kubelet CSR auto-approval: a node identity for any name → Node authorizer: token request for a node's pods → CSR self-approval: forging a cluster identity.
Step 1 of 3 Kubelet CSR auto-approval: a node identity for any name csr_nodeclient_autoapprove
Kubelets get their client certificates by submitting a CertificateSigningRequest that names system:node:<name> in the group system:nodes. The controller manager approves such a request by itself when a SubjectAccessReview says the requester may create certificatesigningrequests/nodeclient. It does not compare the node name to the requester, nor check that the node exists.
Whoever holds that subresource together with create certificatesigningrequests therefore gets a signed kubelet identity for any node name, and the Node authorizer grants that identity the ServiceAccount tokens and referenced Secrets of every pod on the named node. kubeadm binds the pair to its bootstrap group, which is the designed use.
From ServiceAccount/nodeid-fixtures/nodeid-joiner
Permission granted create certificatesigningrequests + create certificatesigningrequests/nodeclient
Gives the attacker can submit a kubelet client CSR for any node name, which the controller manager auto-approves for holders of the nodeclient subresource
Step 2 of 3 Node authorizer: token request for a node's pods node_token_request
The Node authorizer lets a kubelet request a token (the TokenRequest API) for the ServiceAccount of any pod bound to its node, because the kubelet has to mount that token into the pod. A node identity for a chosen name therefore yields the tokens of every ServiceAccount with a pod on that node, and across names, in the cluster.
This edge leaves the node_identity sink; it is what makes that sink traversable in the graph.
From ServiceAccount/nodeid-fixtures/nodeid-joiner → ServiceAccount/csr-fixtures/sa-csr-mint
Permission granted node authorizer: create serviceaccounts/token for pods bound to the node
Gives the attacker as the node identity for kubesplaining-e2e-control-plane, can request a token for ServiceAccount csr-fixtures/sa-csr-mint, whose pod is bound there
Step 3 of 3 CSR self-approval: forging a cluster identity csr_approve
The combination of create on certificatesigningrequests AND update/patch on certificatesigningrequests/approval at cluster scope lets the holder have the cluster CA sign an x509 client cert carrying any Subject DN they choose. The apiserver maps the certificate's CN onto the username it authorizes and each O onto a group, for any cert signed by a CA in --client-ca-file. It never checks whether that identity is one Kubernetes would have issued — so CN=system:serviceaccount:kube-system:<sa> authenticates as that ServiceAccount even though Kubernetes itself never issues certificates to ServiceAccounts.
Pick the claim carefully. O=system:masters is the famous version and the one modern clusters block: CertificateSubjectRestriction (default-on since 1.19) rejects that Organization for the kubernetes.io/kube-apiserver-client signer. The Common Name is unrestricted, so the route that works is claiming an existing privileged identity — a kube-system ServiceAccount such as clusterrole-aggregation-controller, or a control-plane user like system:kube-controller-manager.
Note the second gate on the approval side: since 1.19 the CertificateApproval admission plugin also requires the approver to hold the approve verb on the CSR's signers resource. A subject with only the two CSR verbs has a latent escalation that goes live the moment the signer verb is added or the plugin is disabled.
This is a permanent backdoor primitive: cert validity is whatever the signer applies (often a year), Kubernetes has no revocation list, and removing the RBAC grant does not invalidate an issued cert — only a CA rotation does.
From ServiceAccount/csr-fixtures/sa-csr-mint
Permission granted create certificatesigningrequests + update certificatesigningrequests/approval
Gives the attacker can submit a CSR claiming a privileged identity (a kube-system ServiceAccount CN, or system:masters where CertificateSubjectRestriction is off) and self-approve it, minting a CA-signed client cert
CRITICAL
ServiceAccount/privesc-fixtures/sa-ephemeral
→
the system:masters group
score 9.0
2 hops
View finding →
ServiceAccount `sa-ephemeral` in namespace `privesc-fixtures` reaches the system:masters group in 2 hops via Ephemeral container injection → CSR self-approval: forging a cluster identity.
Step 1 of 2 Ephemeral container injection ephemeral_container_inject
update/patch on pods/ephemeralcontainers adds an attacker-chosen container to an already-running pod (the mechanism behind kubectl debug). The injected container joins the victim pod's namespaces and can mount its ServiceAccount token, so it is effectively pod creation against an existing victim: the attacker picks the image but inherits the pod's identity and host exposure.
From ServiceAccount/privesc-fixtures/sa-ephemeral → ServiceAccount/csr-fixtures/sa-csr-mint
Permission granted update,patch pods/ephemeralcontainers
Gives the attacker can inject an ephemeral container into pods running as ServiceAccount csr-fixtures/sa-csr-mint
Step 2 of 2 CSR self-approval: forging a cluster identity csr_approve
The combination of create on certificatesigningrequests AND update/patch on certificatesigningrequests/approval at cluster scope lets the holder have the cluster CA sign an x509 client cert carrying any Subject DN they choose. The apiserver maps the certificate's CN onto the username it authorizes and each O onto a group, for any cert signed by a CA in --client-ca-file. It never checks whether that identity is one Kubernetes would have issued — so CN=system:serviceaccount:kube-system:<sa> authenticates as that ServiceAccount even though Kubernetes itself never issues certificates to ServiceAccounts.
Pick the claim carefully. O=system:masters is the famous version and the one modern clusters block: CertificateSubjectRestriction (default-on since 1.19) rejects that Organization for the kubernetes.io/kube-apiserver-client signer. The Common Name is unrestricted, so the route that works is claiming an existing privileged identity — a kube-system ServiceAccount such as clusterrole-aggregation-controller, or a control-plane user like system:kube-controller-manager.
Note the second gate on the approval side: since 1.19 the CertificateApproval admission plugin also requires the approver to hold the approve verb on the CSR's signers resource. A subject with only the two CSR verbs has a latent escalation that goes live the moment the signer verb is added or the plugin is disabled.
This is a permanent backdoor primitive: cert validity is whatever the signer applies (often a year), Kubernetes has no revocation list, and removing the RBAC grant does not invalidate an issued cert — only a CA rotation does.
From ServiceAccount/csr-fixtures/sa-csr-mint
Permission granted create certificatesigningrequests + update certificatesigningrequests/approval
Gives the attacker can submit a CSR claiming a privileged identity (a kube-system ServiceAccount CN, or system:masters where CertificateSubjectRestriction is off) and self-approve it, minting a CA-signed client cert
CRITICAL
ServiceAccount/privesc-fixtures/sa-pod-exec
→
the system:masters group
score 9.0
2 hops
View finding →
ServiceAccount `sa-pod-exec` in namespace `privesc-fixtures` reaches the system:masters group in 2 hops via Pod exec → container takeover → CSR self-approval: forging a cluster identity.
Step 1 of 2 Pod exec → container takeover pod_exec
The pods/exec subresource opens a shell inside a running container. If the container's pod uses a privileged ServiceAccount, the attacker inherits that SA's reach. If the container is itself privileged or mounts the host, this is also a node-escape primitive.
From ServiceAccount/privesc-fixtures/sa-pod-exec → ServiceAccount/csr-fixtures/sa-csr-mint
Permission granted create,get pods/exec|pods/attach
Gives the attacker can exec into pods running as ServiceAccount csr-fixtures/sa-csr-mint
Step 2 of 2 CSR self-approval: forging a cluster identity csr_approve
The combination of create on certificatesigningrequests AND update/patch on certificatesigningrequests/approval at cluster scope lets the holder have the cluster CA sign an x509 client cert carrying any Subject DN they choose. The apiserver maps the certificate's CN onto the username it authorizes and each O onto a group, for any cert signed by a CA in --client-ca-file. It never checks whether that identity is one Kubernetes would have issued — so CN=system:serviceaccount:kube-system:<sa> authenticates as that ServiceAccount even though Kubernetes itself never issues certificates to ServiceAccounts.
Pick the claim carefully. O=system:masters is the famous version and the one modern clusters block: CertificateSubjectRestriction (default-on since 1.19) rejects that Organization for the kubernetes.io/kube-apiserver-client signer. The Common Name is unrestricted, so the route that works is claiming an existing privileged identity — a kube-system ServiceAccount such as clusterrole-aggregation-controller, or a control-plane user like system:kube-controller-manager.
Note the second gate on the approval side: since 1.19 the CertificateApproval admission plugin also requires the approver to hold the approve verb on the CSR's signers resource. A subject with only the two CSR verbs has a latent escalation that goes live the moment the signer verb is added or the plugin is disabled.
This is a permanent backdoor primitive: cert validity is whatever the signer applies (often a year), Kubernetes has no revocation list, and removing the RBAC grant does not invalidate an issued cert — only a CA rotation does.
From ServiceAccount/csr-fixtures/sa-csr-mint
Permission granted create certificatesigningrequests + update certificatesigningrequests/approval
Gives the attacker can submit a CSR claiming a privileged identity (a kube-system ServiceAccount CN, or system:masters where CertificateSubjectRestriction is off) and self-approve it, minting a CA-signed client cert
CRITICAL
ServiceAccount/rbac-fixtures/sa-pod-create
→
the system:masters group
score 9.0
2 hops
View finding →
ServiceAccount `sa-pod-create` in namespace `rbac-fixtures` reaches the system:masters group in 2 hops via Pod creation → ServiceAccount token theft → CSR self-approval: forging a cluster identity.
Step 1 of 2 Pod creation → ServiceAccount token theft pod_create_token_theft
Anyone who can create pods in a namespace can mount any ServiceAccount in that namespace into the pod. Cluster-scoped pod-create lets you mount any ServiceAccount in any namespace. Once the pod is running, the attacker reads /var/run/secrets/kubernetes.io/serviceaccount/token from inside it, and now holds a token for that SA.
This is the single most common privilege-escalation pattern in production Kubernetes.
From ServiceAccount/rbac-fixtures/sa-pod-create → ServiceAccount/csr-fixtures/sa-csr-mint
Permission granted create pods
Gives the attacker can create pods that mount ServiceAccount csr-fixtures/sa-csr-mint
Step 2 of 2 CSR self-approval: forging a cluster identity csr_approve
The combination of create on certificatesigningrequests AND update/patch on certificatesigningrequests/approval at cluster scope lets the holder have the cluster CA sign an x509 client cert carrying any Subject DN they choose. The apiserver maps the certificate's CN onto the username it authorizes and each O onto a group, for any cert signed by a CA in --client-ca-file. It never checks whether that identity is one Kubernetes would have issued — so CN=system:serviceaccount:kube-system:<sa> authenticates as that ServiceAccount even though Kubernetes itself never issues certificates to ServiceAccounts.
Pick the claim carefully. O=system:masters is the famous version and the one modern clusters block: CertificateSubjectRestriction (default-on since 1.19) rejects that Organization for the kubernetes.io/kube-apiserver-client signer. The Common Name is unrestricted, so the route that works is claiming an existing privileged identity — a kube-system ServiceAccount such as clusterrole-aggregation-controller, or a control-plane user like system:kube-controller-manager.
Note the second gate on the approval side: since 1.19 the CertificateApproval admission plugin also requires the approver to hold the approve verb on the CSR's signers resource. A subject with only the two CSR verbs has a latent escalation that goes live the moment the signer verb is added or the plugin is disabled.
This is a permanent backdoor primitive: cert validity is whatever the signer applies (often a year), Kubernetes has no revocation list, and removing the RBAC grant does not invalidate an issued cert — only a CA rotation does.
From ServiceAccount/csr-fixtures/sa-csr-mint
Permission granted create certificatesigningrequests + update certificatesigningrequests/approval
Gives the attacker can submit a CSR claiming a privileged identity (a kube-system ServiceAccount CN, or system:masters where CertificateSubjectRestriction is off) and self-approve it, minting a CA-signed client cert
Survives cutting the crb-pod-create binding (2 hops)
This route reaches the same target without the crb-pod-create binding, so removing this subject from that binding alone does not close it. The Remediation for this finding may name a broader fix that closes both.
Step 1 of 2 Steal node IAM role via IMDS imds_node_role_pivot
EC2-backed EKS worker nodes attach an IAM role to the instance and expose its credentials at the link-local IMDS endpoint 169.254.169.254. Pods inherit the host's network unless a NetworkPolicy denies egress to that IP, so a compromised pod can curl IMDS, parse out the node-role credentials, and act in AWS as the node.
The node role is typically broader than any single workload's IRSA role: it can pull from ECR, describe EC2 instances, and is often given additional grants for cluster-autoscaler / EBS-CSI / external-dns. This is a credential-theft chain (SSRF to cloud creds) rather than a Kubernetes RBAC chain.
From ServiceAccount/rbac-fixtures/sa-pod-create
Permission granted IMDS reachable, IRSA unbound
Gives the attacker pod rbac-fixtures/daemon-app-v82sg falls back to node IAM role via IMDS
Step 2 of 2 Control-plane PKI theft control_plane_pki_theft
Root on a node is serious anywhere, but root on a control-plane node is game over. The cluster's certificate authority private key sits at /etc/kubernetes/pki/ca.key. With it an attacker signs a client certificate carrying O=system:masters entirely offline, and the API server accepts it because that group short-circuits authorization.
No RBAC object changes, so no audit event records the grant. Recovery means rotating the cluster CA, not merely deleting a binding.
From ServiceAccount/rbac-fixtures/sa-pod-create
Permission granted root on a schedulable control-plane node
Gives the attacker can read /etc/kubernetes/pki/ca.key and forge an O=system:masters client certificate offline
CRITICAL
ServiceAccount/rbac-fixtures/sa-workload-mutate
→
the system:masters group
score 9.0
2 hops
View finding →
ServiceAccount `sa-workload-mutate` in namespace `rbac-fixtures` reaches the system:masters group in 2 hops via Workload creation → ServiceAccount token theft → CSR self-approval: forging a cluster identity.
Step 1 of 2 Workload creation → ServiceAccount token theft workload_create_token_theft
A Deployment, DaemonSet, StatefulSet, Job, or CronJob carries a pod template, and its controller creates pods from that template. Whoever writes the template chooses the ServiceAccount the pods run as, and Kubernetes checks only that the ServiceAccount exists, not that the writer may use it.
So create on any of these kinds reaches exactly what create pods reaches: every ServiceAccount in the namespace (or in every namespace, for a cluster-wide grant). Removing create pods from a role while leaving create deployments changes nothing.
From ServiceAccount/rbac-fixtures/sa-workload-mutate → ServiceAccount/csr-fixtures/sa-csr-mint
Permission granted create deployments/daemonsets/statefulsets/jobs/cronjobs
Gives the attacker can create a workload whose pods run as ServiceAccount csr-fixtures/sa-csr-mint
Step 2 of 2 CSR self-approval: forging a cluster identity csr_approve
The combination of create on certificatesigningrequests AND update/patch on certificatesigningrequests/approval at cluster scope lets the holder have the cluster CA sign an x509 client cert carrying any Subject DN they choose. The apiserver maps the certificate's CN onto the username it authorizes and each O onto a group, for any cert signed by a CA in --client-ca-file. It never checks whether that identity is one Kubernetes would have issued — so CN=system:serviceaccount:kube-system:<sa> authenticates as that ServiceAccount even though Kubernetes itself never issues certificates to ServiceAccounts.
Pick the claim carefully. O=system:masters is the famous version and the one modern clusters block: CertificateSubjectRestriction (default-on since 1.19) rejects that Organization for the kubernetes.io/kube-apiserver-client signer. The Common Name is unrestricted, so the route that works is claiming an existing privileged identity — a kube-system ServiceAccount such as clusterrole-aggregation-controller, or a control-plane user like system:kube-controller-manager.
Note the second gate on the approval side: since 1.19 the CertificateApproval admission plugin also requires the approver to hold the approve verb on the CSR's signers resource. A subject with only the two CSR verbs has a latent escalation that goes live the moment the signer verb is added or the plugin is disabled.
This is a permanent backdoor primitive: cert validity is whatever the signer applies (often a year), Kubernetes has no revocation list, and removing the RBAC grant does not invalidate an issued cert — only a CA rotation does.
From ServiceAccount/csr-fixtures/sa-csr-mint
Permission granted create certificatesigningrequests + update certificatesigningrequests/approval
Gives the attacker can submit a CSR claiming a privileged identity (a kube-system ServiceAccount CN, or system:masters where CertificateSubjectRestriction is off) and self-approve it, minting a CA-signed client cert
CRITICAL
ServiceAccount/vulnerable/privileged-reader
→
the system:masters group
score 9.0
2 hops
View finding →
ServiceAccount `privileged-reader` in namespace `vulnerable` reaches the system:masters group in 2 hops via Pod creation → ServiceAccount token theft → CSR self-approval: forging a cluster identity.
Step 1 of 2 Pod creation → ServiceAccount token theft pod_create_token_theft
Anyone who can create pods in a namespace can mount any ServiceAccount in that namespace into the pod. Cluster-scoped pod-create lets you mount any ServiceAccount in any namespace. Once the pod is running, the attacker reads /var/run/secrets/kubernetes.io/serviceaccount/token from inside it, and now holds a token for that SA.
This is the single most common privilege-escalation pattern in production Kubernetes.
From ServiceAccount/vulnerable/privileged-reader → ServiceAccount/csr-fixtures/sa-csr-mint
Permission granted create pods
Gives the attacker can create pods that mount ServiceAccount csr-fixtures/sa-csr-mint
Step 2 of 2 CSR self-approval: forging a cluster identity csr_approve
The combination of create on certificatesigningrequests AND update/patch on certificatesigningrequests/approval at cluster scope lets the holder have the cluster CA sign an x509 client cert carrying any Subject DN they choose. The apiserver maps the certificate's CN onto the username it authorizes and each O onto a group, for any cert signed by a CA in --client-ca-file. It never checks whether that identity is one Kubernetes would have issued — so CN=system:serviceaccount:kube-system:<sa> authenticates as that ServiceAccount even though Kubernetes itself never issues certificates to ServiceAccounts.
Pick the claim carefully. O=system:masters is the famous version and the one modern clusters block: CertificateSubjectRestriction (default-on since 1.19) rejects that Organization for the kubernetes.io/kube-apiserver-client signer. The Common Name is unrestricted, so the route that works is claiming an existing privileged identity — a kube-system ServiceAccount such as clusterrole-aggregation-controller, or a control-plane user like system:kube-controller-manager.
Note the second gate on the approval side: since 1.19 the CertificateApproval admission plugin also requires the approver to hold the approve verb on the CSR's signers resource. A subject with only the two CSR verbs has a latent escalation that goes live the moment the signer verb is added or the plugin is disabled.
This is a permanent backdoor primitive: cert validity is whatever the signer applies (often a year), Kubernetes has no revocation list, and removing the RBAC grant does not invalidate an issued cert — only a CA rotation does.
From ServiceAccount/csr-fixtures/sa-csr-mint
Permission granted create certificatesigningrequests + update certificatesigningrequests/approval
Gives the attacker can submit a CSR claiming a privileged identity (a kube-system ServiceAccount CN, or system:masters where CertificateSubjectRestriction is off) and self-approve it, minting a CA-signed client cert
CRITICAL
ServiceAccount/nodeid-fixtures/nodeid-tokenwriter
→
the system:masters group
score 8.9
3 hops
View finding →
ServiceAccount `nodeid-tokenwriter` in namespace `nodeid-fixtures` reaches the system:masters group in 3 hops via Bootstrap token minting → Node authorizer: token request for a node's pods → CSR self-approval: forging a cluster identity.
Step 1 of 3 Bootstrap token minting bootstrap_token_mint
A Secret of type bootstrap.kubernetes.io/token in kube-system is a credential: the bootstrap-token authenticator accepts its <id>.<secret> as the user system:bootstrap:<id> in the groups the Secret's auth-extra-groups names. On a kubeadm cluster that group may submit kubelet client CSRs that the controller manager auto-approves.
A Secret write reaching kube-system therefore mints a token that buys a kubelet identity for any node name. The edge is drawn only when the cluster has the auto-approval binding; without it, the token authenticates but reaches nothing.
From ServiceAccount/nodeid-fixtures/nodeid-tokenwriter
Permission granted create secrets in kube-system
Gives the attacker can write a bootstrap-token Secret in kube-system, minting a token that this cluster's bootstrap group turns into an auto-approved kubelet client certificate for any node name
Step 2 of 3 Node authorizer: token request for a node's pods node_token_request
The Node authorizer lets a kubelet request a token (the TokenRequest API) for the ServiceAccount of any pod bound to its node, because the kubelet has to mount that token into the pod. A node identity for a chosen name therefore yields the tokens of every ServiceAccount with a pod on that node, and across names, in the cluster.
This edge leaves the node_identity sink; it is what makes that sink traversable in the graph.
From ServiceAccount/nodeid-fixtures/nodeid-tokenwriter → ServiceAccount/csr-fixtures/sa-csr-mint
Permission granted node authorizer: create serviceaccounts/token for pods bound to the node
Gives the attacker as the node identity for kubesplaining-e2e-control-plane, can request a token for ServiceAccount csr-fixtures/sa-csr-mint, whose pod is bound there
Step 3 of 3 CSR self-approval: forging a cluster identity csr_approve
The combination of create on certificatesigningrequests AND update/patch on certificatesigningrequests/approval at cluster scope lets the holder have the cluster CA sign an x509 client cert carrying any Subject DN they choose. The apiserver maps the certificate's CN onto the username it authorizes and each O onto a group, for any cert signed by a CA in --client-ca-file. It never checks whether that identity is one Kubernetes would have issued — so CN=system:serviceaccount:kube-system:<sa> authenticates as that ServiceAccount even though Kubernetes itself never issues certificates to ServiceAccounts.
Pick the claim carefully. O=system:masters is the famous version and the one modern clusters block: CertificateSubjectRestriction (default-on since 1.19) rejects that Organization for the kubernetes.io/kube-apiserver-client signer. The Common Name is unrestricted, so the route that works is claiming an existing privileged identity — a kube-system ServiceAccount such as clusterrole-aggregation-controller, or a control-plane user like system:kube-controller-manager.
Note the second gate on the approval side: since 1.19 the CertificateApproval admission plugin also requires the approver to hold the approve verb on the CSR's signers resource. A subject with only the two CSR verbs has a latent escalation that goes live the moment the signer verb is added or the plugin is disabled.
This is a permanent backdoor primitive: cert validity is whatever the signer applies (often a year), Kubernetes has no revocation list, and removing the RBAC grant does not invalidate an issued cert — only a CA rotation does.
From ServiceAccount/csr-fixtures/sa-csr-mint
Permission granted create certificatesigningrequests + update certificatesigningrequests/approval
Gives the attacker can submit a CSR claiming a privileged identity (a kube-system ServiceAccount CN, or system:masters where CertificateSubjectRestriction is off) and self-approve it, minting a CA-signed client cert
CRITICAL
ServiceAccount/privesc-fixtures/sa-secret-mint
→
the system:masters group
score 8.9
3 hops
View finding →
ServiceAccount `sa-secret-mint` in namespace `privesc-fixtures` reaches the system:masters group in 3 hops via Bootstrap token minting → Node authorizer: token request for a node's pods → CSR self-approval: forging a cluster identity.
Step 1 of 3 Bootstrap token minting bootstrap_token_mint
A Secret of type bootstrap.kubernetes.io/token in kube-system is a credential: the bootstrap-token authenticator accepts its <id>.<secret> as the user system:bootstrap:<id> in the groups the Secret's auth-extra-groups names. On a kubeadm cluster that group may submit kubelet client CSRs that the controller manager auto-approves.
A Secret write reaching kube-system therefore mints a token that buys a kubelet identity for any node name. The edge is drawn only when the cluster has the auto-approval binding; without it, the token authenticates but reaches nothing.
From ServiceAccount/privesc-fixtures/sa-secret-mint
Permission granted create,get secrets in kube-system
Gives the attacker can write a bootstrap-token Secret in kube-system, minting a token that this cluster's bootstrap group turns into an auto-approved kubelet client certificate for any node name
Step 2 of 3 Node authorizer: token request for a node's pods node_token_request
The Node authorizer lets a kubelet request a token (the TokenRequest API) for the ServiceAccount of any pod bound to its node, because the kubelet has to mount that token into the pod. A node identity for a chosen name therefore yields the tokens of every ServiceAccount with a pod on that node, and across names, in the cluster.
This edge leaves the node_identity sink; it is what makes that sink traversable in the graph.
From ServiceAccount/privesc-fixtures/sa-secret-mint → ServiceAccount/csr-fixtures/sa-csr-mint
Permission granted node authorizer: create serviceaccounts/token for pods bound to the node
Gives the attacker as the node identity for kubesplaining-e2e-control-plane, can request a token for ServiceAccount csr-fixtures/sa-csr-mint, whose pod is bound there
Step 3 of 3 CSR self-approval: forging a cluster identity csr_approve
The combination of create on certificatesigningrequests AND update/patch on certificatesigningrequests/approval at cluster scope lets the holder have the cluster CA sign an x509 client cert carrying any Subject DN they choose. The apiserver maps the certificate's CN onto the username it authorizes and each O onto a group, for any cert signed by a CA in --client-ca-file. It never checks whether that identity is one Kubernetes would have issued — so CN=system:serviceaccount:kube-system:<sa> authenticates as that ServiceAccount even though Kubernetes itself never issues certificates to ServiceAccounts.
Pick the claim carefully. O=system:masters is the famous version and the one modern clusters block: CertificateSubjectRestriction (default-on since 1.19) rejects that Organization for the kubernetes.io/kube-apiserver-client signer. The Common Name is unrestricted, so the route that works is claiming an existing privileged identity — a kube-system ServiceAccount such as clusterrole-aggregation-controller, or a control-plane user like system:kube-controller-manager.
Note the second gate on the approval side: since 1.19 the CertificateApproval admission plugin also requires the approver to hold the approve verb on the CSR's signers resource. A subject with only the two CSR verbs has a latent escalation that goes live the moment the signer verb is added or the plugin is disabled.
This is a permanent backdoor primitive: cert validity is whatever the signer applies (often a year), Kubernetes has no revocation list, and removing the RBAC grant does not invalidate an issued cert — only a CA rotation does.
From ServiceAccount/csr-fixtures/sa-csr-mint
Permission granted create certificatesigningrequests + update certificatesigningrequests/approval
Gives the attacker can submit a CSR claiming a privileged identity (a kube-system ServiceAccount CN, or system:masters where CertificateSubjectRestriction is off) and self-approve it, minting a CA-signed client cert
CRITICAL
ServiceAccount/cloud-eks-test/eks-admin-irsa
→
the system:masters group
score 8.8
2 hops
View finding →
ServiceAccount `eks-admin-irsa` in namespace `cloud-eks-test` reaches the system:masters group in 2 hops via Assume AWS IAM Role via IRSA → AWS IAM principal granted cluster-admin via aws-auth.
Step 1 of 2 Assume AWS IAM Role via IRSA irsa_assume_role
A pod whose ServiceAccount is annotated with eks.amazonaws.com/role-arn can call sts:AssumeRoleWithWebIdentity with the projected SA token and receive short-lived AWS credentials for the named IAM role. The exchange happens entirely in user-space inside the pod, so anyone with exec on that pod (or with create-pod rights in the namespace) inherits the IAM role's permissions.
What the attacker gains depends on the IAM role's policy. If the role carries AdministratorAccess, PowerUserAccess, or any *:* grant, this is an AWS-account-wide takeover routed through Kubernetes.
From ServiceAccount/cloud-eks-test/eks-admin-irsa → User/arn:aws:iam::123456789012:role/AdministratorAccess
Permission granted arn:aws:iam::123456789012:role/AdministratorAccess
Gives the attacker ServiceAccount can assume arn:aws:iam::123456789012:role/AdministratorAccess via IRSA
Step 2 of 2 AWS IAM principal granted cluster-admin via aws-auth aws_auth_admin
EKS authenticates AWS IAM principals into Kubernetes via the kube-system/aws-auth ConfigMap. Each entry under mapRoles / mapUsers ties an IAM role or user ARN to a Kubernetes username and a list of groups. If that group list contains system:masters, the IAM principal is hard-coded as cluster-admin by the apiserver. If it contains any group bound to cluster-admin via a ClusterRoleBinding, the effect is the same: the IAM principal can do anything in the cluster.
This grant is invisible to kubectl get clusterrolebindings: the mapping lives in a ConfigMap and the resulting identity is synthesized at request-time by the EKS aws-iam-authenticator.
From User/arn:aws:iam::123456789012:role/AdministratorAccess
Permission granted system:masters via aws-auth
Gives the attacker external IAM principal arn:aws:iam::123456789012:role/AdministratorAccess is mapped to system:masters via aws-auth
CRITICAL
ServiceAccount/cutres/cutres-doublebind
→
the system:masters group
score 8.8
2 hops
View finding →
ServiceAccount `cutres-doublebind` in namespace `cutres` reaches the system:masters group in 2 hops via Create a privileged pod and escape to the node → Control-plane PKI theft.
Step 1 of 2 Create a privileged pod and escape to the node pod_create_privileged_escape
RBAC never inspects pod contents, only the create verb. When the target namespace has no restrictive Pod Security Admission enforce label, an attacker who can create pods sets privileged: true, hostPID, or a hostPath mount of / and breaks out to the node. Baseline or Restricted enforcement would block this and limit the risk to token theft alone.
From ServiceAccount/cutres/cutres-doublebind
Permission granted create pods (Pod Security Admission does not block privileged)
Gives the attacker can create a privileged pod that escapes to the node
Step 2 of 2 Control-plane PKI theft control_plane_pki_theft
Root on a node is serious anywhere, but root on a control-plane node is game over. The cluster's certificate authority private key sits at /etc/kubernetes/pki/ca.key. With it an attacker signs a client certificate carrying O=system:masters entirely offline, and the API server accepts it because that group short-circuits authorization.
No RBAC object changes, so no audit event records the grant. Recovery means rotating the cluster CA, not merely deleting a binding.
From ServiceAccount/cutres/cutres-doublebind
Permission granted root on a schedulable control-plane node
Gives the attacker can read /etc/kubernetes/pki/ca.key and forge an O=system:masters client certificate offline
Survives cutting the cutres-pod-creator-a binding (2 hops)
This route reaches the same target without the cutres-pod-creator-a binding, so removing this subject from that binding alone does not close it. The Remediation for this finding may name a broader fix that closes both.
Step 1 of 2 Create a privileged pod and escape to the node pod_create_privileged_escape
RBAC never inspects pod contents, only the create verb. When the target namespace has no restrictive Pod Security Admission enforce label, an attacker who can create pods sets privileged: true, hostPID, or a hostPath mount of / and breaks out to the node. Baseline or Restricted enforcement would block this and limit the risk to token theft alone.
From ServiceAccount/cutres/cutres-doublebind
Permission granted create pods (Pod Security Admission does not block privileged)
Gives the attacker can create a privileged pod that escapes to the node
Step 2 of 2 Control-plane PKI theft control_plane_pki_theft
Root on a node is serious anywhere, but root on a control-plane node is game over. The cluster's certificate authority private key sits at /etc/kubernetes/pki/ca.key. With it an attacker signs a client certificate carrying O=system:masters entirely offline, and the API server accepts it because that group short-circuits authorization.
No RBAC object changes, so no audit event records the grant. Recovery means rotating the cluster CA, not merely deleting a binding.
From ServiceAccount/cutres/cutres-doublebind
Permission granted root on a schedulable control-plane node
Gives the attacker can read /etc/kubernetes/pki/ca.key and forge an O=system:masters client certificate offline
CRITICAL
ServiceAccount/foothold-fixtures/foothold-priv
→
the system:masters group
score 8.8
2 hops
View finding →
ServiceAccount `foothold-priv` in namespace `foothold-fixtures` reaches the system:masters group in 2 hops via Container escape to host → Control-plane PKI theft.
Step 1 of 2 Container escape to host pod_host_escape
The pod is configured in a way that makes escaping to the underlying node trivial: privileged: true, hostPID, hostNetwork, or a sensitive hostPath mount (root, docker.sock, etc.). An attacker who controls the container reaches root on the node, then has access to every pod and kubelet credential on that node.
From ServiceAccount/foothold-fixtures/foothold-priv
Permission granted privileged
Gives the attacker runs in pod foothold-fixtures/foothold-priv-app-568f779db7-cmqmb with privileged
Step 2 of 2 Control-plane PKI theft control_plane_pki_theft
Root on a node is serious anywhere, but root on a control-plane node is game over. The cluster's certificate authority private key sits at /etc/kubernetes/pki/ca.key. With it an attacker signs a client certificate carrying O=system:masters entirely offline, and the API server accepts it because that group short-circuits authorization.
No RBAC object changes, so no audit event records the grant. Recovery means rotating the cluster CA, not merely deleting a binding.
From ServiceAccount/foothold-fixtures/foothold-priv
Permission granted root on a schedulable control-plane node
Gives the attacker can read /etc/kubernetes/pki/ca.key and forge an O=system:masters client certificate offline
CRITICAL
ServiceAccount/hookbackend-fixtures/hookbackend-operator
→
the system:masters group
score 8.8
2 hops
View finding →
ServiceAccount `hookbackend-operator` in namespace `hookbackend-fixtures` reaches the system:masters group in 2 hops via Control-plane backend hijack → Control-plane PKI theft.
Step 1 of 2 Control-plane backend hijack control_plane_backend_hijack
Admission webhooks and aggregated API servers are ordinary Services that the API server itself calls, with its own front-proxy credentials and the caller's identity attached. The API server verifies them against the configuration's caBundle with the Service's DNS name pinned. Whoever can steer that Service's traffic (write its EndpointSlices or spec, or put a pod of their own behind it) and present its serving certificate (read the Secret, mount it, or run code in the backend's pods) is that backend.
A namespace hosting such a backend therefore has to be treated like kube-system: the built-in edit and admin ClusterRoles hold both halves. A hijacked mutating webhook on pods rewrites every new pod; a hijacked native-group APIService serves a core API group; a validating webhook is bypassed; anything else is an interception point for the API server's traffic.
From ServiceAccount/hookbackend-fixtures/hookbackend-operator
Permission granted write services + read secrets in hookbackend-fixtures
Gives the attacker can take over the backend of MutatingWebhookConfiguration hookbackend-fixtures-injector/inject.hookbackend-fixtures.example.com in namespace hookbackend-fixtures, which the API server calls with its own credentials
Step 2 of 2 Control-plane PKI theft control_plane_pki_theft
Root on a node is serious anywhere, but root on a control-plane node is game over. The cluster's certificate authority private key sits at /etc/kubernetes/pki/ca.key. With it an attacker signs a client certificate carrying O=system:masters entirely offline, and the API server accepts it because that group short-circuits authorization.
No RBAC object changes, so no audit event records the grant. Recovery means rotating the cluster CA, not merely deleting a binding.
From ServiceAccount/hookbackend-fixtures/hookbackend-operator
Permission granted root on a schedulable control-plane node
Gives the attacker can read /etc/kubernetes/pki/ca.key and forge an O=system:masters client certificate offline
CRITICAL
ServiceAccount/local-path-storage/local-path-provisioner-service-account
→
the system:masters group
score 8.8
2 hops
View finding →
ServiceAccount `local-path-provisioner-service-account` in namespace `local-path-storage` reaches the system:masters group in 2 hops via Create a privileged pod and escape to the node → Control-plane PKI theft.
Step 1 of 2 Create a privileged pod and escape to the node pod_create_privileged_escape
RBAC never inspects pod contents, only the create verb. When the target namespace has no restrictive Pod Security Admission enforce label, an attacker who can create pods sets privileged: true, hostPID, or a hostPath mount of / and breaks out to the node. Baseline or Restricted enforcement would block this and limit the risk to token theft alone.
From ServiceAccount/local-path-storage/local-path-provisioner-service-account
Permission granted create pods (Pod Security Admission does not block privileged)
Gives the attacker can create a privileged pod that escapes to the node
Step 2 of 2 Control-plane PKI theft control_plane_pki_theft
Root on a node is serious anywhere, but root on a control-plane node is game over. The cluster's certificate authority private key sits at /etc/kubernetes/pki/ca.key. With it an attacker signs a client certificate carrying O=system:masters entirely offline, and the API server accepts it because that group short-circuits authorization.
No RBAC object changes, so no audit event records the grant. Recovery means rotating the cluster CA, not merely deleting a binding.
From ServiceAccount/local-path-storage/local-path-provisioner-service-account
Permission granted root on a schedulable control-plane node
Gives the attacker can read /etc/kubernetes/pki/ca.key and forge an O=system:masters client certificate offline
Survives cutting the local-path-provisioner-bind binding (2 hops)
This route reaches the same target without the local-path-provisioner-bind binding, so removing this subject from that binding alone does not close it. The Remediation for this finding may name a broader fix that closes both.
Step 1 of 2 Steal node IAM role via IMDS imds_node_role_pivot
EC2-backed EKS worker nodes attach an IAM role to the instance and expose its credentials at the link-local IMDS endpoint 169.254.169.254. Pods inherit the host's network unless a NetworkPolicy denies egress to that IP, so a compromised pod can curl IMDS, parse out the node-role credentials, and act in AWS as the node.
The node role is typically broader than any single workload's IRSA role: it can pull from ECR, describe EC2 instances, and is often given additional grants for cluster-autoscaler / EBS-CSI / external-dns. This is a credential-theft chain (SSRF to cloud creds) rather than a Kubernetes RBAC chain.
From ServiceAccount/local-path-storage/local-path-provisioner-service-account
Permission granted IMDS reachable, IRSA unbound
Gives the attacker pod local-path-storage/local-path-provisioner-67b8995b4b-r5gbn falls back to node IAM role via IMDS
Step 2 of 2 Control-plane PKI theft control_plane_pki_theft
Root on a node is serious anywhere, but root on a control-plane node is game over. The cluster's certificate authority private key sits at /etc/kubernetes/pki/ca.key. With it an attacker signs a client certificate carrying O=system:masters entirely offline, and the API server accepts it because that group short-circuits authorization.
No RBAC object changes, so no audit event records the grant. Recovery means rotating the cluster CA, not merely deleting a binding.
From ServiceAccount/local-path-storage/local-path-provisioner-service-account
Permission granted root on a schedulable control-plane node
Gives the attacker can read /etc/kubernetes/pki/ca.key and forge an O=system:masters client certificate offline
CRITICAL
ServiceAccount/map-fixtures/sa-mutating-policy
→
the system:masters group
score 8.8
2 hops
View finding →
ServiceAccount `sa-mutating-policy` in namespace `map-fixtures` reaches the system:masters group in 2 hops via MutatingAdmissionPolicy injection → Control-plane PKI theft.
Step 1 of 2 MutatingAdmissionPolicy injection mutating_policy_inject
A MutatingAdmissionPolicy is the in-tree, webhookless way to rewrite objects as the API server admits them (GA in Kubernetes v1.36). Its CEL / JSONPatch mutation lives in etcd and runs inside the API server, so unlike a mutating webhook there is no external endpoint, TLS certificate, or backing Deployment to notice.
An attacker who can write both the policy and a binding for it injects privileged: true, a hostPath mount, or an extra container into every pod created afterwards. Mutating admission runs before validating admission, so the injected pod still faces Pod Security Admission: the mutation targets a namespace PSA does not restrict (an unlabeled one, or kube-system), lands a privileged pod there, and that is a node escape.
From ServiceAccount/map-fixtures/sa-mutating-policy
Permission granted create/update mutatingadmissionpolicies + mutatingadmissionpolicybindings
Gives the attacker can author and bind a MutatingAdmissionPolicy that injects a privileged/hostPath pod at admission time
Step 2 of 2 Control-plane PKI theft control_plane_pki_theft
Root on a node is serious anywhere, but root on a control-plane node is game over. The cluster's certificate authority private key sits at /etc/kubernetes/pki/ca.key. With it an attacker signs a client certificate carrying O=system:masters entirely offline, and the API server accepts it because that group short-circuits authorization.
No RBAC object changes, so no audit event records the grant. Recovery means rotating the cluster CA, not merely deleting a binding.
From ServiceAccount/map-fixtures/sa-mutating-policy
Permission granted root on a schedulable control-plane node
Gives the attacker can read /etc/kubernetes/pki/ca.key and forge an O=system:masters client certificate offline
CRITICAL
ServiceAccount/privesc-fixtures/sa-pod-create-escape
→
the system:masters group
score 8.8
2 hops
View finding →
ServiceAccount `sa-pod-create-escape` in namespace `privesc-fixtures` reaches the system:masters group in 2 hops via Create a privileged pod and escape to the node → Control-plane PKI theft.
Step 1 of 2 Create a privileged pod and escape to the node pod_create_privileged_escape
RBAC never inspects pod contents, only the create verb. When the target namespace has no restrictive Pod Security Admission enforce label, an attacker who can create pods sets privileged: true, hostPID, or a hostPath mount of / and breaks out to the node. Baseline or Restricted enforcement would block this and limit the risk to token theft alone.
From ServiceAccount/privesc-fixtures/sa-pod-create-escape
Permission granted create pods (Pod Security Admission does not block privileged)
Gives the attacker can create a privileged pod that escapes to the node
Step 2 of 2 Control-plane PKI theft control_plane_pki_theft
Root on a node is serious anywhere, but root on a control-plane node is game over. The cluster's certificate authority private key sits at /etc/kubernetes/pki/ca.key. With it an attacker signs a client certificate carrying O=system:masters entirely offline, and the API server accepts it because that group short-circuits authorization.
No RBAC object changes, so no audit event records the grant. Recovery means rotating the cluster CA, not merely deleting a binding.
From ServiceAccount/privesc-fixtures/sa-pod-create-escape
Permission granted root on a schedulable control-plane node
Gives the attacker can read /etc/kubernetes/pki/ca.key and forge an O=system:masters client certificate offline
CRITICAL
ServiceAccount/psa-suppressed/default
→
the system:masters group
score 8.8
2 hops
View finding →
ServiceAccount `default` in namespace `psa-suppressed` reaches the system:masters group in 2 hops via Container escape to host → Control-plane PKI theft.
Step 1 of 2 Container escape to host pod_host_escape
The pod is configured in a way that makes escaping to the underlying node trivial: privileged: true, hostPID, hostNetwork, or a sensitive hostPath mount (root, docker.sock, etc.). An attacker who controls the container reaches root on the node, then has access to every pod and kubelet credential on that node.
From ServiceAccount/psa-suppressed/default
Permission granted privileged
Gives the attacker runs in pod psa-suppressed/psa-priv-app-54c64bdd84-w4v5m with privileged
Step 2 of 2 Control-plane PKI theft control_plane_pki_theft
Root on a node is serious anywhere, but root on a control-plane node is game over. The cluster's certificate authority private key sits at /etc/kubernetes/pki/ca.key. With it an attacker signs a client certificate carrying O=system:masters entirely offline, and the API server accepts it because that group short-circuits authorization.
No RBAC object changes, so no audit event records the grant. Recovery means rotating the cluster CA, not merely deleting a binding.
From ServiceAccount/psa-suppressed/default
Permission granted root on a schedulable control-plane node
Gives the attacker can read /etc/kubernetes/pki/ca.key and forge an O=system:masters client certificate offline
CRITICAL
ServiceAccount/psa-unlabeled-fixtures/sa-psa-unlabeled
→
the system:masters group
score 8.8
2 hops
View finding →
ServiceAccount `sa-psa-unlabeled` in namespace `psa-unlabeled-fixtures` reaches the system:masters group in 2 hops via Container escape to host → Control-plane PKI theft.
Step 1 of 2 Container escape to host pod_host_escape
The pod is configured in a way that makes escaping to the underlying node trivial: privileged: true, hostPID, hostNetwork, or a sensitive hostPath mount (root, docker.sock, etc.). An attacker who controls the container reaches root on the node, then has access to every pod and kubelet credential on that node.
From ServiceAccount/psa-unlabeled-fixtures/sa-psa-unlabeled
Permission granted hostNetwork
Gives the attacker runs in pod psa-unlabeled-fixtures/psa-unlabeled-app-f5ff8974-nmmrs with hostNetwork
Step 2 of 2 Control-plane PKI theft control_plane_pki_theft
Root on a node is serious anywhere, but root on a control-plane node is game over. The cluster's certificate authority private key sits at /etc/kubernetes/pki/ca.key. With it an attacker signs a client certificate carrying O=system:masters entirely offline, and the API server accepts it because that group short-circuits authorization.
No RBAC object changes, so no audit event records the grant. Recovery means rotating the cluster CA, not merely deleting a binding.
From ServiceAccount/psa-unlabeled-fixtures/sa-psa-unlabeled
Permission granted root on a schedulable control-plane node
Gives the attacker can read /etc/kubernetes/pki/ca.key and forge an O=system:masters client certificate offline
CRITICAL
ServiceAccount/psaflip-fixtures/psaflip-flipper
→
the system:masters group
score 8.8
2 hops
View finding →
ServiceAccount `psaflip-flipper` in namespace `psaflip-fixtures` reaches the system:masters group in 2 hops via Pod Security Admission label flip → Control-plane PKI theft.
Step 1 of 2 Pod Security Admission label flip namespace_psa_label_flip
Pod Security Admission decides how strictly to vet pods in a namespace by reading the pod-security.kubernetes.io/enforce label on the Namespace object at admission time. That label is ordinary metadata: nothing in Kubernetes protects it, so anyone who can update or patch the namespace can set it to privileged and switch the lockdown off.
Alone the label write changes nothing. Paired with a way to create pods in that namespace, it lets the attacker land a privileged or host-mounting pod in a namespace the cluster's PSA posture reports as restricted, and escape to the node from there. The write grant is outside the built-in admin/edit roles, and a namespaced Role can carry it for its own namespace, because the API server treats /api/v1/namespaces/<ns> as a request inside <ns>.
From ServiceAccount/psaflip-fixtures/psaflip-flipper
Permission granted patch namespaces + create pods (psaflip-fixtures)
Gives the attacker can relabel namespace psaflip-fixtures to pod-security enforce=privileged, then run a privileged pod there and escape to the node
Step 2 of 2 Control-plane PKI theft control_plane_pki_theft
Root on a node is serious anywhere, but root on a control-plane node is game over. The cluster's certificate authority private key sits at /etc/kubernetes/pki/ca.key. With it an attacker signs a client certificate carrying O=system:masters entirely offline, and the API server accepts it because that group short-circuits authorization.
No RBAC object changes, so no audit event records the grant. Recovery means rotating the cluster CA, not merely deleting a binding.
From ServiceAccount/psaflip-fixtures/psaflip-flipper
Permission granted root on a schedulable control-plane node
Gives the attacker can read /etc/kubernetes/pki/ca.key and forge an O=system:masters client certificate offline
CRITICAL
ServiceAccount/rbac-fixtures/sa-nodes-proxy
→
the system:masters group
score 8.8
2 hops
View finding →
ServiceAccount `sa-nodes-proxy` in namespace `rbac-fixtures` reaches the system:masters group in 2 hops via nodes/proxy → kubelet API → Control-plane PKI theft.
Step 1 of 2 nodes/proxy → kubelet API nodes_proxy
The nodes/proxy subresource forwards requests to the kubelet on each node. Combined with kubelet's /exec endpoint and a WebSocket verb mismatch, this becomes a primitive for executing commands inside any pod the kubelet can reach.
From ServiceAccount/rbac-fixtures/sa-nodes-proxy
Permission granted get nodes/proxy
Gives the attacker can reach kubelet API via nodes/proxy WebSocket verb confusion
Step 2 of 2 Control-plane PKI theft control_plane_pki_theft
Root on a node is serious anywhere, but root on a control-plane node is game over. The cluster's certificate authority private key sits at /etc/kubernetes/pki/ca.key. With it an attacker signs a client certificate carrying O=system:masters entirely offline, and the API server accepts it because that group short-circuits authorization.
No RBAC object changes, so no audit event records the grant. Recovery means rotating the cluster CA, not merely deleting a binding.
From ServiceAccount/rbac-fixtures/sa-nodes-proxy
Permission granted root on a schedulable control-plane node
Gives the attacker can read /etc/kubernetes/pki/ca.key and forge an O=system:masters client certificate offline
CRITICAL
ServiceAccount/vulnerable/default
→
the system:masters group
score 8.8
2 hops
View finding →
ServiceAccount `default` in namespace `vulnerable` reaches the system:masters group in 2 hops via Container escape to host → Control-plane PKI theft.
Step 1 of 2 Container escape to host pod_host_escape
The pod is configured in a way that makes escaping to the underlying node trivial: privileged: true, hostPID, hostNetwork, or a sensitive hostPath mount (root, docker.sock, etc.). An attacker who controls the container reaches root on the node, then has access to every pod and kubelet credential on that node.
From ServiceAccount/vulnerable/default
Permission granted hostPID,hostIPC
Gives the attacker runs in pod vulnerable/host-ns-app-7cb46d5788-xbc8b with hostPID, hostIPC
Step 2 of 2 Control-plane PKI theft control_plane_pki_theft
Root on a node is serious anywhere, but root on a control-plane node is game over. The cluster's certificate authority private key sits at /etc/kubernetes/pki/ca.key. With it an attacker signs a client certificate carrying O=system:masters entirely offline, and the API server accepts it because that group short-circuits authorization.
No RBAC object changes, so no audit event records the grant. Recovery means rotating the cluster CA, not merely deleting a binding.
From ServiceAccount/vulnerable/default
Permission granted root on a schedulable control-plane node
Gives the attacker can read /etc/kubernetes/pki/ca.key and forge an O=system:masters client certificate offline
CRITICAL
ServiceAccount/cloud-eks-test/eks-token-minter
→
the system:masters group
score 8.7
3 hops
View finding →
ServiceAccount `eks-token-minter` in namespace `cloud-eks-test` reaches the system:masters group in 3 hops via TokenRequest minting → Assume AWS IAM Role via IRSA → AWS IAM principal granted cluster-admin via aws-auth.
Step 1 of 3 TokenRequest minting token_request
The create verb on serviceaccounts/token mints a fresh, valid token for any ServiceAccount in scope, with no pod required. Cleaner than the pod-creation route and harder to spot in audit logs.
From ServiceAccount/cloud-eks-test/eks-token-minter → ServiceAccount/cloud-eks-test/eks-admin-irsa
Permission granted create serviceaccounts/token
Gives the attacker can mint tokens for ServiceAccount cloud-eks-test/eks-admin-irsa
Step 2 of 3 Assume AWS IAM Role via IRSA irsa_assume_role
A pod whose ServiceAccount is annotated with eks.amazonaws.com/role-arn can call sts:AssumeRoleWithWebIdentity with the projected SA token and receive short-lived AWS credentials for the named IAM role. The exchange happens entirely in user-space inside the pod, so anyone with exec on that pod (or with create-pod rights in the namespace) inherits the IAM role's permissions.
What the attacker gains depends on the IAM role's policy. If the role carries AdministratorAccess, PowerUserAccess, or any *:* grant, this is an AWS-account-wide takeover routed through Kubernetes.
From ServiceAccount/cloud-eks-test/eks-admin-irsa → User/arn:aws:iam::123456789012:role/AdministratorAccess
Permission granted arn:aws:iam::123456789012:role/AdministratorAccess
Gives the attacker ServiceAccount can assume arn:aws:iam::123456789012:role/AdministratorAccess via IRSA
Step 3 of 3 AWS IAM principal granted cluster-admin via aws-auth aws_auth_admin
EKS authenticates AWS IAM principals into Kubernetes via the kube-system/aws-auth ConfigMap. Each entry under mapRoles / mapUsers ties an IAM role or user ARN to a Kubernetes username and a list of groups. If that group list contains system:masters, the IAM principal is hard-coded as cluster-admin by the apiserver. If it contains any group bound to cluster-admin via a ClusterRoleBinding, the effect is the same: the IAM principal can do anything in the cluster.
This grant is invisible to kubectl get clusterrolebindings: the mapping lives in a ConfigMap and the resulting identity is synthesized at request-time by the EKS aws-iam-authenticator.
From User/arn:aws:iam::123456789012:role/AdministratorAccess
Permission granted system:masters via aws-auth
Gives the attacker external IAM principal arn:aws:iam::123456789012:role/AdministratorAccess is mapped to system:masters via aws-auth
CRITICAL
ServiceAccount/foothold-ops/foothold-execer
→
the system:masters group
score 8.4
3 hops
View finding →
ServiceAccount `foothold-execer` in namespace `foothold-ops` reaches the system:masters group in 3 hops via Pod exec → container takeover → Container escape to host → Control-plane PKI theft.
Step 1 of 3 Pod exec → container takeover pod_exec
The pods/exec subresource opens a shell inside a running container. If the container's pod uses a privileged ServiceAccount, the attacker inherits that SA's reach. If the container is itself privileged or mounts the host, this is also a node-escape primitive.
From ServiceAccount/foothold-ops/foothold-execer → ServiceAccount/foothold-fixtures/foothold-priv
Permission granted create pods/exec|pods/attach
Gives the attacker can exec into pods running as ServiceAccount foothold-fixtures/foothold-priv
Step 2 of 3 Container escape to host pod_host_escape
The pod is configured in a way that makes escaping to the underlying node trivial: privileged: true, hostPID, hostNetwork, or a sensitive hostPath mount (root, docker.sock, etc.). An attacker who controls the container reaches root on the node, then has access to every pod and kubelet credential on that node.
From ServiceAccount/foothold-fixtures/foothold-priv
Permission granted privileged
Gives the attacker runs in pod foothold-fixtures/foothold-priv-app-568f779db7-cmqmb with privileged
Step 3 of 3 Control-plane PKI theft control_plane_pki_theft
Root on a node is serious anywhere, but root on a control-plane node is game over. The cluster's certificate authority private key sits at /etc/kubernetes/pki/ca.key. With it an attacker signs a client certificate carrying O=system:masters entirely offline, and the API server accepts it because that group short-circuits authorization.
No RBAC object changes, so no audit event records the grant. Recovery means rotating the cluster CA, not merely deleting a binding.
From ServiceAccount/foothold-fixtures/foothold-priv
Permission granted root on a schedulable control-plane node
Gives the attacker can read /etc/kubernetes/pki/ca.key and forge an O=system:masters client certificate offline
HIGH
ServiceAccount/csr-fixtures/sa-csr-sign
→
the system:masters group
score 8.7
1 hop
View finding →
ServiceAccount `sa-csr-sign` in namespace `csr-fixtures` reaches the system:masters group in 1 hop via Signer control: issuing certs without approval.
Signer control: issuing certs without approval csr_sign
The sign verb on the signers resource plus update/patch on certificatesigningrequests/status is the authorization Kubernetes defines for being a certificate signer: the CertificateSigning admission plugin checks sign when a status write populates status.certificate. Where CSR self-approval asks the cluster's signer to issue a cert, this identity is the signer — no create, no /approval, and no approver anywhere in the chain.
For kubernetes.io/kube-apiserver-client that means issuing a client certificate for any identity the holder names. For the kubelet signers it means minting node identities (CN=system:node:<name>), which the Node authorizer accepts for every object bound to that node.
One condition decides urgency: a certificate only authenticates if it chains to a CA in the apiserver's --client-ca-file. This grant designates the holder as the signer, and a real signer holds that CA key by definition. So the question is whether this identity is supposed to be a certificate authority for cluster identities — true for the controller-manager or a purpose-built signer controller, never true for an application ServiceAccount.
From ServiceAccount/csr-fixtures/sa-csr-sign
Permission granted sign signers/kubernetes.io/kube-apiserver-client + update certificatesigningrequests/status
Gives the attacker is an authorized signer for apiserver client certificates and can issue one for any identity without an approval step
HIGH
ServiceAccount/cert-manager/cert-manager
→
the system:masters group
score 8.3
2 hops
View finding →
ServiceAccount `cert-manager` in namespace `cert-manager` reaches the system:masters group in 2 hops via Migrate pods onto an attacker node → Control-plane PKI theft.
Step 1 of 2 Migrate pods onto an attacker node node_drain_migrate
A way to remove pods (delete pods, deletecollection pods, or create pods/eviction) combined with cluster-scoped node control (update/patch on nodes, which is what kubectl cordon and kubectl taint use; update/patch on nodes/status; or delete nodes) lets an attacker cordon, taint, or remove every node except one they control, then evict a sensitive pod. The scheduler relocates the pod onto the attacker's node, where its ServiceAccount token and traffic are exposed.
From ServiceAccount/cert-manager/cert-manager
Permission granted delete pods + update nodes/status
Gives the attacker can migrate sensitive pods onto an attacker-controlled node via eviction + node manipulation
Step 2 of 2 Control-plane PKI theft control_plane_pki_theft
Root on a node is serious anywhere, but root on a control-plane node is game over. The cluster's certificate authority private key sits at /etc/kubernetes/pki/ca.key. With it an attacker signs a client certificate carrying O=system:masters entirely offline, and the API server accepts it because that group short-circuits authorization.
No RBAC object changes, so no audit event records the grant. Recovery means rotating the cluster CA, not merely deleting a binding.
From ServiceAccount/cert-manager/cert-manager
Permission granted root on a schedulable control-plane node
Gives the attacker can read /etc/kubernetes/pki/ca.key and forge an O=system:masters client certificate offline
HIGH
ServiceAccount/cloud-eks-test/default
→
the system:masters group
score 8.3
2 hops
View finding →
ServiceAccount `default` in namespace `cloud-eks-test` reaches the system:masters group in 2 hops via Steal node IAM role via IMDS → Control-plane PKI theft.
Step 1 of 2 Steal node IAM role via IMDS imds_node_role_pivot
EC2-backed EKS worker nodes attach an IAM role to the instance and expose its credentials at the link-local IMDS endpoint 169.254.169.254. Pods inherit the host's network unless a NetworkPolicy denies egress to that IP, so a compromised pod can curl IMDS, parse out the node-role credentials, and act in AWS as the node.
The node role is typically broader than any single workload's IRSA role: it can pull from ECR, describe EC2 instances, and is often given additional grants for cluster-autoscaler / EBS-CSI / external-dns. This is a credential-theft chain (SSRF to cloud creds) rather than a Kubernetes RBAC chain.
From ServiceAccount/cloud-eks-test/default
Permission granted IMDS reachable, IRSA unbound
Gives the attacker pod cloud-eks-test/imds-pivot-app-68cfbfc794-vhjw8 falls back to node IAM role via IMDS
Step 2 of 2 Control-plane PKI theft control_plane_pki_theft
Root on a node is serious anywhere, but root on a control-plane node is game over. The cluster's certificate authority private key sits at /etc/kubernetes/pki/ca.key. With it an attacker signs a client certificate carrying O=system:masters entirely offline, and the API server accepts it because that group short-circuits authorization.
No RBAC object changes, so no audit event records the grant. Recovery means rotating the cluster CA, not merely deleting a binding.
From ServiceAccount/cloud-eks-test/default
Permission granted root on a schedulable control-plane node
Gives the attacker can read /etc/kubernetes/pki/ca.key and forge an O=system:masters client certificate offline
HIGH
ServiceAccount/containersec-fixtures/default
→
the system:masters group
score 8.3
2 hops
View finding →
ServiceAccount `default` in namespace `containersec-fixtures` reaches the system:masters group in 2 hops via Steal node IAM role via IMDS → Control-plane PKI theft.
Step 1 of 2 Steal node IAM role via IMDS imds_node_role_pivot
EC2-backed EKS worker nodes attach an IAM role to the instance and expose its credentials at the link-local IMDS endpoint 169.254.169.254. Pods inherit the host's network unless a NetworkPolicy denies egress to that IP, so a compromised pod can curl IMDS, parse out the node-role credentials, and act in AWS as the node.
The node role is typically broader than any single workload's IRSA role: it can pull from ECR, describe EC2 instances, and is often given additional grants for cluster-autoscaler / EBS-CSI / external-dns. This is a credential-theft chain (SSRF to cloud creds) rather than a Kubernetes RBAC chain.
From ServiceAccount/containersec-fixtures/default
Permission granted IMDS reachable, IRSA unbound
Gives the attacker pod containersec-fixtures/containersec-image-64d6ddbdbd-zxw7f falls back to node IAM role via IMDS
Step 2 of 2 Control-plane PKI theft control_plane_pki_theft
Root on a node is serious anywhere, but root on a control-plane node is game over. The cluster's certificate authority private key sits at /etc/kubernetes/pki/ca.key. With it an attacker signs a client certificate carrying O=system:masters entirely offline, and the API server accepts it because that group short-circuits authorization.
No RBAC object changes, so no audit event records the grant. Recovery means rotating the cluster CA, not merely deleting a binding.
From ServiceAccount/containersec-fixtures/default
Permission granted root on a schedulable control-plane node
Gives the attacker can read /etc/kubernetes/pki/ca.key and forge an O=system:masters client certificate offline
HIGH
ServiceAccount/cutres/cutres-detour
→
the system:masters group
score 8.3
2 hops
View finding →
ServiceAccount `cutres-detour` in namespace `cutres` reaches the system:masters group in 2 hops via Migrate pods onto an attacker node → Control-plane PKI theft.
Step 1 of 2 Migrate pods onto an attacker node node_drain_migrate
A way to remove pods (delete pods, deletecollection pods, or create pods/eviction) combined with cluster-scoped node control (update/patch on nodes, which is what kubectl cordon and kubectl taint use; update/patch on nodes/status; or delete nodes) lets an attacker cordon, taint, or remove every node except one they control, then evict a sensitive pod. The scheduler relocates the pod onto the attacker's node, where its ServiceAccount token and traffic are exposed.
From ServiceAccount/cutres/cutres-detour
Permission granted delete pods + update nodes/status
Gives the attacker can migrate sensitive pods onto an attacker-controlled node via eviction + node manipulation
Step 2 of 2 Control-plane PKI theft control_plane_pki_theft
Root on a node is serious anywhere, but root on a control-plane node is game over. The cluster's certificate authority private key sits at /etc/kubernetes/pki/ca.key. With it an attacker signs a client certificate carrying O=system:masters entirely offline, and the API server accepts it because that group short-circuits authorization.
No RBAC object changes, so no audit event records the grant. Recovery means rotating the cluster CA, not merely deleting a binding.
From ServiceAccount/cutres/cutres-detour
Permission granted root on a schedulable control-plane node
Gives the attacker can read /etc/kubernetes/pki/ca.key and forge an O=system:masters client certificate offline
HIGH
ServiceAccount/cutres/cutres-parallel
→
the system:masters group
score 8.3
2 hops
View finding →
ServiceAccount `cutres-parallel` in namespace `cutres` reaches the system:masters group in 2 hops via Migrate pods onto an attacker node → Control-plane PKI theft.
Step 1 of 2 Migrate pods onto an attacker node node_drain_migrate
A way to remove pods (delete pods, deletecollection pods, or create pods/eviction) combined with cluster-scoped node control (update/patch on nodes, which is what kubectl cordon and kubectl taint use; update/patch on nodes/status; or delete nodes) lets an attacker cordon, taint, or remove every node except one they control, then evict a sensitive pod. The scheduler relocates the pod onto the attacker's node, where its ServiceAccount token and traffic are exposed.
From ServiceAccount/cutres/cutres-parallel
Permission granted delete pods + update nodes/status
Gives the attacker can migrate sensitive pods onto an attacker-controlled node via eviction + node manipulation
Step 2 of 2 Control-plane PKI theft control_plane_pki_theft
Root on a node is serious anywhere, but root on a control-plane node is game over. The cluster's certificate authority private key sits at /etc/kubernetes/pki/ca.key. With it an attacker signs a client certificate carrying O=system:masters entirely offline, and the API server accepts it because that group short-circuits authorization.
No RBAC object changes, so no audit event records the grant. Recovery means rotating the cluster CA, not merely deleting a binding.
From ServiceAccount/cutres/cutres-parallel
Permission granted root on a schedulable control-plane node
Gives the attacker can read /etc/kubernetes/pki/ca.key and forge an O=system:masters client certificate offline
HIGH
ServiceAccount/deepchain-tenant/deepchain-privileged
→
the system:masters group
score 8.3
2 hops
View finding →
ServiceAccount `deepchain-privileged` in namespace `deepchain-tenant` reaches the system:masters group in 2 hops via Migrate pods onto an attacker node → Control-plane PKI theft.
Step 1 of 2 Migrate pods onto an attacker node node_drain_migrate
A way to remove pods (delete pods, deletecollection pods, or create pods/eviction) combined with cluster-scoped node control (update/patch on nodes, which is what kubectl cordon and kubectl taint use; update/patch on nodes/status; or delete nodes) lets an attacker cordon, taint, or remove every node except one they control, then evict a sensitive pod. The scheduler relocates the pod onto the attacker's node, where its ServiceAccount token and traffic are exposed.
From ServiceAccount/deepchain-tenant/deepchain-privileged
Permission granted delete pods + update nodes/status
Gives the attacker can migrate sensitive pods onto an attacker-controlled node via eviction + node manipulation
Step 2 of 2 Control-plane PKI theft control_plane_pki_theft
Root on a node is serious anywhere, but root on a control-plane node is game over. The cluster's certificate authority private key sits at /etc/kubernetes/pki/ca.key. With it an attacker signs a client certificate carrying O=system:masters entirely offline, and the API server accepts it because that group short-circuits authorization.
No RBAC object changes, so no audit event records the grant. Recovery means rotating the cluster CA, not merely deleting a binding.
From ServiceAccount/deepchain-tenant/deepchain-privileged
Permission granted root on a schedulable control-plane node
Gives the attacker can read /etc/kubernetes/pki/ca.key and forge an O=system:masters client certificate offline
HIGH
ServiceAccount/flat-network/default
→
the system:masters group
score 8.3
2 hops
View finding →
ServiceAccount `default` in namespace `flat-network` reaches the system:masters group in 2 hops via Steal node IAM role via IMDS → Control-plane PKI theft.
Step 1 of 2 Steal node IAM role via IMDS imds_node_role_pivot
EC2-backed EKS worker nodes attach an IAM role to the instance and expose its credentials at the link-local IMDS endpoint 169.254.169.254. Pods inherit the host's network unless a NetworkPolicy denies egress to that IP, so a compromised pod can curl IMDS, parse out the node-role credentials, and act in AWS as the node.
The node role is typically broader than any single workload's IRSA role: it can pull from ECR, describe EC2 instances, and is often given additional grants for cluster-autoscaler / EBS-CSI / external-dns. This is a credential-theft chain (SSRF to cloud creds) rather than a Kubernetes RBAC chain.
From ServiceAccount/flat-network/default
Permission granted IMDS reachable, IRSA unbound
Gives the attacker pod flat-network/api-55d9f69c7d-ppr7v falls back to node IAM role via IMDS
Step 2 of 2 Control-plane PKI theft control_plane_pki_theft
Root on a node is serious anywhere, but root on a control-plane node is game over. The cluster's certificate authority private key sits at /etc/kubernetes/pki/ca.key. With it an attacker signs a client certificate carrying O=system:masters entirely offline, and the API server accepts it because that group short-circuits authorization.
No RBAC object changes, so no audit event records the grant. Recovery means rotating the cluster CA, not merely deleting a binding.
From ServiceAccount/flat-network/default
Permission granted root on a schedulable control-plane node
Gives the attacker can read /etc/kubernetes/pki/ca.key and forge an O=system:masters client certificate offline
HIGH
ServiceAccount/flux-system/kustomize-controller
→
the system:masters group
score 8.3
2 hops
View finding →
ServiceAccount `kustomize-controller` in namespace `flux-system` reaches the system:masters group in 2 hops via Migrate pods onto an attacker node → Control-plane PKI theft.
Step 1 of 2 Migrate pods onto an attacker node node_drain_migrate
A way to remove pods (delete pods, deletecollection pods, or create pods/eviction) combined with cluster-scoped node control (update/patch on nodes, which is what kubectl cordon and kubectl taint use; update/patch on nodes/status; or delete nodes) lets an attacker cordon, taint, or remove every node except one they control, then evict a sensitive pod. The scheduler relocates the pod onto the attacker's node, where its ServiceAccount token and traffic are exposed.
From ServiceAccount/flux-system/kustomize-controller
Permission granted delete pods + update nodes/status
Gives the attacker can migrate sensitive pods onto an attacker-controlled node via eviction + node manipulation
Step 2 of 2 Control-plane PKI theft control_plane_pki_theft
Root on a node is serious anywhere, but root on a control-plane node is game over. The cluster's certificate authority private key sits at /etc/kubernetes/pki/ca.key. With it an attacker signs a client certificate carrying O=system:masters entirely offline, and the API server accepts it because that group short-circuits authorization.
No RBAC object changes, so no audit event records the grant. Recovery means rotating the cluster CA, not merely deleting a binding.
From ServiceAccount/flux-system/kustomize-controller
Permission granted root on a schedulable control-plane node
Gives the attacker can read /etc/kubernetes/pki/ca.key and forge an O=system:masters client certificate offline
HIGH
ServiceAccount/foothold-exec/foothold-decoy-sa
→
the system:masters group
score 8.3
2 hops
View finding →
ServiceAccount `foothold-decoy-sa` in namespace `foothold-exec` reaches the system:masters group in 2 hops via Migrate pods onto an attacker node → Control-plane PKI theft.
Step 1 of 2 Migrate pods onto an attacker node node_drain_migrate
A way to remove pods (delete pods, deletecollection pods, or create pods/eviction) combined with cluster-scoped node control (update/patch on nodes, which is what kubectl cordon and kubectl taint use; update/patch on nodes/status; or delete nodes) lets an attacker cordon, taint, or remove every node except one they control, then evict a sensitive pod. The scheduler relocates the pod onto the attacker's node, where its ServiceAccount token and traffic are exposed.
From ServiceAccount/foothold-exec/foothold-decoy-sa
Permission granted delete pods + update nodes/status
Gives the attacker can migrate sensitive pods onto an attacker-controlled node via eviction + node manipulation
Step 2 of 2 Control-plane PKI theft control_plane_pki_theft
Root on a node is serious anywhere, but root on a control-plane node is game over. The cluster's certificate authority private key sits at /etc/kubernetes/pki/ca.key. With it an attacker signs a client certificate carrying O=system:masters entirely offline, and the API server accepts it because that group short-circuits authorization.
No RBAC object changes, so no audit event records the grant. Recovery means rotating the cluster CA, not merely deleting a binding.
From ServiceAccount/foothold-exec/foothold-decoy-sa
Permission granted root on a schedulable control-plane node
Gives the attacker can read /etc/kubernetes/pki/ca.key and forge an O=system:masters client certificate offline
HIGH
ServiceAccount/foothold-exec/foothold-reader
→
the system:masters group
score 8.3
2 hops
View finding →
ServiceAccount `foothold-reader` in namespace `foothold-exec` reaches the system:masters group in 2 hops via Steal node IAM role via IMDS → Control-plane PKI theft.
Step 1 of 2 Steal node IAM role via IMDS imds_node_role_pivot
EC2-backed EKS worker nodes attach an IAM role to the instance and expose its credentials at the link-local IMDS endpoint 169.254.169.254. Pods inherit the host's network unless a NetworkPolicy denies egress to that IP, so a compromised pod can curl IMDS, parse out the node-role credentials, and act in AWS as the node.
The node role is typically broader than any single workload's IRSA role: it can pull from ECR, describe EC2 instances, and is often given additional grants for cluster-autoscaler / EBS-CSI / external-dns. This is a credential-theft chain (SSRF to cloud creds) rather than a Kubernetes RBAC chain.
From ServiceAccount/foothold-exec/foothold-reader
Permission granted IMDS reachable, IRSA unbound
Gives the attacker pod foothold-exec/foothold-target falls back to node IAM role via IMDS
Step 2 of 2 Control-plane PKI theft control_plane_pki_theft
Root on a node is serious anywhere, but root on a control-plane node is game over. The cluster's certificate authority private key sits at /etc/kubernetes/pki/ca.key. With it an attacker signs a client certificate carrying O=system:masters entirely offline, and the API server accepts it because that group short-circuits authorization.
No RBAC object changes, so no audit event records the grant. Recovery means rotating the cluster CA, not merely deleting a binding.
From ServiceAccount/foothold-exec/foothold-reader
Permission granted root on a schedulable control-plane node
Gives the attacker can read /etc/kubernetes/pki/ca.key and forge an O=system:masters client certificate offline
HIGH
ServiceAccount/foothold-fixtures/foothold-quiet
→
the system:masters group
score 8.3
2 hops
View finding →
ServiceAccount `foothold-quiet` in namespace `foothold-fixtures` reaches the system:masters group in 2 hops via Steal node IAM role via IMDS → Control-plane PKI theft.
Step 1 of 2 Steal node IAM role via IMDS imds_node_role_pivot
EC2-backed EKS worker nodes attach an IAM role to the instance and expose its credentials at the link-local IMDS endpoint 169.254.169.254. Pods inherit the host's network unless a NetworkPolicy denies egress to that IP, so a compromised pod can curl IMDS, parse out the node-role credentials, and act in AWS as the node.
The node role is typically broader than any single workload's IRSA role: it can pull from ECR, describe EC2 instances, and is often given additional grants for cluster-autoscaler / EBS-CSI / external-dns. This is a credential-theft chain (SSRF to cloud creds) rather than a Kubernetes RBAC chain.
From ServiceAccount/foothold-fixtures/foothold-quiet
Permission granted IMDS reachable, IRSA unbound
Gives the attacker pod foothold-fixtures/foothold-quiet-app-749c54956-6w7wr falls back to node IAM role via IMDS
Step 2 of 2 Control-plane PKI theft control_plane_pki_theft
Root on a node is serious anywhere, but root on a control-plane node is game over. The cluster's certificate authority private key sits at /etc/kubernetes/pki/ca.key. With it an attacker signs a client certificate carrying O=system:masters entirely offline, and the API server accepts it because that group short-circuits authorization.
No RBAC object changes, so no audit event records the grant. Recovery means rotating the cluster CA, not merely deleting a binding.
From ServiceAccount/foothold-fixtures/foothold-quiet
Permission granted root on a schedulable control-plane node
Gives the attacker can read /etc/kubernetes/pki/ca.key and forge an O=system:masters client certificate offline
HIGH
ServiceAccount/gw-workloads/gw-web-sa
→
the system:masters group
score 8.3
2 hops
View finding →
ServiceAccount `gw-web-sa` in namespace `gw-workloads` reaches the system:masters group in 2 hops via Steal node IAM role via IMDS → Control-plane PKI theft.
Step 1 of 2 Steal node IAM role via IMDS imds_node_role_pivot
EC2-backed EKS worker nodes attach an IAM role to the instance and expose its credentials at the link-local IMDS endpoint 169.254.169.254. Pods inherit the host's network unless a NetworkPolicy denies egress to that IP, so a compromised pod can curl IMDS, parse out the node-role credentials, and act in AWS as the node.
The node role is typically broader than any single workload's IRSA role: it can pull from ECR, describe EC2 instances, and is often given additional grants for cluster-autoscaler / EBS-CSI / external-dns. This is a credential-theft chain (SSRF to cloud creds) rather than a Kubernetes RBAC chain.
From ServiceAccount/gw-workloads/gw-web-sa
Permission granted IMDS reachable, IRSA unbound
Gives the attacker pod gw-workloads/gw-web-78c47cbd6c-psgsw falls back to node IAM role via IMDS
Step 2 of 2 Control-plane PKI theft control_plane_pki_theft
Root on a node is serious anywhere, but root on a control-plane node is game over. The cluster's certificate authority private key sits at /etc/kubernetes/pki/ca.key. With it an attacker signs a client certificate carrying O=system:masters entirely offline, and the API server accepts it because that group short-circuits authorization.
No RBAC object changes, so no audit event records the grant. Recovery means rotating the cluster CA, not merely deleting a binding.
From ServiceAccount/gw-workloads/gw-web-sa
Permission granted root on a schedulable control-plane node
Gives the attacker can read /etc/kubernetes/pki/ca.key and forge an O=system:masters client certificate offline
HIGH
ServiceAccount/hookbackend-fixtures/default
→
the system:masters group
score 8.3
2 hops
View finding →
ServiceAccount `default` in namespace `hookbackend-fixtures` reaches the system:masters group in 2 hops via Steal node IAM role via IMDS → Control-plane PKI theft.
Step 1 of 2 Steal node IAM role via IMDS imds_node_role_pivot
EC2-backed EKS worker nodes attach an IAM role to the instance and expose its credentials at the link-local IMDS endpoint 169.254.169.254. Pods inherit the host's network unless a NetworkPolicy denies egress to that IP, so a compromised pod can curl IMDS, parse out the node-role credentials, and act in AWS as the node.
The node role is typically broader than any single workload's IRSA role: it can pull from ECR, describe EC2 instances, and is often given additional grants for cluster-autoscaler / EBS-CSI / external-dns. This is a credential-theft chain (SSRF to cloud creds) rather than a Kubernetes RBAC chain.
From ServiceAccount/hookbackend-fixtures/default
Permission granted IMDS reachable, IRSA unbound
Gives the attacker pod hookbackend-fixtures/hookbackend-injector-98b757bb8-2rtf4 falls back to node IAM role via IMDS
Step 2 of 2 Control-plane PKI theft control_plane_pki_theft
Root on a node is serious anywhere, but root on a control-plane node is game over. The cluster's certificate authority private key sits at /etc/kubernetes/pki/ca.key. With it an attacker signs a client certificate carrying O=system:masters entirely offline, and the API server accepts it because that group short-circuits authorization.
No RBAC object changes, so no audit event records the grant. Recovery means rotating the cluster CA, not merely deleting a binding.
From ServiceAccount/hookbackend-fixtures/default
Permission granted root on a schedulable control-plane node
Gives the attacker can read /etc/kubernetes/pki/ca.key and forge an O=system:masters client certificate offline
HIGH
ServiceAccount/imgswap-fixtures/imgswap-reader
→
the system:masters group
score 8.3
2 hops
View finding →
ServiceAccount `imgswap-reader` in namespace `imgswap-fixtures` reaches the system:masters group in 2 hops via Steal node IAM role via IMDS → Control-plane PKI theft.
Step 1 of 2 Steal node IAM role via IMDS imds_node_role_pivot
EC2-backed EKS worker nodes attach an IAM role to the instance and expose its credentials at the link-local IMDS endpoint 169.254.169.254. Pods inherit the host's network unless a NetworkPolicy denies egress to that IP, so a compromised pod can curl IMDS, parse out the node-role credentials, and act in AWS as the node.
The node role is typically broader than any single workload's IRSA role: it can pull from ECR, describe EC2 instances, and is often given additional grants for cluster-autoscaler / EBS-CSI / external-dns. This is a credential-theft chain (SSRF to cloud creds) rather than a Kubernetes RBAC chain.
From ServiceAccount/imgswap-fixtures/imgswap-reader
Permission granted IMDS reachable, IRSA unbound
Gives the attacker pod imgswap-fixtures/imgswap-reader-app-b5544c498-vrnqg falls back to node IAM role via IMDS
Step 2 of 2 Control-plane PKI theft control_plane_pki_theft
Root on a node is serious anywhere, but root on a control-plane node is game over. The cluster's certificate authority private key sits at /etc/kubernetes/pki/ca.key. With it an attacker signs a client certificate carrying O=system:masters entirely offline, and the API server accepts it because that group short-circuits authorization.
No RBAC object changes, so no audit event records the grant. Recovery means rotating the cluster CA, not merely deleting a binding.
From ServiceAccount/imgswap-fixtures/imgswap-reader
Permission granted root on a schedulable control-plane node
Gives the attacker can read /etc/kubernetes/pki/ca.key and forge an O=system:masters client certificate offline
HIGH
ServiceAccount/ingress-only/default
→
the system:masters group
score 8.3
2 hops
View finding →
ServiceAccount `default` in namespace `ingress-only` reaches the system:masters group in 2 hops via Steal node IAM role via IMDS → Control-plane PKI theft.
Step 1 of 2 Steal node IAM role via IMDS imds_node_role_pivot
EC2-backed EKS worker nodes attach an IAM role to the instance and expose its credentials at the link-local IMDS endpoint 169.254.169.254. Pods inherit the host's network unless a NetworkPolicy denies egress to that IP, so a compromised pod can curl IMDS, parse out the node-role credentials, and act in AWS as the node.
The node role is typically broader than any single workload's IRSA role: it can pull from ECR, describe EC2 instances, and is often given additional grants for cluster-autoscaler / EBS-CSI / external-dns. This is a credential-theft chain (SSRF to cloud creds) rather than a Kubernetes RBAC chain.
From ServiceAccount/ingress-only/default
Permission granted IMDS reachable, IRSA unbound
Gives the attacker pod ingress-only/ingress-app-7bdfc6c57-6t55d falls back to node IAM role via IMDS
Step 2 of 2 Control-plane PKI theft control_plane_pki_theft
Root on a node is serious anywhere, but root on a control-plane node is game over. The cluster's certificate authority private key sits at /etc/kubernetes/pki/ca.key. With it an attacker signs a client certificate carrying O=system:masters entirely offline, and the API server accepts it because that group short-circuits authorization.
No RBAC object changes, so no audit event records the grant. Recovery means rotating the cluster CA, not merely deleting a binding.
From ServiceAccount/ingress-only/default
Permission granted root on a schedulable control-plane node
Gives the attacker can read /etc/kubernetes/pki/ca.key and forge an O=system:masters client certificate offline
HIGH
ServiceAccount/lp-fixtures/sa-lp-narrow
→
the system:masters group
score 8.3
2 hops
View finding →
ServiceAccount `sa-lp-narrow` in namespace `lp-fixtures` reaches the system:masters group in 2 hops via Steal node IAM role via IMDS → Control-plane PKI theft.
Step 1 of 2 Steal node IAM role via IMDS imds_node_role_pivot
EC2-backed EKS worker nodes attach an IAM role to the instance and expose its credentials at the link-local IMDS endpoint 169.254.169.254. Pods inherit the host's network unless a NetworkPolicy denies egress to that IP, so a compromised pod can curl IMDS, parse out the node-role credentials, and act in AWS as the node.
The node role is typically broader than any single workload's IRSA role: it can pull from ECR, describe EC2 instances, and is often given additional grants for cluster-autoscaler / EBS-CSI / external-dns. This is a credential-theft chain (SSRF to cloud creds) rather than a Kubernetes RBAC chain.
From ServiceAccount/lp-fixtures/sa-lp-narrow
Permission granted IMDS reachable, IRSA unbound
Gives the attacker pod lp-fixtures/lp-narrow-app-6b8848bf64-jfqrj falls back to node IAM role via IMDS
Step 2 of 2 Control-plane PKI theft control_plane_pki_theft
Root on a node is serious anywhere, but root on a control-plane node is game over. The cluster's certificate authority private key sits at /etc/kubernetes/pki/ca.key. With it an attacker signs a client certificate carrying O=system:masters entirely offline, and the API server accepts it because that group short-circuits authorization.
No RBAC object changes, so no audit event records the grant. Recovery means rotating the cluster CA, not merely deleting a binding.
From ServiceAccount/lp-fixtures/sa-lp-narrow
Permission granted root on a schedulable control-plane node
Gives the attacker can read /etc/kubernetes/pki/ca.key and forge an O=system:masters client certificate offline
HIGH
ServiceAccount/lp-fixtures/sa-lp-orphan
→
the system:masters group
score 8.3
2 hops
View finding →
ServiceAccount `sa-lp-orphan` in namespace `lp-fixtures` reaches the system:masters group in 2 hops via Steal node IAM role via IMDS → Control-plane PKI theft.
Step 1 of 2 Steal node IAM role via IMDS imds_node_role_pivot
EC2-backed EKS worker nodes attach an IAM role to the instance and expose its credentials at the link-local IMDS endpoint 169.254.169.254. Pods inherit the host's network unless a NetworkPolicy denies egress to that IP, so a compromised pod can curl IMDS, parse out the node-role credentials, and act in AWS as the node.
The node role is typically broader than any single workload's IRSA role: it can pull from ECR, describe EC2 instances, and is often given additional grants for cluster-autoscaler / EBS-CSI / external-dns. This is a credential-theft chain (SSRF to cloud creds) rather than a Kubernetes RBAC chain.
From ServiceAccount/lp-fixtures/sa-lp-orphan
Permission granted IMDS reachable, IRSA unbound
Gives the attacker pod lp-fixtures/lp-orphan-app-68d649f6c5-qsjpw falls back to node IAM role via IMDS
Step 2 of 2 Control-plane PKI theft control_plane_pki_theft
Root on a node is serious anywhere, but root on a control-plane node is game over. The cluster's certificate authority private key sits at /etc/kubernetes/pki/ca.key. With it an attacker signs a client certificate carrying O=system:masters entirely offline, and the API server accepts it because that group short-circuits authorization.
No RBAC object changes, so no audit event records the grant. Recovery means rotating the cluster CA, not merely deleting a binding.
From ServiceAccount/lp-fixtures/sa-lp-orphan
Permission granted root on a schedulable control-plane node
Gives the attacker can read /etc/kubernetes/pki/ca.key and forge an O=system:masters client certificate offline
HIGH
ServiceAccount/lp-fixtures/sa-lp-wildcard
→
the system:masters group
score 8.3
2 hops
View finding →
ServiceAccount `sa-lp-wildcard` in namespace `lp-fixtures` reaches the system:masters group in 2 hops via Steal node IAM role via IMDS → Control-plane PKI theft.
Step 1 of 2 Steal node IAM role via IMDS imds_node_role_pivot
EC2-backed EKS worker nodes attach an IAM role to the instance and expose its credentials at the link-local IMDS endpoint 169.254.169.254. Pods inherit the host's network unless a NetworkPolicy denies egress to that IP, so a compromised pod can curl IMDS, parse out the node-role credentials, and act in AWS as the node.
The node role is typically broader than any single workload's IRSA role: it can pull from ECR, describe EC2 instances, and is often given additional grants for cluster-autoscaler / EBS-CSI / external-dns. This is a credential-theft chain (SSRF to cloud creds) rather than a Kubernetes RBAC chain.
From ServiceAccount/lp-fixtures/sa-lp-wildcard
Permission granted IMDS reachable, IRSA unbound
Gives the attacker pod lp-fixtures/lp-wildcard-app-7bb4d99f67-6ggf2 falls back to node IAM role via IMDS
Step 2 of 2 Control-plane PKI theft control_plane_pki_theft
Root on a node is serious anywhere, but root on a control-plane node is game over. The cluster's certificate authority private key sits at /etc/kubernetes/pki/ca.key. With it an attacker signs a client certificate carrying O=system:masters entirely offline, and the API server accepts it because that group short-circuits authorization.
No RBAC object changes, so no audit event records the grant. Recovery means rotating the cluster CA, not merely deleting a binding.
From ServiceAccount/lp-fixtures/sa-lp-wildcard
Permission granted root on a schedulable control-plane node
Gives the attacker can read /etc/kubernetes/pki/ca.key and forge an O=system:masters client certificate offline
HIGH
ServiceAccount/netpol-imds/default
→
the system:masters group
score 8.3
2 hops
View finding →
ServiceAccount `default` in namespace `netpol-imds` reaches the system:masters group in 2 hops via Steal node IAM role via IMDS → Control-plane PKI theft.
Step 1 of 2 Steal node IAM role via IMDS imds_node_role_pivot
EC2-backed EKS worker nodes attach an IAM role to the instance and expose its credentials at the link-local IMDS endpoint 169.254.169.254. Pods inherit the host's network unless a NetworkPolicy denies egress to that IP, so a compromised pod can curl IMDS, parse out the node-role credentials, and act in AWS as the node.
The node role is typically broader than any single workload's IRSA role: it can pull from ECR, describe EC2 instances, and is often given additional grants for cluster-autoscaler / EBS-CSI / external-dns. This is a credential-theft chain (SSRF to cloud creds) rather than a Kubernetes RBAC chain.
From ServiceAccount/netpol-imds/default
Permission granted IMDS reachable, IRSA unbound
Gives the attacker pod netpol-imds/imds-allow-app-7f9f6cb9df-k2q2n falls back to node IAM role via IMDS
Step 2 of 2 Control-plane PKI theft control_plane_pki_theft
Root on a node is serious anywhere, but root on a control-plane node is game over. The cluster's certificate authority private key sits at /etc/kubernetes/pki/ca.key. With it an attacker signs a client certificate carrying O=system:masters entirely offline, and the API server accepts it because that group short-circuits authorization.
No RBAC object changes, so no audit event records the grant. Recovery means rotating the cluster CA, not merely deleting a binding.
From ServiceAccount/netpol-imds/default
Permission granted root on a schedulable control-plane node
Gives the attacker can read /etc/kubernetes/pki/ca.key and forge an O=system:masters client certificate offline
HIGH
ServiceAccount/privesc-fixtures/sa-node-migrate
→
the system:masters group
score 8.3
2 hops
View finding →
ServiceAccount `sa-node-migrate` in namespace `privesc-fixtures` reaches the system:masters group in 2 hops via Migrate pods onto an attacker node → Control-plane PKI theft.
Step 1 of 2 Migrate pods onto an attacker node node_drain_migrate
A way to remove pods (delete pods, deletecollection pods, or create pods/eviction) combined with cluster-scoped node control (update/patch on nodes, which is what kubectl cordon and kubectl taint use; update/patch on nodes/status; or delete nodes) lets an attacker cordon, taint, or remove every node except one they control, then evict a sensitive pod. The scheduler relocates the pod onto the attacker's node, where its ServiceAccount token and traffic are exposed.
From ServiceAccount/privesc-fixtures/sa-node-migrate
Permission granted delete pods + update nodes/status
Gives the attacker can migrate sensitive pods onto an attacker-controlled node via eviction + node manipulation
Step 2 of 2 Control-plane PKI theft control_plane_pki_theft
Root on a node is serious anywhere, but root on a control-plane node is game over. The cluster's certificate authority private key sits at /etc/kubernetes/pki/ca.key. With it an attacker signs a client certificate carrying O=system:masters entirely offline, and the API server accepts it because that group short-circuits authorization.
No RBAC object changes, so no audit event records the grant. Recovery means rotating the cluster CA, not merely deleting a binding.
From ServiceAccount/privesc-fixtures/sa-node-migrate
Permission granted root on a schedulable control-plane node
Gives the attacker can read /etc/kubernetes/pki/ca.key and forge an O=system:masters client certificate offline
HIGH
ServiceAccount/pv-hostpath-fixtures/sa-pv-hostpath
→
the system:masters group
score 8.3
2 hops
View finding →
ServiceAccount `sa-pv-hostpath` in namespace `pv-hostpath-fixtures` reaches the system:masters group in 2 hops via Steal node IAM role via IMDS → Control-plane PKI theft.
Step 1 of 2 Steal node IAM role via IMDS imds_node_role_pivot
EC2-backed EKS worker nodes attach an IAM role to the instance and expose its credentials at the link-local IMDS endpoint 169.254.169.254. Pods inherit the host's network unless a NetworkPolicy denies egress to that IP, so a compromised pod can curl IMDS, parse out the node-role credentials, and act in AWS as the node.
The node role is typically broader than any single workload's IRSA role: it can pull from ECR, describe EC2 instances, and is often given additional grants for cluster-autoscaler / EBS-CSI / external-dns. This is a credential-theft chain (SSRF to cloud creds) rather than a Kubernetes RBAC chain.
From ServiceAccount/pv-hostpath-fixtures/sa-pv-hostpath
Permission granted IMDS reachable, IRSA unbound
Gives the attacker pod pv-hostpath-fixtures/pv-hostpath-app-5bb7f7676-zqvzl falls back to node IAM role via IMDS
Step 2 of 2 Control-plane PKI theft control_plane_pki_theft
Root on a node is serious anywhere, but root on a control-plane node is game over. The cluster's certificate authority private key sits at /etc/kubernetes/pki/ca.key. With it an attacker signs a client certificate carrying O=system:masters entirely offline, and the API server accepts it because that group short-circuits authorization.
No RBAC object changes, so no audit event records the grant. Recovery means rotating the cluster CA, not merely deleting a binding.
From ServiceAccount/pv-hostpath-fixtures/sa-pv-hostpath
Permission granted root on a schedulable control-plane node
Gives the attacker can read /etc/kubernetes/pki/ca.key and forge an O=system:masters client certificate offline
HIGH
ServiceAccount/rbac-fixtures/sa-cluster-admin
→
the system:masters group
score 8.3
2 hops
View finding →
ServiceAccount `sa-cluster-admin` in namespace `rbac-fixtures` reaches the system:masters group in 2 hops via Migrate pods onto an attacker node → Control-plane PKI theft.
Step 1 of 2 Migrate pods onto an attacker node node_drain_migrate
A way to remove pods (delete pods, deletecollection pods, or create pods/eviction) combined with cluster-scoped node control (update/patch on nodes, which is what kubectl cordon and kubectl taint use; update/patch on nodes/status; or delete nodes) lets an attacker cordon, taint, or remove every node except one they control, then evict a sensitive pod. The scheduler relocates the pod onto the attacker's node, where its ServiceAccount token and traffic are exposed.
From ServiceAccount/rbac-fixtures/sa-cluster-admin
Permission granted delete pods + update nodes/status
Gives the attacker can migrate sensitive pods onto an attacker-controlled node via eviction + node manipulation
Step 2 of 2 Control-plane PKI theft control_plane_pki_theft
Root on a node is serious anywhere, but root on a control-plane node is game over. The cluster's certificate authority private key sits at /etc/kubernetes/pki/ca.key. With it an attacker signs a client certificate carrying O=system:masters entirely offline, and the API server accepts it because that group short-circuits authorization.
No RBAC object changes, so no audit event records the grant. Recovery means rotating the cluster CA, not merely deleting a binding.
From ServiceAccount/rbac-fixtures/sa-cluster-admin
Permission granted root on a schedulable control-plane node
Gives the attacker can read /etc/kubernetes/pki/ca.key and forge an O=system:masters client certificate offline
HIGH
ServiceAccount/rbac-fixtures/sa-wildcard
→
the system:masters group
score 8.3
2 hops
View finding →
ServiceAccount `sa-wildcard` in namespace `rbac-fixtures` reaches the system:masters group in 2 hops via Migrate pods onto an attacker node → Control-plane PKI theft.
Step 1 of 2 Migrate pods onto an attacker node node_drain_migrate
A way to remove pods (delete pods, deletecollection pods, or create pods/eviction) combined with cluster-scoped node control (update/patch on nodes, which is what kubectl cordon and kubectl taint use; update/patch on nodes/status; or delete nodes) lets an attacker cordon, taint, or remove every node except one they control, then evict a sensitive pod. The scheduler relocates the pod onto the attacker's node, where its ServiceAccount token and traffic are exposed.
From ServiceAccount/rbac-fixtures/sa-wildcard
Permission granted delete pods + update nodes/status
Gives the attacker can migrate sensitive pods onto an attacker-controlled node via eviction + node manipulation
Step 2 of 2 Control-plane PKI theft control_plane_pki_theft
Root on a node is serious anywhere, but root on a control-plane node is game over. The cluster's certificate authority private key sits at /etc/kubernetes/pki/ca.key. With it an attacker signs a client certificate carrying O=system:masters entirely offline, and the API server accepts it because that group short-circuits authorization.
No RBAC object changes, so no audit event records the grant. Recovery means rotating the cluster CA, not merely deleting a binding.
From ServiceAccount/rbac-fixtures/sa-wildcard
Permission granted root on a schedulable control-plane node
Gives the attacker can read /etc/kubernetes/pki/ca.key and forge an O=system:masters client certificate offline
HIGH
ServiceAccount/secrets-bundle/cross-ns-reader
→
the system:masters group
score 8.3
2 hops
View finding →
ServiceAccount `cross-ns-reader` in namespace `secrets-bundle` reaches the system:masters group in 2 hops via Steal node IAM role via IMDS → Control-plane PKI theft.
Step 1 of 2 Steal node IAM role via IMDS imds_node_role_pivot
EC2-backed EKS worker nodes attach an IAM role to the instance and expose its credentials at the link-local IMDS endpoint 169.254.169.254. Pods inherit the host's network unless a NetworkPolicy denies egress to that IP, so a compromised pod can curl IMDS, parse out the node-role credentials, and act in AWS as the node.
The node role is typically broader than any single workload's IRSA role: it can pull from ECR, describe EC2 instances, and is often given additional grants for cluster-autoscaler / EBS-CSI / external-dns. This is a credential-theft chain (SSRF to cloud creds) rather than a Kubernetes RBAC chain.
From ServiceAccount/secrets-bundle/cross-ns-reader
Permission granted IMDS reachable, IRSA unbound
Gives the attacker pod secrets-bundle/cross-ns-consumer-6c945c9c9d-blz86 falls back to node IAM role via IMDS
Step 2 of 2 Control-plane PKI theft control_plane_pki_theft
Root on a node is serious anywhere, but root on a control-plane node is game over. The cluster's certificate authority private key sits at /etc/kubernetes/pki/ca.key. With it an attacker signs a client certificate carrying O=system:masters entirely offline, and the API server accepts it because that group short-circuits authorization.
No RBAC object changes, so no audit event records the grant. Recovery means rotating the cluster CA, not merely deleting a binding.
From ServiceAccount/secrets-bundle/cross-ns-reader
Permission granted root on a schedulable control-plane node
Gives the attacker can read /etc/kubernetes/pki/ca.key and forge an O=system:masters client certificate offline
HIGH
ServiceAccount/statusspoof-fixtures/default
→
the system:masters group
score 8.3
2 hops
View finding →
ServiceAccount `default` in namespace `statusspoof-fixtures` reaches the system:masters group in 2 hops via Steal node IAM role via IMDS → Control-plane PKI theft.
Step 1 of 2 Steal node IAM role via IMDS imds_node_role_pivot
EC2-backed EKS worker nodes attach an IAM role to the instance and expose its credentials at the link-local IMDS endpoint 169.254.169.254. Pods inherit the host's network unless a NetworkPolicy denies egress to that IP, so a compromised pod can curl IMDS, parse out the node-role credentials, and act in AWS as the node.
The node role is typically broader than any single workload's IRSA role: it can pull from ECR, describe EC2 instances, and is often given additional grants for cluster-autoscaler / EBS-CSI / external-dns. This is a credential-theft chain (SSRF to cloud creds) rather than a Kubernetes RBAC chain.
From ServiceAccount/statusspoof-fixtures/default
Permission granted IMDS reachable, IRSA unbound
Gives the attacker pod statusspoof-fixtures/statusspoof-api-ff8647558-st88g falls back to node IAM role via IMDS
Step 2 of 2 Control-plane PKI theft control_plane_pki_theft
Root on a node is serious anywhere, but root on a control-plane node is game over. The cluster's certificate authority private key sits at /etc/kubernetes/pki/ca.key. With it an attacker signs a client certificate carrying O=system:masters entirely offline, and the API server accepts it because that group short-circuits authorization.
No RBAC object changes, so no audit event records the grant. Recovery means rotating the cluster CA, not merely deleting a binding.
From ServiceAccount/statusspoof-fixtures/default
Permission granted root on a schedulable control-plane node
Gives the attacker can read /etc/kubernetes/pki/ca.key and forge an O=system:masters client certificate offline
HIGH
ServiceAccount/deepchain-tenant/deepchain-binder
→
the system:masters group
score 8.0
4 hops
View finding →
ServiceAccount `deepchain-binder` in namespace `deepchain-tenant` reaches the system:masters group in 4 hops via RoleBinding write access plus bind → Co-located ServiceAccount token theft → Migrate pods onto an attacker node → ….
Step 1 of 4 RoleBinding write access plus bind modify_role_binding
create/update/patch on rolebindings or clusterrolebindings lets the attacker bind themselves to a role, but not to any role. Kubernetes runs an escalation-prevention check on every binding write: the writer must already hold every permission the referenced role grants, or hold the bind verb on it, or the API server refuses the write and names the missing rules. The escalation reported here is the pair, a binding write held together with bind.
A binding write on its own still matters, it just is not escalation: the check passes for permissions the writer already holds, so they can hand their own privileges to other subjects. That is lateral spread and persistence, reported separately as a flat finding rather than as a path.
Scope matters. At cluster scope the reach is cluster-admin equivalent. Granted by a RoleBinding the reach is bounded to that one namespace — full namespace-admin, but the bound ClusterRole's verbs apply only inside the binding's namespace.
From ServiceAccount/deepchain-tenant/deepchain-binder
Permission granted create/update rolebindings + bind (cluster)roles
Gives the attacker can RoleBind itself to any ClusterRole within namespace deepchain-tenant, holding the `bind` verb that satisfies RBAC escalation prevention
Step 2 of 4 Co-located ServiceAccount token theft colocated_sa_token_theft
Administrative control over a namespace implies control over every identity inside it. Someone who can create RoleBindings in a namespace can create a pod that mounts any ServiceAccount there, exec into a pod already running as it, or read its token Secret directly.
This matters when a namespace hosts an identity more powerful than the namespace itself, for example a controller whose ClusterRoleBinding grants cluster-wide permissions. Namespace-admin then becomes a stepping stone rather than a boundary.
From ServiceAccount/deepchain-tenant/deepchain-binder → ServiceAccount/deepchain-tenant/deepchain-privileged
Permission granted namespace-admin in deepchain-tenant
Gives the attacker can steal the token of co-located ServiceAccount deepchain-tenant/deepchain-privileged
Step 3 of 4 Migrate pods onto an attacker node node_drain_migrate
A way to remove pods (delete pods, deletecollection pods, or create pods/eviction) combined with cluster-scoped node control (update/patch on nodes, which is what kubectl cordon and kubectl taint use; update/patch on nodes/status; or delete nodes) lets an attacker cordon, taint, or remove every node except one they control, then evict a sensitive pod. The scheduler relocates the pod onto the attacker's node, where its ServiceAccount token and traffic are exposed.
From ServiceAccount/deepchain-tenant/deepchain-privileged
Permission granted delete pods + update nodes/status
Gives the attacker can migrate sensitive pods onto an attacker-controlled node via eviction + node manipulation
Step 4 of 4 Control-plane PKI theft control_plane_pki_theft
Root on a node is serious anywhere, but root on a control-plane node is game over. The cluster's certificate authority private key sits at /etc/kubernetes/pki/ca.key. With it an attacker signs a client certificate carrying O=system:masters entirely offline, and the API server accepts it because that group short-circuits authorization.
No RBAC object changes, so no audit event records the grant. Recovery means rotating the cluster CA, not merely deleting a binding.
From ServiceAccount/deepchain-tenant/deepchain-privileged
Permission granted root on a schedulable control-plane node
Gives the attacker can read /etc/kubernetes/pki/ca.key and forge an O=system:masters client certificate offline
HIGH
ServiceAccount/foothold-ops/foothold-named-execer
→
the system:masters group
score 7.9
3 hops
View finding →
ServiceAccount `foothold-named-execer` in namespace `foothold-ops` reaches the system:masters group in 3 hops via Pod exec → container takeover → Steal node IAM role via IMDS → Control-plane PKI theft.
Step 1 of 3 Pod exec → container takeover pod_exec
The pods/exec subresource opens a shell inside a running container. If the container's pod uses a privileged ServiceAccount, the attacker inherits that SA's reach. If the container is itself privileged or mounts the host, this is also a node-escape primitive.
From ServiceAccount/foothold-ops/foothold-named-execer → ServiceAccount/foothold-exec/foothold-reader
Permission granted create pods/exec|pods/attach
Gives the attacker can exec into pods running as ServiceAccount foothold-exec/foothold-reader
Step 2 of 3 Steal node IAM role via IMDS imds_node_role_pivot
EC2-backed EKS worker nodes attach an IAM role to the instance and expose its credentials at the link-local IMDS endpoint 169.254.169.254. Pods inherit the host's network unless a NetworkPolicy denies egress to that IP, so a compromised pod can curl IMDS, parse out the node-role credentials, and act in AWS as the node.
The node role is typically broader than any single workload's IRSA role: it can pull from ECR, describe EC2 instances, and is often given additional grants for cluster-autoscaler / EBS-CSI / external-dns. This is a credential-theft chain (SSRF to cloud creds) rather than a Kubernetes RBAC chain.
From ServiceAccount/foothold-exec/foothold-reader
Permission granted IMDS reachable, IRSA unbound
Gives the attacker pod foothold-exec/foothold-target falls back to node IAM role via IMDS
Step 3 of 3 Control-plane PKI theft control_plane_pki_theft
Root on a node is serious anywhere, but root on a control-plane node is game over. The cluster's certificate authority private key sits at /etc/kubernetes/pki/ca.key. With it an attacker signs a client certificate carrying O=system:masters entirely offline, and the API server accepts it because that group short-circuits authorization.
No RBAC object changes, so no audit event records the grant. Recovery means rotating the cluster CA, not merely deleting a binding.
From ServiceAccount/foothold-exec/foothold-reader
Permission granted root on a schedulable control-plane node
Gives the attacker can read /etc/kubernetes/pki/ca.key and forge an O=system:masters client certificate offline
HIGH
ServiceAccount/imgswap-fixtures/imgswap-patcher
→
the system:masters group
score 7.9
3 hops
View finding →
ServiceAccount `imgswap-patcher` in namespace `imgswap-fixtures` reaches the system:masters group in 3 hops via Pod image swap: code injection into a running pod → Steal node IAM role via IMDS → Control-plane PKI theft.
Step 1 of 3 Pod image swap: code injection into a running pod pod_image_hijack
The API server keeps a pod's container image fields writable after the pod is running, and nothing in-tree checks who changed them. A subject with plain update or patch on pods can point a running container at an image it controls; the kubelet restarts that container with the new image inside the same pod, so the attacker's code inherits the pod's mounted ServiceAccount token, its securityContext, and any host access it had.
This is the same position pods/exec or an ephemeral container gives, reached through a write verb that edit-style roles and label-patching operators carry routinely. No workload controller reverts it: ReplicaSets, StatefulSets, and DaemonSets reconcile on labels and template hashes, not on the live image.
From ServiceAccount/imgswap-fixtures/imgswap-patcher → ServiceAccount/imgswap-fixtures/imgswap-reader
Permission granted get,list,patch pods
Gives the attacker can swap the container image of pods running as ServiceAccount imgswap-fixtures/imgswap-reader and run code inside them
Step 2 of 3 Steal node IAM role via IMDS imds_node_role_pivot
EC2-backed EKS worker nodes attach an IAM role to the instance and expose its credentials at the link-local IMDS endpoint 169.254.169.254. Pods inherit the host's network unless a NetworkPolicy denies egress to that IP, so a compromised pod can curl IMDS, parse out the node-role credentials, and act in AWS as the node.
The node role is typically broader than any single workload's IRSA role: it can pull from ECR, describe EC2 instances, and is often given additional grants for cluster-autoscaler / EBS-CSI / external-dns. This is a credential-theft chain (SSRF to cloud creds) rather than a Kubernetes RBAC chain.
From ServiceAccount/imgswap-fixtures/imgswap-reader
Permission granted IMDS reachable, IRSA unbound
Gives the attacker pod imgswap-fixtures/imgswap-reader-app-b5544c498-vrnqg falls back to node IAM role via IMDS
Step 3 of 3 Control-plane PKI theft control_plane_pki_theft
Root on a node is serious anywhere, but root on a control-plane node is game over. The cluster's certificate authority private key sits at /etc/kubernetes/pki/ca.key. With it an attacker signs a client certificate carrying O=system:masters entirely offline, and the API server accepts it because that group short-circuits authorization.
No RBAC object changes, so no audit event records the grant. Recovery means rotating the cluster CA, not merely deleting a binding.
From ServiceAccount/imgswap-fixtures/imgswap-reader
Permission granted root on a schedulable control-plane node
Gives the attacker can read /etc/kubernetes/pki/ca.key and forge an O=system:masters client certificate offline
HIGH
User/gw-deployer
→
the system:masters group
score 7.9
3 hops
View finding →
User `gw-deployer` reaches the system:masters group in 3 hops via Workload creation → ServiceAccount token theft → Steal node IAM role via IMDS → Control-plane PKI theft.
Step 1 of 3 Workload creation → ServiceAccount token theft workload_create_token_theft
A Deployment, DaemonSet, StatefulSet, Job, or CronJob carries a pod template, and its controller creates pods from that template. Whoever writes the template chooses the ServiceAccount the pods run as, and Kubernetes checks only that the ServiceAccount exists, not that the writer may use it.
So create on any of these kinds reaches exactly what create pods reaches: every ServiceAccount in the namespace (or in every namespace, for a cluster-wide grant). Removing create pods from a role while leaving create deployments changes nothing.
From User/gw-deployer → ServiceAccount/gw-workloads/gw-web-sa
Permission granted create deployments
Gives the attacker can create a workload whose pods run as ServiceAccount gw-workloads/gw-web-sa
Step 2 of 3 Steal node IAM role via IMDS imds_node_role_pivot
EC2-backed EKS worker nodes attach an IAM role to the instance and expose its credentials at the link-local IMDS endpoint 169.254.169.254. Pods inherit the host's network unless a NetworkPolicy denies egress to that IP, so a compromised pod can curl IMDS, parse out the node-role credentials, and act in AWS as the node.
The node role is typically broader than any single workload's IRSA role: it can pull from ECR, describe EC2 instances, and is often given additional grants for cluster-autoscaler / EBS-CSI / external-dns. This is a credential-theft chain (SSRF to cloud creds) rather than a Kubernetes RBAC chain.
From ServiceAccount/gw-workloads/gw-web-sa
Permission granted IMDS reachable, IRSA unbound
Gives the attacker pod gw-workloads/gw-web-78c47cbd6c-psgsw falls back to node IAM role via IMDS
Step 3 of 3 Control-plane PKI theft control_plane_pki_theft
Root on a node is serious anywhere, but root on a control-plane node is game over. The cluster's certificate authority private key sits at /etc/kubernetes/pki/ca.key. With it an attacker signs a client certificate carrying O=system:masters entirely offline, and the API server accepts it because that group short-circuits authorization.
No RBAC object changes, so no audit event records the grant. Recovery means rotating the cluster CA, not merely deleting a binding.
From ServiceAccount/gw-workloads/gw-web-sa
Permission granted root on a schedulable control-plane node
Gives the attacker can read /etc/kubernetes/pki/ca.key and forge an O=system:masters client certificate offline
HIGH
User/gw-patcher
→
the system:masters group
score 7.9
3 hops
View finding →
User `gw-patcher` reaches the system:masters group in 3 hops via Workload template rewrite → Steal node IAM role via IMDS → Control-plane PKI theft.
Step 1 of 3 Workload template rewrite workload_hijack
update or patch on an existing Deployment, DaemonSet, StatefulSet, or CronJob lets the writer change its pod template: the image, the command, and the ServiceAccount. The controller then rolls out pods from the new template on its own. The writer gains every ServiceAccount in that namespace, the same as create pods.
It can also give more than that. The rewritten pods keep the rest of the workload's spec, so a workload that already runs privileged or mounts the host (a CNI or log-shipper DaemonSet in kube-system, for example) hands that host access to the writer's code. A Job is not affected: its pod template cannot be changed after creation.
From User/gw-patcher → ServiceAccount/gw-workloads/gw-web-sa
Permission granted patch deployments
Gives the attacker can rewrite the pod template of Deployment gw-workloads/gw-web, whose pods run as ServiceAccount gw-workloads/gw-web-sa
Step 2 of 3 Steal node IAM role via IMDS imds_node_role_pivot
EC2-backed EKS worker nodes attach an IAM role to the instance and expose its credentials at the link-local IMDS endpoint 169.254.169.254. Pods inherit the host's network unless a NetworkPolicy denies egress to that IP, so a compromised pod can curl IMDS, parse out the node-role credentials, and act in AWS as the node.
The node role is typically broader than any single workload's IRSA role: it can pull from ECR, describe EC2 instances, and is often given additional grants for cluster-autoscaler / EBS-CSI / external-dns. This is a credential-theft chain (SSRF to cloud creds) rather than a Kubernetes RBAC chain.
From ServiceAccount/gw-workloads/gw-web-sa
Permission granted IMDS reachable, IRSA unbound
Gives the attacker pod gw-workloads/gw-web-78c47cbd6c-psgsw falls back to node IAM role via IMDS
Step 3 of 3 Control-plane PKI theft control_plane_pki_theft
Root on a node is serious anywhere, but root on a control-plane node is game over. The cluster's certificate authority private key sits at /etc/kubernetes/pki/ca.key. With it an attacker signs a client certificate carrying O=system:masters entirely offline, and the API server accepts it because that group short-circuits authorization.
No RBAC object changes, so no audit event records the grant. Recovery means rotating the cluster CA, not merely deleting a binding.
From ServiceAccount/gw-workloads/gw-web-sa
Permission granted root on a schedulable control-plane node
Gives the attacker can read /etc/kubernetes/pki/ca.key and forge an O=system:masters client certificate offline