Skip to main content
cd ../config-traps
risk/register/kubernetes-pods-inherit-api-tokens-nobody-requested.html
Kubernetes RBAC Hardeninghigh severityKubernetes

Kubernetes Pods Inherit API Tokens Nobody Requested

Severity
high
Reviewed
12 Jul 2026
Remediation
~20 minutes
Overview

Every ServiceAccount and Pod that omits automountServiceAccountToken inherits the default true value, auto-mounting a live API token nobody requested. One container RCE or SSRF then yields a working bearer credential, escalating instantly if that namespace's default ServiceAccount is bound to a ClusterRole.

Operational summary

At a glance

Symptom
Container RCE, SSRF, or dependency compromise reaches API server using auto-mounted default token
Likely cause
automountServiceAccountToken left unset on ServiceAccounts and Pods, defaulting to true
Impact
Attacker lists secrets, reads other tokens, enumerates ConfigMaps, or execs into pods cluster-wide via bound ClusterRole.
Verification signal
Re-run the detection test and a controlled negative-path test.
Safe correction
Set automountServiceAccountToken false by default; enforce via Kyverno/Gatekeeper; never bind default SAs to ClusterRoles.
Rollback or recovery
Restore the exported configuration if the new control blocks required production traffic, then narrow the policy before redeployment.

The Trap

automountServiceAccountToken left unset on ServiceAccounts and PodSpecs

The Default State

Kubernetes defaults automountServiceAccountToken to true at the API server level. When a namespace is created, its default ServiceAccount inherits this, and every Pod that does not explicitly set automountServiceAccountToken: false gets a projected volume mounted at /var/run/secrets/kubernetes.io/serviceaccount/, containing token, ca.crt, and namespace. Developers writing manifests almost never set the field on either the ServiceAccount or the Pod, because nothing in kubectl apply warns them it happened. The kubelet’s TokenRequest-issued token defaults to a 3607-second expiry and is bound to the pod’s service account, but with no audience restriction unless BoundServiceAccountTokenVolume behaviour has been explicitly configured with specific audiences.

The Blast Radius

A single RCE in any container, a vulnerable base image with a dependency confusion payload, an SSRF that reaches the metadata-style endpoint, gives an attacker a valid bearer token scoped to the cluster’s API server. If that namespace’s default ServiceAccount has been bound, even loosely, to a ClusterRole via a ClusterRoleBinding — common when teams apply a broad ‘view’ or custom operator role cluster-wide for convenience — the attacker can now run kubectl-equivalent calls against https://kubernetes.default.svc: list secrets across namespaces, read other ServiceAccount tokens, enumerate ConfigMaps holding connection strings, or exec into other pods if ‘pods/exec’ verbs are present. This is the exact mechanism behind most container-breakout-to-cluster-takeover incident writeups: the compromised workload never touches the node, it just asks the API server nicely with a token nobody meant to hand it. Audit logs show the requests as legitimate ServiceAccount activity, not an intrusion, because from the API server’s perspective they are.

The Lead Mechanic Fix

Set automountServiceAccountToken: false on every ServiceAccount by default: kubectl patch serviceaccount default -n <namespace> -p ‘{“automountServiceAccountToken”: false}’. For the small number of pods that genuinely need API access, mount a scoped, audience-bound, short-lived token explicitly via a projected volume with serviceAccountToken specifying audience and expirationSeconds (900 or lower), rather than relying on the legacy auto-mounted secret. Enforce this cluster-wide with a Kyverno ClusterPolicy or Gatekeeper constraint that denies any Pod spec lacking an explicit automountServiceAccountToken: false unless the ServiceAccount is on an allow-list tied to a documented RoleBinding, not a ClusterRoleBinding. Never bind default ServiceAccounts to ClusterRoles.

03

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.

Control to implement

Set automountServiceAccountToken false by default; enforce via Kyverno/Gatekeeper; never bind default SAs to ClusterRoles.

Validate the vendor-specific syntax in official documentation before applying it.

04

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.

After remediation

Further reading stays below the corrective workflow and is selected by platform, category and shared technical keywords.

Discover more

Connected KBY resources

Kubernetes Pods Inherit API Tokens Nobody… | Config Traps