Unlabelled Namespaces Inherit PodSecurity's Privileged Default
A namespace created without a pod-security.kubernetes.io/enforce label picks up whatever level the cluster's AdmissionConfiguration falls back to, and on most clusters that fallback is still privileged. Helm charts, Terraform modules and CI-generated preview environments routinely skip the label, so PodSecurity admission runs, reports healthy, and denies nothing.
At a glance
- Unsafe setting
- PodSecurity Admission runs cluster-wide with no AdmissionConfiguration file, leaving unlabelled namespaces on the implicit "privileged" default.
- Failure trigger
- A namespace created by Helm, Terraform or CI without the pod-security.kubernetes.io/enforce label is scheduled with privileged: true and hostPID: true.
- Blast radius
- Unlabelled namespaces admit privileged containers unchecked, allowing host filesystem access, kubelet API pivoting and cluster-wide service account token theft.
- Recommended control
- Set a cluster-level PodSecurityConfiguration defaulting enforce to baseline or restricted, and require the label via a ValidatingAdmissionPolicy on namespace creation.
The Trap
Namespace-scoped PodSecurity enforcement without a hardened cluster-wide default. PodSecurity Admission decides what a namespace permits by reading its pod-security.kubernetes.io/enforce label, but that label is optional per namespace. If the label is absent, the admission plugin falls back to whatever defaults.enforce value the API server was given at startup — and if nobody supplied an AdmissionConfiguration file, that value is “privileged”.
The Default State
Since Kubernetes 1.25, the PodSecurity admission plugin is compiled into kube-apiserver and listed in –enable-admission-plugins by default, so security tooling that only checks whether the plugin is loaded reports a clean pass. Operators then label the two or three namespaces they consciously hardened — usually production workloads — and assume the rest inherit something safe. They don’t. Namespaces created by Helm releases, Terraform kubernetes_namespace resources, GitOps reconcilers, and CI pipelines spinning up per-branch preview environments almost never carry the enforce label, because nobody writes it into the chart template. Each of these lands on the cluster’s implicit default, which without an explicit AdmissionConfiguration file is “privileged:latest” for enforce, audit and warn alike — the equivalent of no PodSecurity Admission at all.
The Blast Radius
A pull-request preview namespace spins up with a container spec setting privileged: true and hostPID: true. PodSecurity Admission admits it silently because the namespace was never labelled and the cluster default permits it. The container mounts the host filesystem, reads the node’s kubelet credentials from /var/lib/kubelet, and queries the cloud instance metadata service for the node’s IAM role. From there it reaches the kubelet API on port 10250, lists every pod on the node, and extracts service account tokens for workloads with far broader RBAC than the preview environment was ever meant to have. Nothing alerts, because admission never fired a denial — there was no policy configured to violate.
The Lead Mechanic Fix
Ship an explicit AdmissionConfiguration and stop relying on the compiled-in default. Set defaults.enforce and defaults.audit to baseline or restricted, pin enforce-version to latest, and list only genuine exemptions by name:
apiVersion: apiserver.config.k8s.io/v1
kind: AdmissionConfiguration
plugins:
– name: PodSecurity
configuration:
apiVersion: pod-security.admission.config.k8s.io/v1
kind: PodSecurityConfiguration
defaults:
enforce: “baseline”
enforce-version: “latest”
exemptions:
namespaces: [“kube-system”]
Restart kube-apiserver with –admission-control-config-file pointing at that manifest, then bind a ValidatingAdmissionPolicy that rejects any namespace CREATE lacking pod-security.kubernetes.io/enforce set to baseline or restricted, closing the gap the label alone leaves open.
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.
Set a cluster-level PodSecurityConfiguration defaulting enforce to baseline or restricted, and require the label via a ValidatingAdmissionPolicy on namespace creation.
Validate the vendor-specific syntax in official documentation before applying it.
Verify, roll back or escalate
Verify
Re-run the detection test and a controlled negative-path test. Confirm the unsafe behaviour is blocked while approved traffic still succeeds.
Rollback
Restore the exported configuration if the new control blocks required production traffic, then narrow the policy before redeployment.
Escalate
Escalate when the blast radius is uncertain, the control cannot be tested safely, or remediation requires an outage or security exception.