Attackers bypass a Kubernetes admission controller by reaching the API in a way the policy never evaluates: a webhook set to failurePolicy Ignore that is down or slow, a namespaceSelector or objectSelector that excludes the namespace or label they use, an operation or subresource the webhook’s rules do not match, or RBAC that lets them read, edit or delete the webhook configuration itself. Pwned Labs teaches both sides of this, writing admission policy and breaking it, hands-on in live clusters through Academy labs and the Kubernetes Attack and Defense bootcamp that leads to the KRTP certification.
What is a Kubernetes admission controller?
A Kubernetes admission controller sits in the API request path after authentication and authorization, and decides whether an object may be created, updated or deleted before it is written to etcd. Requests pass through mutating admission first, then object schema validation, then validating admission, so a mutating step can change an object and a later validating step can still reject it. Some controllers are built in and compiled into the API server. The ones defenders usually configure are dynamic: validating and mutating admission webhooks, which call out to a service, and the newer in-tree ValidatingAdmissionPolicy, which runs CEL expressions inside the API server and reached general availability in Kubernetes 1.30. If the concept is new, start with the admission controller glossary entry; this post is about the ways attackers slip past one, and the Pwned Labs Kubernetes Attack and Defense bootcamp drills each of them in a live cluster.
What are the built-in admission controllers?
Built-in controllers are compiled into the API server and turned on with the enable-admission-plugins flag. Common ones include NamespaceLifecycle, LimitRanger, ServiceAccount, DefaultStorageClass, ResourceQuota, and the two that run webhooks, MutatingAdmissionWebhook and ValidatingAdmissionWebhook. The security-relevant built-in is Pod Security Admission, which replaced PodSecurityPolicy after PodSecurityPolicy was removed in Kubernetes 1.25. Pod Security Admission is not configured with RBAC rules; it is driven by namespace labels such as pod-security.kubernetes.io/enforce. That design is also its bypass: a subject who can create or relabel a namespace can set a weaker enforce level, or land a workload in a namespace that was never labelled, and the restricted standard simply does not apply. Built-in controllers cannot be deleted by a cluster user the way a webhook configuration can, but their reach still depends on how they are enabled and, for Pod Security Admission, on who controls namespace labels.
How do attackers bypass admission control?
Bypasses fall into a few repeatable classes, and almost none of them are software vulnerabilities. They are the control not running, not matching, or being reachable by the attacker:
- Fail-open webhooks. A webhook with failurePolicy Ignore admits the request whenever the webhook errors or times out, so an outage, a single-replica backend, or a webhook an attacker can overload becomes a silent gap.
- Selector and namespace gaps. A namespaceSelector or objectSelector that excludes a namespace or a label, often added so the webhook does not break the control plane, is a door: deploy into the excluded namespace or set the excluded label.
- Scope gaps. A webhook’s rules match specific apiGroups, apiVersions, resources and operations. A request that uses a different API version mapping to the same resource, a subresource, or an operation the rules omit, is never evaluated. matchPolicy Exact makes this worse than matchPolicy Equivalent.
- RBAC on the control itself. A subject who can update or delete the ValidatingWebhookConfiguration, the policy binding, or the webhook’s backing Service and Deployment can simply remove the control.
- Out-of-scope targets. Admission control evaluates new create, update, delete and connect requests, not workloads already running. An attacker who execs into a live pod or already holds a token is past it.
The rest of this post takes the three that cause the most real-world damage, fail-open webhooks, RBAC on the configuration, and the mutating-webhook case, and shows how each one is abused and closed.
Why fail-open webhooks are the most common gap
The default failurePolicy is Fail, which rejects a request when the webhook cannot answer. In production that is risky: if the webhook pod is down, every matching request is blocked, so teams often switch it to Ignore to protect availability. That trade turns reliability into a security hole. An attacker who can crash, saturate or simply outwait the webhook, within its timeoutSeconds, lands the change the policy would have denied. A webhook running on one replica, or reachable only through a Service an attacker can disrupt, is the same problem waiting to happen, and the window does not have to be long because admission is evaluated per request. Pwned Labs reproduces this fail-open behaviour against OPA Gatekeeper in the Secure Kubernetes using OPA Gatekeeper lab, so you can watch a mis-set policy let a workload through.
How mutating webhooks add their own risk
Validating webhooks say yes or no. Mutating webhooks change the object first, which gives them more power and a different failure mode. A mutating webhook is where sidecars, default securityContext values and injected volumes come from, so a compromised or overly trusting mutating webhook can add a privileged sidecar or mount to a pod that would otherwise be clean, and the validating stage may pass the mutated object. Ordering matters too: mutating runs before validating, and reinvocationPolicy IfNeeded lets a mutating webhook run again after another webhook has changed the object, which can reintroduce something a policy expected to be gone. Treat a mutating webhook as part of the trusted computing base of the cluster, protect its configuration and backend with the same care as the API server, and prefer validating controls where mutation is not actually needed. Pwned Labs covers webhook trust and abuse end to end in its Kubernetes Attack and Defense bootcamp.
How RBAC turns into an admission bypass
Admission control is only as strong as the permissions around it. If a role can patch or delete objects in admissionregistration.k8s.io, the webhook configuration is editable, and editing it to narrow its rules or widen its exclusions disables enforcement without touching the workload. The same is true of the Secret holding the webhook’s CA bundle, the Service that fronts it, or the Deployment behind it, and for the in-tree model, the ValidatingAdmissionPolicyBinding that activates a policy. This is why an attacker who has reached permissive RBAC, from a compromised node identity or a leaked service account token, is often one step from neutralising policy entirely. Pwned Labs works this RBAC-to-cluster-control path in the Exploit Kubernetes Overly Permissive RBAC lab, and the broader Kubernetes penetration testing guide puts it in the context of a full cluster compromise.
A fail-open policy and an excluded namespace
Take a cluster that blocks privileged pods with an OPA Gatekeeper policy. Two common shortcuts undo it. The webhook runs failurePolicy Ignore on a single replica, because a fail-closed version once caused an outage, and it excludes kube-system and a few operator namespaces with a namespaceSelector so platform components are not blocked. An attacker who can create workloads tries the direct route first: a privileged pod in one of the excluded namespaces, where the policy never runs. If those namespaces are locked down, the fail-open gap is the fallback: overload or restart the single Gatekeeper replica, then create the pod inside the timeout window. The control was in place and the pod still landed, which is the whole case for testing admission from the attacker side instead of trusting the config. Pwned Labs rebuilds this kind of setup in a live cluster in the Kubernetes Attack and Defense bootcamp.
How to defend against admission controller bypass
The defenses map onto the bypass classes. Set failurePolicy to Fail and run the webhook highly available so fail-closed does not cause outages. Use matchPolicy Equivalent and review namespaceSelector and objectSelector exclusions so nothing important is carved out. Lock down RBAC so no workload identity can update or delete webhook configurations, policy bindings, the CA Secret, or the webhook’s Service and Deployment, and keep namespace-label changes, which drive Pod Security Admission, to a small set of trusted principals. Prefer ValidatingAdmissionPolicy where it fits, because a policy that runs inside the API server has no external webhook to overload and no network dependency to break. Enforce Pod Security Admission at the namespace, and run admission tools in enforce mode rather than audit-only. Then confirm it holds by testing from an attacker’s position. Pwned Labs teaches these controls from the attacking side, so you can see which ones actually break the chain and which only look like they do.
How do I learn to test admission control?
You can read about the failure modes, but you learn to find them by breaking the controls and rebuilding them in a real cluster. The Pwned Labs Kubernetes Attack and Defense bootcamp, which leads to the KRTP certification, covers RBAC escalation, container escape, cloud identity abuse and the policy controls that are meant to stop them, and the broader Kubernetes penetration testing guide sets the surrounding context. For a full overview of the paths and curriculum, see the Pwned Labs Kubernetes and container security training page.
Practice this at Pwned Labs
Pwned Labs runs the admission-control attack and defense surface as hands-on labs in live Kubernetes clusters.
- Secure Kubernetes using OPA Gatekeeper (Premium, Intermediate): write and apply OPA Gatekeeper admission policies in Rego, and see where a fail-open or mis-scoped policy lets a workload through.
- Exploit Kubernetes Overly Permissive RBAC (Premium, Intermediate): from compromised credentials on an EC2 instance, abuse overly permissive RBAC to reach cluster control, the same RBAC that can edit an admission webhook.
- Escalate from SSJI to EKS (Premium, Beginner): chain server-side JavaScript injection through IAM and IDOR weaknesses to reach the Amazon EKS cluster behind the application.
- Escalate from Prototype Pollution to EKS Takeover (Premium, Intermediate): exploit prototype pollution in a Node.js app for code execution, break out of the container, and abuse RBAC to take over an EKS cluster.
Frequently asked questions
Does failurePolicy Ignore bypass the admission policy?
Not on a normal decision. failurePolicy only decides what happens when the webhook errors or times out: Ignore admits the request, Fail rejects it, and the default is Fail. The risk is that operators set Ignore so a broken webhook does not take the cluster down, which turns any webhook outage, or a webhook an attacker can overload, into a quiet bypass.
What is the difference between a validating and a mutating admission webhook?
A validating webhook can only accept or reject a request. A mutating webhook changes the object first, for example injecting a sidecar or setting defaults, and runs before validation. Mutating webhooks are more powerful and therefore more sensitive: a compromised one can add a privileged sidecar or volume that the validating stage then passes.
Can ValidatingAdmissionPolicy be bypassed the same way as a webhook?
It removes the fail-open and network-dependency problems, because the policy runs inside the API server as CEL with no external webhook to overload. It is still bound by its own match rules and by RBAC on the policy and its binding, so scope gaps and permission to edit the policy remain the ways through. Pwned Labs covers both the webhook and in-tree policy models in its Kubernetes Attack and Defense bootcamp.
How do I see which admission controllers and webhooks a cluster uses?
List the dynamic ones with kubectl get validatingwebhookconfigurations, mutatingwebhookconfigurations and validatingadmissionpolicies, then read each one’s rules, failurePolicy and selectors. The built-in controllers are set by the API server’s enable-admission-plugins flag, which you confirm on the control plane or, on managed clusters, from the provider documentation.
Do admission controllers stop attacks on pods that are already running?
No. Admission control evaluates create, update, delete and connect requests, not workloads already in the cluster, so an attacker who execs into a running pod or already holds a token is outside its scope. Runtime detection and tight RBAC cover that gap. Pwned Labs walks the move from a running pod to cluster and cloud control in its KRTP labs.
Does Pod Security Admission replace PodSecurityPolicy?
Yes. PodSecurityPolicy was removed in Kubernetes 1.25, and Pod Security Admission is the built-in replacement. It applies the baseline or restricted pod standard per namespace through labels rather than through RBAC rules, so the control depends on who can set and change those namespace labels.
Is OPA Gatekeeper or Kyverno enough on its own?
Both are validating webhooks, so they inherit the same fail-open, namespace-exclusion and RBAC-on-the-config weaknesses, and their audit mode reports without blocking. They are effective when set to enforce with failurePolicy Fail, tight RBAC and high availability, and weak when any of those is missing. Pwned Labs shows this gap directly in its OPA Gatekeeper lab.
About Pwned Labs
Pwned Labs is a hands-on cloud and AI offensive security training platform. It runs real-world attack labs and bootcamps for AWS, Azure, GCP, Kubernetes and AI systems, including the ACRTP, MCRTP, GCRTP, KRTP and AISRTP certifications. Free labs are at pwnedlabs.io/explore.