Kubernetes security: the most exploited mistakes and how to audit a cluster
By Kike Gandia · Co-Founder & CEO, OSCP
Kubernetes is not insecure, but its defaults put getting things working ahead of isolating them: pods talk to each other without restriction, secrets are stored unencrypted in etcd and audit logging does not switch itself on. Add broad RBAC permissions and privileged pods, and a vulnerability in a single application can end in control of the cluster and, on a managed service, of part of the cloud account. This guide covers the most exploited mistakes, what changes on EKS, AKS and GKE, and how a cluster is audited both against a baseline and from an attacker's point of view.
Why a Kubernetes cluster is a different kind of target
A Kubernetes cluster is, above all, an API. Whoever controls the API server controls every workload, every secret and often the cloud credentials the nodes work with. That is why an attacker's goal is usually not the application itself but using it as a way into the control plane.
There are three usual starting points:
- From outside: an API server, an admin dashboard or the kubelet port exposed to the internet with weak or no authentication.
- From a compromised container: a remote code execution flaw in an application gives a shell inside a pod. From there the attacker tries the service account token, the internal network, the cloud metadata service and the chance of escaping to the node.
- From the delivery chain: a kubeconfig on a developer's laptop or the CI/CD pipeline's credentials, which usually have permission to deploy anything.
The case that made it famous was Tesla in 2018: according to RedLock's research team, attackers got into a Kubernetes console that was not password protected, found AWS credentials in a pod with access to an S3 bucket and used the cluster to mine cryptocurrency.
For years the official documentation summed up security in four layers, the “4Cs”: cloud, cluster, container and code. The English documentation now organises it by lifecycle phase (develop, distribute, deploy and runtime), but the underlying idea still holds: each layer depends on the one below, and a well-hardened cluster on a weak cloud account is not secure.
The most exploited mistakes at a glance
| Mistake | Why it is serious | How it is detected |
|---|---|---|
| Excessive RBAC | Service accounts or users with permissions equivalent to cluster admin | Review of roles and bindings, analysis of who can do what |
| Privileged pods or host access | A compromised container escapes to the node and, from there, to other pods | Pod Security Admission, admission policies, CIS Benchmark |
| Network without NetworkPolicies | A compromised pod reaches databases, internal APIs and the control plane | Policy review and a reachability test from a pod |
| Unencrypted or misplaced secrets | Whoever reads etcd, a backup or a repository gets credentials | API server configuration, review of manifests and repositories |
| Pods reaching the node's cloud role | A shell in a pod turns into cloud account credentials | Testing the metadata service from a pod |
| Exposed components | API server, dashboards or kubelet reachable without proper authentication | External scanning and configuration review |
| Vulnerable or retired components | An ingress controller or an image with critical flaws gives access to the cluster | Version inventory and image scanning |
| No audit logging | No way of knowing what an attacker did or of detecting it in time | API server or managed service configuration |
The following sections explain each block and what to check.
RBAC: the permissions that amount to being an admin
Kubernetes role-based access control (RBAC) is powerful, but some permissions that look narrow allow escalation. The project's own RBAC good practices guide lists them:
| Permission | Why it is dangerous |
|---|---|
| get, list or watch on secrets | Listing or watching secrets also reveals their contents, not just their names |
| Creating pods or resources that manage them (deployments, jobs…) | Grants implicit access to the namespace's secrets, ConfigMaps and service accounts; a privileged pod reaches the node |
| Creating persistent volumes | Allows mounting node paths (hostPath) and reading its file system |
| get on nodes/proxy | Not read-only: it allows running commands in the node's pods while bypassing auditing and admission control |
| escalate and bind verbs | Allow creating or binding roles with permissions the user does not have |
| impersonate verb | Allows acting as another user or service account |
| Approving certificate signing requests (CSRs) | Allows issuing client certificates with arbitrary names, including those of system components |
| Creating service account tokens | Allows obtaining tokens for existing service accounts, with their permissions |
| Managing admission webhooks | Whoever controls them can read and modify the objects created in the cluster |
| Modifying namespaces | Changing their labels can switch off the Pod Security level or change what network policies apply to |
On top of that come the configuration mistakes that keep appearing in reviews:
- cluster-admin bound to an application's service account or to the deployment pipeline's user “to make it work”.
- Wildcards in verbs or resources (*), which also grant whatever is added in the future.
- The service account token mounted in every pod, even when the application never calls the API server. It is the first thing anyone who gets a shell in a pod tries.
- Roles inherited from tools —operators, dashboards, monitoring agents— installed with broad permissions and never reviewed.
The basic check is to ask the cluster itself what each identity can do, starting with the service accounts of internet-facing applications.
Pod security: privileges, Pod Security Standards and admission
A container is not a virtual machine: it shares the kernel with the node. Some configuration options break whatever isolation is left:
- privileged: true: the container has practically the same permissions as a root process on the node.
- hostPath: mounts node directories inside the container; depending on the path, it allows reading kubelet credentials or writing to the system.
- hostNetwork, hostPID or hostIPC: the container sees the node's network, processes or shared memory.
- Added Linux capabilities, such as SYS_ADMIN, and the ability to escalate privileges inside the container.
- Running as root without needing to.
To prevent this systematically, Kubernetes defines three levels, the Pod Security Standards:
| Level | What it allows | When to use it |
|---|---|---|
| Privileged | Unrestricted | Only system components that need it, such as some network or storage agents |
| Baseline | Minimal restrictions that prevent known privilege escalations | The reasonable minimum for any application |
| Restricted | Heavy restrictions, following current pod hardening best practices | The target for your own applications |
They are applied with Pod Security Admission, stable since Kubernetes 1.25, through labels on each namespace with three modes: enforce (reject), audit (log) and warn (notify). Its predecessor, PodSecurityPolicy, was removed in that same version: a cluster that relied on it and was upgraded without replacing it may have lost its controls without anyone noticing. For finer-grained rules —allowed image registries, mandatory labels, resource limits— policy engines such as Kyverno or OPA Gatekeeper are used.
Networking: by default, everything talks to everything
The official documentation is explicit: by default, a pod is not isolated and accepts all inbound connections, and the same applies to outbound traffic. NetworkPolicies change that, with an important caveat: they only work if the cluster's network plugin (CNI) implements them. Creating a policy in a cluster whose CNI does not support them has no effect at all.
Without network policies, a compromised pod can:
- Connect to the databases, caches and queues of any namespace.
- Call internal APIs designed on the assumption that only other trusted services would use them.
- Reach the cloud provider's metadata service and other node services.
- Go out to the internet to download tools or exfiltrate data.
The recommended pattern is to deny everything by default in each namespace and open only the flows that are needed, including egress: most applications have no need to reach the metadata service or the internet.
The ingress controller deserves separate attention, because it receives internet traffic and usually has broad permissions. In March 2025 the project published CVE-2025-1974 in ingress-nginx, with a CVSS score of 9.8: according to the official Kubernetes blog, anything on the pod network had a good chance of taking over the cluster with no credentials, partly because ingress-nginx has access to all secrets by default. Its retirement was announced in November 2025, and maintenance ended in March 2026: if your cluster still uses it, it will no longer receive security patches and you should plan the migration, for example to a Gateway API implementation.
Secrets: base64 is not encryption
The Kubernetes Secret object gives a false sense of protection. The official documentation makes three points clear:
- By default, secrets are stored unencrypted in etcd, the API server's data store. Anyone with access to etcd or one of its backups can read them.
- Base64 encoding provides no confidentiality. It only obscures them so they cannot be read at a glance.
- Anyone who can create a pod in a namespace can read every secret in that namespace, even without direct permission on them: mounting them in a pod they control is enough.
What to review:
| Aspect | What to check |
|---|---|
| Encryption at rest | On self-managed clusters, that the API server starts with an encryption configuration (EncryptionConfiguration), ideally with a KMS provider; on managed services, what encryption the provider applies and whether you can use your own key |
| Access to secrets | Who has get, list or watch on secrets and who can create pods in each namespace |
| Secrets outside the cluster | Plain-text values in manifests, Helm values files, Git repositories or container images |
| Environment variables | Secrets injected as variables, which end up in crash dumps and diagnostic tools |
| External manager | Whether a cloud or third-party secrets manager with rotation is used instead of copying values into the cluster |
In practice, the most exposed secrets are not in etcd but in the deployment repository: a values file with the database password, committed to Git two years ago and never rotated.
Managed Kubernetes: EKS, AKS and GKE
On a managed service, the provider takes care of the control plane: the API server, etcd and their availability. Everything else is still yours: node configuration, RBAC, workloads, network policies, secrets and, above all, the bridge between Kubernetes identities and cloud identities.
That bridge is the most exploited point. A node has a cloud role or identity to do its job; if a pod can reach the node's metadata service, it can obtain those credentials. The EKS best practices guide warns about this explicitly and recommends requiring IMDSv2 with a hop limit of 1 so pods cannot reach it. Watch the defaults: in managed node groups the limit is 2, which lets pods through; EKS Auto Mode, by contrast, enforces a limit of 1.
The right alternative is to give each application its own cloud identity, tied to its Kubernetes service account:
| Service | Per-workload identity | What to review |
|---|---|---|
| Amazon EKS | IAM Roles for Service Accounts (IRSA) or EKS Pod Identity | Pod access to the node's metadata service and the permissions of each associated role |
| Azure AKS | Microsoft Entra Workload ID | That no configuration remains from the old pod-managed identity, now retired |
| Google GKE | Workload Identity Federation for GKE | That the GKE metadata server is enabled, so pods cannot reach the Compute Engine one |
Two other EKS details that come up often in reviews: control plane logs, including the audit log, are not sent to CloudWatch by default, and the API server endpoint is public by default, protected by IAM and RBAC. Neither is a flaw in itself, but both should be conscious decisions.
Monitoring, versions and images
Three areas nobody notices until they are needed:
- Audit logging. On a self-managed cluster, if the API server does not start with an audit policy (--audit-policy-file), no events are logged. On managed services it has to be enabled and sent somewhere someone reviews it. Without it, there is no way of knowing what an attacker did with a stolen token.
- Versions. The project maintains the three most recent minor versions, each for roughly 14 months. An out-of-support cluster stops receiving security patches, and the same goes for its add-ons: ingress controllers, CNIs, operators and Helm charts installed years ago.
- Images. Most known vulnerabilities in a cluster are not in Kubernetes but in the images it runs. The sensible approach is minimal base images, scanning in the pipeline and in the registry, pinning by digest rather than by tag, and an admission policy limiting which registries can be deployed from.
The security of the pipeline that builds and deploys those images is a topic of its own: if an attacker controls the CI/CD, they control what runs in the cluster. We cover it in the resource on CI/CD pipeline pentesting.
How a Kubernetes cluster is audited
A complete audit combines two perspectives: configuration against a baseline and behaviour against an attacker.
| Test | Question it answers | How it is done |
|---|---|---|
| CIS baseline | Do the control plane, nodes and policies follow the recommendations? | CIS Kubernetes Benchmark (and its EKS, AKS and GKE variants) with kube-bench |
| Cluster posture | Which workloads break good practice? | Scanners such as Kubescape (a CNCF incubating project) or Trivy, which also scans images |
| RBAC analysis | Who can do what, and who can escalate? | Review of roles and bindings, kubectl auth can-i per identity, permission graph tools |
| External surface | What is visible from the internet? | Discovery of API servers, dashboards, kubelet ports, ingress and LoadBalancer or NodePort services |
| Compromised pod | How far does an attacker get with a shell in an application? | From a test pod: service account token, internal network, cloud metadata, node escape, secrets |
| Bridge to the cloud | What does whoever controls a pod or a node get in the cloud account? | Effective permissions of node roles and per-workload identities |
The first two rows automate well and should run continuously. The last four are the ones that find the paths that end in an incident, because they depend on combining findings: an application with a flaw, a service account with too many permissions, a pod that reaches the metadata service and a node role that can read every bucket.
A word on tools: kube-hunter, widely cited in older guides, is no longer actively developed and its own repository recommends Trivy. And no tool replaces testing from a compromised pod, which is the one that answers the question that matters.
FAQ
Is Kubernetes insecure by default?
Not exactly, but its defaults favour functionality: pods are not network-isolated, secrets are stored unencrypted in etcd and audit logging does not switch itself on. A freshly created cluster is fine to start working with, not for production with sensitive data until it is hardened.
Are Kubernetes Secrets encrypted?
Not by default: they are stored unencrypted in etcd and base64 encoding provides no confidentiality. You need to enable encryption at rest on the API server or check what the managed service offers, limit who can read them or create pods and, preferably, use an external secrets manager with rotation.
What replaces PodSecurityPolicy?
Pod Security Admission, which applies the Pod Security Standards (Privileged, Baseline and Restricted) through labels on each namespace and has been stable since Kubernetes 1.25, the same version in which PodSecurityPolicy was removed. For more specific rules it is complemented by policy engines such as Kyverno or OPA Gatekeeper.
If we use EKS, AKS or GKE, is cluster security the provider's job?
Only the control plane's. RBAC, pod configuration, network policies, secrets, images and the relationship between Kubernetes and cloud identities remain your responsibility, and that is where most incidents happen.
Is running kube-bench or a posture scanner enough?
It is a good starting point and should run continuously, but it is not enough. Those tools compare configuration against rules; they do not check what an attacker can do by chaining a vulnerable application, an over-privileged service account and access to the node's cloud role. That needs offensive testing from a compromised pod.
We still use ingress-nginx: what should we do?
Plan the migration as soon as possible. The project was retired in March 2026 and no longer receives security patches, after a critical 2025 vulnerability that allowed taking over the cluster from the pod network. The alternative the project recommends is Gateway API, through one of its implementations, or another maintained ingress controller.
Related service
cloud penetration testing, including EKS, AKS and GKE clusters
Related content
- The most common cloud misconfigurations
- AWS penetration testing: what is tested and what AWS allows
- CSPM vs cloud penetration testing
- CI/CD pipeline pentesting
- DevSecOps: offensive security in development
- Internal ethical hacking: the attacker-inside scenario