Role based access control in Kubernetes decides who can do what inside a cluster, and a single loose rule can hand a small workload the keys to everything. A Kubernetes RBAC misconfiguration is rarely a typo you notice right away. It is a Role that grants more than it should, a binding pointed at the wrong account, or a wildcard nobody trimmed, and it usually stays quiet until someone maps out what that access really allows.
How a Kubernetes RBAC misconfiguration actually happens
RBAC in Kubernetes is built from four object types. A Role or ClusterRole lists permissions. A RoleBinding or ClusterRoleBinding attaches that list to a subject, which is a user, a group, or a service account. The permission itself is a set of verbs like get, list, create, or delete over a set of resources like pods or secrets. Nothing here is dangerous on its own. The trouble starts when the list is wider than the job in front of it.
Three habits cause most of the damage. People copy an example that uses wildcards and never narrow it. People bind a strong role to an account that many pods already share. People grant a verb that looks harmless but opens a side door. Each one is easy to write and hard to spot later.
Wildcard verbs and resources
The fastest way to over grant is a wildcard. A rule with verbs: ["*"] and resources: ["*"] means every action on every object the API server knows about. That includes secrets, deployments, and the RBAC objects themselves, so the subject can even rewrite its own permissions. A wildcard reads as convenience while you are writing it. It reads as full control to anyone who lands on that subject later.
Binding a strong ClusterRole to a default account
Every namespace ships with a service account named default. If a pod does not name an account, it runs as that one. So when someone binds a strong ClusterRole to the default account, every pod in that namespace that never set an account quietly gains those rights. The binding was meant for one workload. It landed on all of them.
Granting create on pods
Permission to create pods sounds like a scheduling detail. It is more than that. A subject who can create a pod can mount any secret in the namespace into that pod and read it, or set a service account on the pod to run as a stronger identity. Create on pods, combined with access to secrets or a privileged account, is a common step from a small foothold to a much larger one.
Broad access to secrets
Secrets hold database passwords, API tokens, and TLS keys. A rule that grants get and list on secrets across a namespace, or worse across the cluster, means the subject can read all of them. Once those values are out, tightening the RBAC rule later does not put them back.
Namespaced Roles versus cluster wide ClusterRoles
The scope of a rule matters as much as its verbs. A Role lives in one namespace and only grants rights inside that namespace. A ClusterRole is cluster wide, and when it is attached with a ClusterRoleBinding it applies in every namespace at once. The same permission list is contained in the first case and cluster wide in the second.
A useful trick is to bind a ClusterRole with a namespaced RoleBinding. You reuse the permission list but keep its effect inside one namespace. Reach for a ClusterRoleBinding only when a subject genuinely needs to act in every namespace, and treat every one you write as something to justify out loud.
A loose RoleBinding and its tightened version
Here is a Role and binding that reads fine in review and grants far too much. It uses wildcards and points at the default account.
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: payments
name: worker-role
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["*"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
namespace: payments
name: worker-binding
subjects:
- kind: ServiceAccount
name: default
namespace: payments
roleRef:
kind: Role
name: worker-role
apiGroup: rbac.authorization.k8s.io
Any pod in payments that did not set its own account now has every verb on every resource, secrets included. Now the tightened version. It names a dedicated account, lists only the verbs the worker needs, and scopes to the two resources it touches.
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: payments
name: worker-role
rules:
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list"]
- apiGroups: ["batch"]
resources: ["jobs"]
verbs: ["get", "list", "create"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
namespace: payments
name: worker-binding
subjects:
- kind: ServiceAccount
name: payments-worker
namespace: payments
roleRef:
kind: Role
name: worker-role
apiGroup: rbac.authorization.k8s.io
The second version tells you exactly what the worker can do. No wildcards, no secrets, no shared account. If that pod is ever taken over, the blast radius is two resource types in one namespace.
Why this is a reachability question
Every pod gets a service account token mounted inside it by default. That token is a live credential for whatever the pod’s account is allowed to do. So a workload token plus a broad binding is a direct path to more access. An attacker who lands in a pod does not need a new exploit. They read the token, ask the API server what it can do, and follow the bindings.
Who can do what in a cluster is not a list you read once. It is a graph you walk, from a token, through a binding, to a role, out to every resource that role can touch.
That is why RBAC review is a reachability problem, not a checklist. The question is not whether one Role looks fine on its own. The question is what the whole chain allows once you start from an account an attacker can reach. This is a close cousin to how service account tokens get abused, covered in Kubernetes service account token abuse, and it rhymes with cloud IAM, where the same graph walk appears in IAM privilege escalation.
How to keep RBAC tight
- Grant least privilege. Start from zero and add only the verbs and resources a workload actually uses. It is easier to add a permission later than to notice an extra one.
- Ban wildcards. Treat
verbs: ["*"]orresources: ["*"]as a review blocker. Name every verb and every resource. - Scope to a namespace. Prefer a
Roleand aRoleBindingover cluster wide grants. Use aClusterRoleBindingonly when the need is genuinely cluster wide. - Never bind to the default account. Give each workload its own named service account, and turn off token mounting where a pod needs no API access.
- Audit bindings on a schedule. List every binding, follow each to its role, and ask who can read secrets or create pods. Fold that check into your CI CD pipeline security so a loose grant fails the build instead of shipping.
Reasoning about the full RBAC graph, from a reachable account to every resource it can touch, is exactly the kind of assumption testing an autonomous researcher is built to do, since the bug is not a bad pattern but a chain nobody traced. You can read how we think about that on our about page, and find more of these breakdowns in deep dives.
Frequently asked questions
What is a Kubernetes RBAC misconfiguration?
It is an RBAC rule that grants more access than a subject needs. Common cases are a Role or ClusterRole with wildcard verbs or resources, a strong ClusterRole bound to the default service account, or broad read access to secrets. Each one looks fine in isolation but widens what a pod can reach once its token is used.
Why is binding a ClusterRole to the default service account dangerous?
Every namespace has a service account named default, and any pod that does not name an account runs as it. If a strong ClusterRole is bound to that account, every such pod silently gains those rights. A grant meant for one workload ends up applying to all of them, which is why each workload should use its own named account.
What is the difference between a Role and a ClusterRole?
A Role lives in one namespace and only grants rights inside it. A ClusterRole is cluster wide, and when attached with a ClusterRoleBinding it applies in every namespace at once. You can bind a ClusterRole with a namespaced RoleBinding to reuse its permission list while keeping the effect inside a single namespace.
How do I audit RBAC for over permissive access?
List every RoleBinding and ClusterRoleBinding, follow each to its role, and ask who can read secrets, create pods, or use wildcards. Treat cluster wide bindings and any * in verbs or resources as items to justify. Reasoning over the full RBAC graph from a reachable account to the resources it can touch is the reliable way to spot escalation paths.
Put an autonomous researcher on your own systems
UnboundCompute is an autonomous security researcher that reasons about how an application fits together and proves the access control and injection bugs it finds. We are opening a small number of founding design partner seats: private early access pointed at a staging target you choose, and a say in what it looks for. If your team ships software worth pressure testing, apply to the design partner program.
