A Namespace Exemption Label That Lets Privileged Pods Bypass Admission Control
A namespace label intended to enforce restricted Pod Security Admission was silently overridden by a bulk relabelling script and an audit-only custom admission policy, letting privileged pods run undetected.
Operational summary
At a glance
- Symptom
- A cluster running Kubernetes with Pod Security Admission (PSA) enforcing the restricted profile at namespace level unexpectedly allows a privileged pod to run in…
- Likely cause
- Two admission mechanisms were active simultaneously: built-in Pod Security Admission (label-driven) and a custom ValidatingAdmissionPolicyBinding created for an internal tooling exemption.
- Impact
- Any workload deployed to the affected namespace can request privileged mode, host networking or hostPath mounts and be admitted without denial, materially increasing the blast radius of a…
- Verification signal
- Validation confirms both that the enforcement label is correctly applied and that a genuinely non-compliant pod specification is now rejected.
- Safe correction
- Restore the intended enforcement level at the namespace label and remove or correctly scope the conflicting custom policy binding.
- Rollback or recovery
- If restoring restricted enforcement blocks a workload that has a legitimate, previously undocumented need for elevated privileges, revert the namespace label to the prior state with kubectl label…
Symptom
A cluster running Kubernetes with Pod Security Admission (PSA) enforcing the restricted profile at namespace level unexpectedly allows a privileged pod to run in a namespace that was believed to be locked down. The pod specification requests privileged: true, host networking and a hostPath mount, none of which should pass admission under the restricted level. There is no error, no denial event and no audit log entry indicating a rejected request; the pod simply starts. Operators reviewing kubectl get pods output only discover the exposure during an unrelated security review, weeks after deployment.
False Assumption
The platform team assumed that applying pod-security.kubernetes.io/enforce: restricted as a namespace label was sufficient, and that the label alone determined enforcement for every workload created in that namespace going forward. The visible assumption was: “the namespace label is the enforcement boundary, so anything in this namespace is restricted.” This ignored a second label added earlier by an automation script for an unrelated purpose: pod-security.kubernetes.io/exempt: platform-agent was never actually set, but a similarly named administrative label, security.exemption/namespace: true, had been added to support a legacy tooling migration and was matched by a custom ValidatingAdmissionPolicy binding that predated PSA adoption. The team did not verify which admission mechanism was actually deciding the outcome; they assumed PSA labels were the only control in effect.
Root Cause
Two admission mechanisms were active simultaneously: built-in Pod Security Admission (label-driven) and a custom ValidatingAdmissionPolicyBinding created for an internal tooling exemption. The custom policy bound to any namespace carrying the label security.exemption/namespace: true and its validationActions field was set to Audit, not Deny, when it was originally authored to test the exemption logic before general availability. Nobody reverted validationActions to Deny once the exemption went live, and because the policy matched broader pod fields than intended (it validated only container image registry, not privilege escalation fields), any pod meeting the registry condition passed the custom policy silently in audit mode while PSA’s namespace label was, separately, later downgraded from restricted to baseline by a bulk labelling script that did not distinguish between production and staging namespaces. The combination made the effective enforcement level baseline, not restricted, and the custom policy never blocked anything because it was in audit-only mode. Kubernetes documentation on debugging applications confirms that diagnosing workload behaviour requires inspecting the actual running configuration and cluster events rather than relying on the intended configuration (Kubernetes, Debugging Applications).
Impact
Any workload deployed to the affected namespace can request privileged mode, host networking or hostPath mounts and be admitted without denial, materially increasing the blast radius of a single compromised container to full node compromise. Because no admission denial event is generated, standard alerting based on rejected admission requests produces no signal, so the exposure persists until manually audited. This is a namespace-wide condition, not limited to one workload, so the risk scope includes every current and future pod scheduled there.
Diagnosis
Confirm the effective Pod Security Admission level actually applied to the namespace, rather than trusting the label that was intended to be set:
kubectl get ns <namespace> -o jsonpath='{.metadata.labels}'
Expected evidence: the output shows the current pod-security.kubernetes.io/enforce value; compare it against the intended restricted value to confirm drift to baseline or absence of the label.
kubectl get validatingadmissionpolicybindings -o yaml
Expected evidence: locate any binding whose matchResources or namespace selector references the namespace, and inspect its validationActions field. A value of Audit or Warn instead of Deny confirms the policy is not actually blocking matching requests.
kubectl get pods -n <namespace> -o jsonpath='{range .items[*]}{.metadata.name}{" privileged="}{.spec.containers[*].securityContext.privileged}{"n"}{end}'
Expected evidence: identifies any running pod with privileged=true in the affected namespace, confirming the admission gap allowed a non-compliant workload to run.
Correction
Restore the intended enforcement level at the namespace label and remove or correctly scope the conflicting custom policy binding. First, set the correct PSA label explicitly rather than relying on a prior bulk change: kubectl label ns <namespace> pod-security.kubernetes.io/enforce=restricted --overwrite. Second, change the custom ValidatingAdmissionPolicyBinding’s validationActions from Audit to Deny only after confirming, via the audit log evidence gathered during diagnosis, that no currently required workload depends on the previously permissive behaviour. Apply the binding update in a non-production namespace first and observe admission responses for at least one full deployment cycle before applying it where production workloads run. Do not delete existing privileged pods as part of this correction; they must be redeployed deliberately once the namespace enforcement is verified, since forced deletion of a running production pod is a separate, higher-risk action requiring its own change window and is out of scope for this correction.
Validation
Validation confirms both that the enforcement label is correctly applied and that a genuinely non-compliant pod specification is now rejected. After applying the correction, attempt to create a test pod with privileged: true in a disposable test namespace carrying the same corrected labels: kubectl apply -f privileged-test-pod.yaml --dry-run=server. Expected evidence: the API server returns an admission denial referencing the restricted PSA level, and the dry-run request is rejected rather than silently accepted. Separately, re-run the ValidatingAdmissionPolicyBinding inspection command and confirm validationActions now reads Deny in the environment where the change was applied. Pass condition: the dry-run pod creation is denied with an explicit PSA violation message, and no pod in the affected namespace shows privileged=true going forward.
Rollback
If restoring restricted enforcement blocks a workload that has a legitimate, previously undocumented need for elevated privileges, revert the namespace label to the prior state with kubectl label ns <namespace> pod-security.kubernetes.io/enforce=baseline --overwrite and revert the policy binding’s validationActions to Audit using the saved manifest captured before the change (kubectl get validatingadmissionpolicybinding <name> -o yaml > pre-change-binding.yaml should be taken before applying any correction). Stop condition: roll back immediately if any production workload fails to schedule or is evicted following the enforcement change, and escalate to the workload owner before reapplying restricted. Rollback restores the previous permissive state only as a temporary measure; it does not resolve the underlying exposure and must be paired with a tracked follow-up to properly scope the workload’s actual privilege requirements.
Prevention
Require that every namespace-level admission label change go through the same change review as a workload deployment, since a label edit has cluster-wide security consequences without a corresponding code review trail. Treat any ValidatingAdmissionPolicyBinding with validationActions: Audit as a temporary, time-boxed state with an explicit expiry date tracked in an issue, not a permanent configuration. Add a scheduled read-only check that compares each namespace’s actual PSA enforcement label against a declared baseline manifest and alerts on drift, so silent downgrades from bulk labelling scripts are caught before a security review discovers them. Finally, require that any custom admission policy intended to eventually enforce Deny be reviewed against the specific pod security fields it claims to cover, since a policy matching only image registry conditions provides no protection against privilege escalation regardless of its validationActions setting.
Apply the safer control
Before you change production
Confirm the affected scope, export the current configuration, and test the replacement control in a non-production environment first.
Fix commands and configuration
restrictedprivileged: truekubectl get podsVerify, roll back or escalate
Verify
Validation confirms both that the enforcement label is correctly applied and that a genuinely non-compliant pod specification is now rejected.
Rollback
If restoring restricted enforcement blocks a workload that has a legitimate, previously undocumented need for elevated privileges, revert the namespace label to the prior state with kubectl label ns <namespace> pod-security.kubernetes.io/enforce=baseline --overwrite and revert the policy binding's validationActions to Audit…
Escalate
Escalate when the blast radius is uncertain, the control cannot be tested safely, or remediation requires an outage or security exception.