Case Study: Lateral Movement Chain in a Kubernetes Security Review
Case Study: Lateral Movement Chain in a Kubernetes Security Review
Anonymized from an engagement completed under NDA. The target: a managed Kubernetes cluster running a production e-commerce platform.
The Question: From One Pod to the Whole Cluster?
The client's question was precise: "Suppose a container image has a vulnerability and an attacker gets a foothold in one pod — can they spread to the entire cluster?"
This is a question a configuration scanner cannot answer. Answering it requires actually building the chain.
Links in the Chain
1. Over-Privileged Service Account (High)
Application pods ran under a service account that could read secrets cluster-wide with get, list, and watch permissions. The justification was convenience — a single account reused across all environments.
Exploitation, from inside a compromised pod:
kubectl auth can-i --list # cluster-wide secrets/list ✓
kubectl get secrets -A # 40+ secrets readable
2. GitOps Credential Stored in a Secret (Critical)
Among the readable secrets: the GitOps operator's Git credential with cluster-admin equivalent write access, stored in plaintext. One link in the chain granted write access to the entire cluster from the Git repository.
3. Long-Lived Token in the CI/CD Pipeline (High)
The deployment pipeline used a non-expiring kubeconfig token. If that token leaked — from the pipeline server, a build log, or a departing engineer — cluster access was permanent.
The Validated Attack Path
Vulnerable pod → over-privileged SA → GitOps secret read
→ cluster-admin Git credential → malicious workload in attacker-chosen namespace
→ persistent cluster access
Every link was demonstrated on screen. No production workloads were touched — validation happened only in an isolated test namespace, per engagement rules.
Remediation Priority and Retest
| Priority | Fix | Retest |
|---|---|---|
| P0 | GitOps credential moved out of Secrets (OIDC-based short-lived tokens) | Git access via secret read severed ✓ |
| P0 | Per-service-account RBAC: pods read only their own namespace's secrets | Cluster-wide listing returns 403 ✓ |
| P1 | Pipeline token converted to short-lived + audit alerting | Expired token rejected ✓ |
| P2 | Pod Security Standards (restricted) enforced | Privilege escalation path closed ✓ |
Cluster Hardening Checklist
- Can application service accounts read secrets cluster-wide?
- Are GitOps/CI credentials stored as plaintext Kubernetes Secrets?
- Are tokens non-expiring?
- Are Pod Security Standards enforced?
- Are RBAC changes monitored via audit logs?
This checklist is scan-level. Chained validation requires real exploitation.
Why Chains Matter More Than Findings
Individually, each finding was "medium" in most scanners' eyes. Chained, they equaled full cluster compromise. This is the recurring pattern in cloud reviews: the sum of small misconfigurations is a critical attack path, and only offensive validation reveals the arithmetic.
Engagement Timeline
| Day | Phase | Output |
|---|---|---|
| 1-2 | Cluster inventory | RBAC map, service account matrix, network policy analysis |
| 3-4 | Identity layer | SA privilege audit, secret access matrix, token lifecycle |
| 5-6 | Chain construction | Isolated exploitation chain in a test namespace |
| 7-8 | CI/CD and GitOps | Pipeline credential flow, GitOps privilege analysis |
| 9-10 | Evidence and report | Video proof of the chain, prioritized remediation plan |
| 11-12 | Delivery + remediation support | Working alongside the platform team |
| 13-14 | Retest | Fix verification, closure |
The full chain was proven by day 6. Because we worked in the same channel as the platform team, P0 fixes started before the report — the time between finding and fix determines a finding's real value.
Practical RBAC Audit Commands
The audit steps used in this engagement, with equivalents you can run on your own cluster:
1. What can the service account actually do?
kubectl auth can-i --list --as=system:serviceaccount:<ns>:<sa>
Expected: application SAs limited to a few verbs in their own namespace. get/list on secrets — and especially * verbs — are red flags.
2. Who can read secrets cluster-wide?
kubectl get clusterrolebindings -o json | \
jq '[.items[] | select(.roleRef.name | test("admin|cluster")) | .subjects]'
Application SAs appearing in cluster-admin bindings herald link #2 of this case.
3. What's the token lifecycle?
Long-lived static tokens (service-account tokens in Secrets) mean the bound-token mechanism hasn't been adopted. Kubernetes 1.24+ produces short-lived, audience-bound tokens by default — the presence of old static tokens signals an incomplete migration.
4. Are Pod Security Standards enforced?
kubectl get ns <ns> --show-labels | grep pod-security
A missing enforce=restricted label means the door for privileged pods is open.
The Detection Side: Would This Chain Have Alerted?
1. Secret read anomaly: a pod attempting secret access in namespaces it normally never touches appears in the API server audit log. Without an audit policy + rule set (Falco or similar), it's invisible. Recommendation: per-SA secret access baseline with deviation alerting.
2. New SA token usage: API calls made with a token extracted from a compromised pod can be distinguished from normal pod traffic by network/source. Streaming control-plane logs into a SIEM is the prerequisite for this detection in managed clusters.
3. GitOps change origin: a commit to the GitOps repo from an unexpected source (a credential, not a human) can be caught pre-deploy: commit signature verification + merge rules.
None of these chain links produced a real-time alert for this client — the detection layer was built together with the remediations.
Finding vs. Threshold: Why Scanners Miss This Chain
| Tool | Sees it? | Why |
|---|---|---|
| Vulnerability scanner | No | RBAC and secret placement aren't "vulnerability signatures" |
| CIS benchmark scan | Partially | May flag the over-privileged SA but doesn't compute the chain |
| Configuration audit | Partially | Lists individual findings, not combined impact |
| Offensive validation | Yes | Actually builds the chain, proves the impact |
A CIS "over-privileged service account" finding sits at P3 on a management agenda. The same finding proven as "the door to a cluster-admin GitOps credential" is P0. The difference isn't the finding — it's the context.
Frequently Asked Questions
How often should a Kubernetes security review be performed?
Mandatory on structural changes (version upgrades, new clusters, GitOps tool changes); annual offensive validation is good practice for stable clusters. RBAC and secret placement are continuously drifting surfaces — scanning is continuous, deep validation is periodic.
Do managed clusters (EKS/GKE/AKS) require pentest permission?
Yes — providers have acceptance policies that generally permit testing on your own clusters under conditions. Control-plane testing and provider infrastructure are out of scope. Check the provider's acceptance policy and document the test window before engagement.
Are Pod Security Standards sufficient?
PSS closes pod-level privilege escalation but doesn't fix RBAC over-privilege or secret placement mistakes. The chain in this case would have worked with PSS enforced — because the links lived in RBAC and credential placement. PSS is necessary but insufficient on its own.
Request a Pilot
To validate your cluster's lateral movement resilience, request a scoping call.
Security Validation
Have you tested this risk in your own system?
Eresus Security delivers real exploit evidence through penetration testing, AI agent security, and red team operations.
Request a pilot testRelated Services