Container and Kubernetes Pentest Checklist

The container and Kubernetes checklist turned into a how-to-test field guide: image security and secrets in layers, Dockerfile/build, container runtime (privileged, capabilities, host mounts, docker.sock), container breakout, registry security, then Kubernetes recon, RBAC, secrets, pod security, network policy, API-server and kubelet exposure, and supply chain — each with the scenario, the real command (trivy, docker, kubectl, kube-hunter, kube-bench, peirates, amicontained), the steps, the find

LazyHackers.in — Checklist

📦 Container and Kubernetes Pentest Checklist

Docker + K8s, item by item: scenario · command · steps · the finding · the fix

☰   How to use this guide

Containers and Kubernetes fail in layers: a leaky image (secrets, vulns, root), a dangerous runtime (privileged, host mounts, the Docker socket), a soft orchestrator (over-permissive RBAC, mounted SA tokens, exposed API). The attacker's goal is usually breakout (container → host) then cluster takeover. This guide turns every item into how-to-test. The cloud IAM that backs the cluster is in the Cloud checklist; the app in the container is web/API.

Benchmark with CIS Docker/Kubernetes (kube-bench, docker-bench) for breadth; verify breakout and RBAC paths by hand. Run kube-hunter/peirates from inside a pod for the assumed-breach view. Each section ends with a coverage table.
Authorised testing only. Breakout and privilege-escalation actions can affect the host/cluster — confirm scope and prefer a non-production cluster.
# Image + config scanning (breadth)
trivy image registry/app:tag ; grype registry/app:tag
docker-bench-security ; kube-bench            # CIS benchmarks
# Inside-the-pod / cluster recon (assumed breach)
kube-hunter --pod ; amicontained ; kubectl auth can-i --list

0   Image security

Images ship secrets in layers, run as root, and carry vulnerable packages. Pull, scan, and inspect the layer history.

trivy image --scanners vuln,secret,config registry/app:tag    # vulns + secrets + misconfig
docker history --no-trunc registry/app:tag                     # secrets baked into layers
docker run --rm -it registry/app:tag id                        # running as root (uid 0)?
dive registry/app:tag                                          # explore layers
⚑ Report as: “Secret baked into image layer / image runs as root / vulnerable packages”
🛡 Fix: Never bake secrets into images (use runtime secrets / mounted volumes); run as a non-root user (USER directive); minimal/distroless base images; scan in CI and fail on criticals; pin and update base images; multi-stage builds to drop build secrets.

Image security — full coverage

Checklist itemHow to testReport as
Secrets in image layerstrivy secret / docker historySecret in image
Image runs as rootdocker run ... idContainer runs as root
Vulnerable packages (CVE)trivy/grypeVulnerable image
Outdated/unpinned base imageinspect baseUnpinned base image
Unnecessary packages/tools (shell, curl)inspect imageBloated attack surface
No image signing / provenancecheck cosign/notationUnsigned image
Sensitive files in imagedive / findSensitive file in image

1   Dockerfile / build

Build-time misconfigurations: ADD from URLs, secrets in build args, latest tags, and no .dockerignore leaking the repo.

⚑ Report as: “Insecure Dockerfile (secrets in build args / ADD remote / latest tag)”
🛡 Fix: Use COPY not ADD (no remote fetch); pass secrets via BuildKit --secret, never ARG/ENV; pin exact base tags (not latest); .dockerignore to avoid copying .git/secrets; multi-stage to keep build tooling out of the final image; drop privileges.

Dockerfile / build — full coverage

Checklist itemHow to testReport as
Secrets in build args/ENVreview DockerfileSecret in build
ADD with remote URLreview DockerfileUnsafe ADD
latest / unpinned tagreview FROMUnpinned image tag
No .dockerignore (repo leak)check contextBuild-context leak
No USER (root by default)review DockerfileNo non-root user
Build runs untrusted codereview build stepsUnsafe build step

2   Container runtime

Runtime flags decide blast radius. Privileged containers, added capabilities, host namespace sharing, and the mounted Docker socket are near-instant host compromise.

# What am I running as / with? (from inside the container)
amicontained                       # caps, namespaces, seccomp
capsh --print ; cat /proc/1/status | grep CapEff
# The classic: mounted Docker socket = root on host
ls -la /var/run/docker.sock && docker -H unix:///var/run/docker.sock ps
# Host mounts / privileged
mount | grep -E ' / |/host' ; cat /proc/self/status | grep Seccomp
⚑ Report as: “Privileged container / mounted docker.sock / host path mount (host compromise)”
🛡 Fix: Never run privileged; drop all capabilities and add back only what's needed; don't mount the Docker socket into containers; no host path mounts of sensitive dirs; keep seccomp/AppArmor profiles on; read-only root filesystem; no host PID/IPC/network unless required.

Container runtime — full coverage

Checklist itemHow to testReport as
Privileged containeramicontained / inspectPrivileged container
Excessive capabilitiescapsh --printExcessive capabilities
Docker socket mountedls docker.sockDocker socket exposure
Host path mounts (sensitive)mountHost filesystem mount
Host PID/IPC/network namespaceinspect namespacesHost namespace sharing
Seccomp/AppArmor disabledcheck profilesNo syscall/MAC confinement
Writable root filesystemtouch /testWritable root FS
No resource limitsinspect limitsNo resource limits

3   Container breakout

Turn a container foothold into host access — via privileged mode, mounts, capabilities (CAP_SYS_ADMIN), the Docker socket, or a runtime CVE.

# Automated breakout enumeration
deepce.sh        # or  CDK (cdk evaluate / cdk run)
# Docker-socket breakout: launch a host-mounting container
docker -H unix:///var/run/docker.sock run -v /:/host -it alpine chroot /host sh
# Privileged + cgroup release_agent breakout (classic PoC) on vulnerable setups
⚑ Report as: “Container breakout to host (privileged / socket / capability / runtime CVE)”
🛡 Fix: Remove the breakout primitives (privileged, socket, host mounts, dangerous caps); patch the container runtime (runc/containerd CVEs); user namespaces + seccomp/AppArmor; treat any container with host access as host-equivalent risk.

Container breakout — full coverage

Checklist itemHow to testReport as
Breakout via privileged modedeepce/CDKContainer breakout (privileged)
Breakout via docker.socksocket run -v /:/hostContainer breakout (socket)
Breakout via capability (SYS_ADMIN)cgroup/release_agentContainer breakout (capability)
Breakout via host mountaccess mounted host pathContainer breakout (mount)
Runtime CVE (runc/containerd)version checkVulnerable container runtime
Kernel exploit from containerkernel versionHost kernel exploitation

4   Registry security

Registries leak images and secrets when public or weakly authenticated.

⚑ Report as: “Public/weakly-authenticated container registry exposing images/secrets”
🛡 Fix: Require auth on registries; private by default; scan images on push; sign images (cosign) and enforce signature verification; rotate registry credentials; least-privilege pull/push.

Registry security — full coverage

Checklist itemHow to testReport as
Public/anonymous registrycurl /v2/_catalogPublic registry
Weak/default registry credstry defaultsWeak registry credentials
Images contain secretspull + trivySecret in registry image
No image signing/verificationcheck cosignNo image signing
No scan on pushreview pipelineNo registry scanning
Kubernetes

5   Kubernetes recon

From inside a pod (assumed breach) or with cluster access: what can this identity do, and what's exposed?

# What can the current (pod) identity do?
kubectl auth can-i --list
kubectl auth can-i create pods ; kubectl auth can-i get secrets
# The mounted service-account token (default behaviour)
cat /var/run/secrets/kubernetes.io/serviceaccount/token
# Automated cluster attack tooling
kube-hunter --pod ; peirates ; kdigger dig all
⚑ Report as: “Default service-account token mounted with usable permissions”
🛡 Fix: Set automountServiceAccountToken: false unless needed; dedicated least-privilege service accounts per workload; restrict the default SA to nothing; segment namespaces.

Kubernetes recon — full coverage

Checklist itemHow to testReport as
Default SA token mountedcat tokenDefault SA token mounted
Current identity permissionskubectl auth can-i --listPermission set mapped
Cluster info / version exposedkubectl versionCluster fingerprint
kube-hunter findingskube-hunter --podCluster exposure findings
Metadata reachable from podcurl 169.254.169.254Cloud metadata from pod

6   Kubernetes RBAC

Over-permissive RBAC is the road to cluster admin: wildcard verbs/resources, the ability to create pods (then mount a privileged pod), read secrets, or escalate via bind/escalate verbs.

# Find dangerous grants
kubectl get clusterrolebindings,rolebindings -A -o wide
kubectl auth can-i '*' '*'                       # cluster-admin?
kubectl auth can-i create pods --all-namespaces  # -> mount privileged pod -> node
# rbac-tool / rakkess for a permission matrix
rbac-tool analysis ; rakkess
⚑ Report as: “Over-permissive RBAC (wildcard / create-pods / read-secrets) enabling cluster escalation”
🛡 Fix: Least-privilege RBAC: no wildcard verbs/resources; restrict create/exec on pods, get/list on secrets, and bind/escalate verbs; avoid cluster-admin bindings; per-namespace roles; audit bindings regularly.

RBAC — full coverage

Checklist itemHow to testReport as
Wildcard verbs/resourcesrbac-tool / can-i *Wildcard RBAC
create/exec pods (privesc to node)can-i create podsPod-creation escalation
get/list secretscan-i get secretsSecret-read permission
bind/escalate verbsreview rolesRBAC escalation verb
cluster-admin binding overusedreview bindingsExcessive cluster-admin
Anonymous/unauthenticated accesstest anonAnonymous cluster access

7   Kubernetes secrets

K8s secrets are base64, not encrypted by default; etcd may be unencrypted; and secrets often sit in env vars.

kubectl get secrets -A
kubectl get secret <name> -o jsonpath='{.data.*}' | base64 -d    # decode
# Secrets in pod env / configmaps
kubectl get pods -o yaml | grep -iE 'password|token|key'
⚑ Report as: “Kubernetes secrets readable / unencrypted at rest (etcd) / secrets in env vars”
🛡 Fix: Enable encryption at rest for secrets (KMS provider); restrict secret read via RBAC; prefer mounted files over env vars; use an external secrets manager; encrypt and lock down etcd; rotate secrets.

Secrets — full coverage

Checklist itemHow to testReport as
Secrets readable via RBACkubectl get secret -oReadable secrets
etcd unencrypted at restcheck encryption configUnencrypted secrets at rest
Secrets in env varsinspect pod envSecret in environment
Secrets in ConfigMapsinspect configmapsSecret in ConfigMap
etcd exposed/unauthenticatedprobe etcdetcd exposure

8   Pod security

Pod specs that allow privileged, hostPath, hostPID/Network, or no securityContext recreate the runtime risks at scale.

⚑ Report as: “Pods allowed to run privileged / hostPath / hostNetwork (no Pod Security enforcement)”
🛡 Fix: Enforce Pod Security Admission (restricted) or an admission controller (OPA/Gatekeeper, Kyverno); deny privileged, hostPath, host namespaces, and privilege escalation; require runAsNonRoot, readOnlyRootFilesystem, dropped capabilities and a seccomp profile.

Pod security — full coverage

Checklist itemHow to testReport as
Privileged pods allowedreview specs / can-iPrivileged pod allowed
hostPath volumes allowedreview specshostPath mount allowed
hostPID/hostIPC/hostNetworkreview specsHost namespace pod
No securityContext / runAsRootreview specsNo pod securityContext
allowPrivilegeEscalation truereview specsPrivilege escalation allowed
No Pod Security Admission / policy enginecheck PSA/OPANo pod-security enforcement

9   Network policy

Without NetworkPolicies, pods talk to everything — flat east-west, easy lateral movement.

⚑ Report as: “No NetworkPolicy — unrestricted pod-to-pod (flat) networking”
🛡 Fix: Default-deny NetworkPolicies per namespace, then allowlist required flows; restrict access to the API server and metadata from pods; segment sensitive namespaces; consider a service mesh with mTLS.

Network policy — full coverage

Checklist itemHow to testReport as
No NetworkPolicy (flat network)kubectl get netpol -ANo network segmentation
Pod-to-pod unrestrictedreachability testUnrestricted east-west
Metadata reachable from podscurl metadataMetadata reachable
Sensitive namespace not isolatedreachability testNamespace isolation gap
No mTLS between servicesreview meshNo service mTLS

10   Control-plane exposure

The API server, kubelet and dashboard are crown-jewel endpoints. Anonymous API access, an open read/write kubelet (10250), or an exposed dashboard are cluster takeover.

# Anonymous API access?
curl -sk https://<api>:6443/api/v1/namespaces/kube-system/secrets
# Kubelet read/write API (10250) — exec into pods if open
curl -sk https://<node>:10250/pods
kube-hunter --remote <api-or-node>
⚑ Report as: “Anonymous API-server access / open kubelet (10250) / exposed dashboard”
🛡 Fix: Disable anonymous auth on the API server; authenticate + authorise the kubelet (no anonymous, webhook authz, read-only port off); never expose the dashboard publicly or with a privileged SA; restrict control-plane access by network; rotate certs.

Control-plane exposure — full coverage

Checklist itemHow to testReport as
Anonymous API-server accesscurl API anonAnonymous API access
Kubelet read/write API opencurl :10250Exposed kubelet
Dashboard exposed/privilegedprobe dashboardExposed dashboard
etcd exposedprobe :2379etcd exposure
API server internet-reachablecheck exposurePublic API server
Control-plane certs weak/oldcheck certsWeak control-plane certs

11   Supply chain & admission control

What gets to run: unsigned images, no admission control, and CI/CD with cluster credentials.

⚑ Report as: “No admission control / unsigned images permitted to run”
🛡 Fix: Enforce image signing/verification at admission (cosign + policy controller); use OPA/Gatekeeper or Kyverno to block dangerous specs; least-privilege CI/CD service accounts; scan and gate in the pipeline; restrict who can deploy.

Supply chain & admission — full coverage

Checklist itemHow to testReport as
No admission control (OPA/Kyverno)check controllersNo admission control
Unsigned images rundeploy unsignedUnsigned image admitted
CI/CD over-privileged in clusterreview CI SAOver-privileged CI/CD
No pipeline scanning/gatingreview pipelineNo supply-chain gating
Mutating webhooks abusablereview webhooksWebhook abuse risk

✓   Coverage map & how to run it

Work image → runtime → breakout for containers, then the Kubernetes sections for the orchestrator. Benchmark with CIS, verify the escalation chains by hand.

SectionRun onFocus
Image/build 0–1Every imageSecrets, root, vulns, Dockerfile
Runtime/breakout 2–3Every containerPrivileged, socket, mounts, breakout
Registry 4RegistriesExposure, signing
K8s 5–11ClustersRBAC, secrets, pod security, network, control plane, supply chain

Core principle: the chain is image → container → node → cluster. A leaky image plus a dangerous runtime flag is host compromise; over-permissive RBAC or a mounted SA token turns one pod into cluster-admin. Benchmark with CIS (kube-bench/docker-bench) for breadth, but verify the breakout and RBAC escalation paths by hand — and tie findings to blast radius. Tick a box only when you've run the test.

Reactions

Related Articles