Figure 1: Anatomy of a controller-based attack. The malicious webhook intercepts legitimate pod creation requests and injects a backdoor sidecar before the object is persisted to etcd.
Niranjan Kumar Sharma As illustrated in Figure 1, this webhook acts as a controller. Every time a legitimate pod is created (e.g., a payment service), the API server sends the pod definition to the attacker’s webhook for approval. The webhook modifies the pod spec to inject a malicious sidecar container before it is persisted to etcd. The hidden danger:
- It’s invisible to kubectl get pods: The malicious sidecar is often hidden deep in the pod spec, and if the attacker uses a common name like proxy-agent, it blends in with legitimate mesh traffic.
- It survives cleanup: If you delete the compromised pod, the Deployment controller creates a new one. The new one triggers the webhook again, and the backdoor is re-injected. The persistence is baked into the lifecycle of the cluster itself.
Mapping the threat: This technique maps to Persistence (TA0003) in the MITRE ATT&CK for Containers matrix. It specifically leverages the cluster’s own control loop to maintain access, making it far more resilient than traditional shell-based backdoors.
Hunting ghosts in the API : To catch this, you have to look beyond standard logs. You need to audit the cluster’s control plane configuration. 1. Audit MutatingWebhookConfigurations Run this command to see who is intercepting your pod creations:
kubectl get mutatingwebhookconfigurations
kubectl get mutatingwebhookconfigurationsLook for webhooks pointing to external URLs or services in namespaces you don’t recognize (e.g., kube-public or default). If you see a webhook named compliance-check pointing to an IP address outside your VPC, treat it as a massive red flag. 2. Monitor RoleBinding changes Controllers need permissions. A rogue controller needs a ServiceAccount with elevated privileges to do damage. Monitor your audit logs for new RoleBindings that grant watch or list permissions on Secrets or Pods. 3. Check for anomalous OwnerReferences Kubernetes objects use OwnerReferences for garbage collection. If you see pods that claim to be owned by a controller that doesn’t exist or doesn’t match standard deployment patterns, investigate immediately.
Locking down the machinery : To prevent controller-based persistence, you must restrict access to the machinery of the cluster.
Restrict Webhook registration: Use Kubernetes RBAC to ensure that only cluster administrators (and specifically the CI/CD pipeline identity) can create or modify MutatingWebhookConfigurations. Developers should never have this permission.
Network policies for the control plane: If you are running self-managed control planes, ensure the API server can only communicate with known, whitelisted webhook endpoints.
Sign your images: Use an admission controller like Kyverno or OPA Gatekeeper to verify that every container image in a pod, including injected sidecars, is signed by your organization’s trusted key.
Final thoughts : Attackers are moving up the stack as Kubernetes clusters mature. They are no longer satisfied with simple container escapes; they are targeting the orchestration layer itself. The Kubernetes Controller pattern is powerful because it offers automation and self-healing. In the hands of an attacker, those same properties create a persistent, resilient foothold. We must stop treating the API server as a trusted black box and start auditing the webhooks that glue our clusters together. This article is published as part of the Foundry Expert Contributor Network.Want to join?
First seen on csoonline.com
Jump to article: www.csoonline.com/article/4151367/why-kubernetes-controllers-are-the-perfect-backdoor.html
![]()

