CDK: The Zero-Dependency Pentesting Toolkit Built for Container Escapes
Hook
Your Alpine container has no shells, no package manager, and no standard utilities—yet you need to test if it can escape to the host. This is exactly the scenario CDK was built for.
Context
Traditional penetration testing tools were designed for full-featured operating systems with package managers, interpreters, and standard UNIX utilities. But the rise of slim containers, distroless images, and security-hardened Kubernetes clusters has created environments where these assumptions break down. A Python-based exploit script is useless in a container without Python. Metasploit won't run without Ruby and its gem dependencies. Even basic reconnaissance becomes impossible when containers lack ps, netstat, or ifconfig.
CDK emerged from the container security community's need for a tool that works in these constrained environments. Built in Go and compiled as a single static binary, it requires zero system dependencies—no libc, no interpreters, no shared libraries. The tool specifically targets the attack surface unique to containerized workloads: excessive Linux capabilities, exposed Docker sockets, cgroup manipulation vectors, container runtime CVEs, and Kubernetes service account misconfigurations. It's not trying to replace general-purpose pentesting frameworks; it's laser-focused on the container escape problem.
Technical Insight
CDK's architecture revolves around three command categories that mirror a typical container penetration workflow: evaluate, exploit, and tool. The evaluate module performs automated reconnaissance by checking for container weaknesses—privileged mode, dangerous capabilities like CAP_SYS_ADMIN or CAP_SYS_PTRACE, mounted Docker sockets, writable cgroup paths, and accessible Kubernetes service accounts. It returns a scored assessment with recommended exploitation paths.
The exploit implementations are where CDK shines technically. Consider the classic Docker socket escape. Many containers have /var/run/docker.sock mounted for legitimate reasons (CI/CD agents, monitoring tools), but this grants full Docker daemon access. CDK's implementation doesn't just mount a volume—it uses a multi-stage approach:
// Simplified example based on CDK's docker.sock exploitation
func exploitDockerSocket() {
// Create privileged container with host root mounted
config := container.Config{
Image: "alpine",
Cmd: []string{"/bin/sh", "-c", "chroot /host sh"},
}
hostConfig := container.HostConfig{
Privileged: true,
Binds: []string{"/:/host"},
}
// Use Docker API via Unix socket
cli, _ := client.NewClientWithOpts(
client.WithHost("unix:///var/run/docker.sock"),
)
// Spawn escape container
resp, _ := cli.ContainerCreate(ctx, &config, &hostConfig, nil, nil, "")
cli.ContainerStart(ctx, resp.ID, types.ContainerStartOptions{})
}
This pattern—spawn a privileged container, mount the host filesystem, chroot into it—is a well-known technique, but CDK packages it into a single command that handles edge cases like different Docker API versions, credential discovery, and cleanup.
The capability-based exploits demonstrate sophisticated understanding of Linux kernel internals. When CDK detects CAP_SYS_ADMIN (often granted unnecessarily), it can leverage this to manipulate the release_agent mechanism in cgroups. This technique writes a payload path to the cgroup's release_agent file, which the kernel executes with full host privileges when the cgroup's last process exits. CDK automates the entire chain: checking writability of cgroup mounts, crafting the payload, triggering the release_agent, and establishing a reverse shell.
The tool module deserves special attention because it reimplements common utilities entirely in Go. When you run cdk run ps, you're not calling /bin/ps—CDK reads /proc directly and formats the output. The nc implementation creates raw TCP listeners and clients using Go's net package. The vi clone provides basic text editing by manipulating terminal escape codes. This might seem like reinventing the wheel, but it's essential for working in environments where these utilities don't exist. The implementations are intentionally minimal—just enough functionality to accomplish pentesting tasks without bloating the binary size.
CDK also includes Kubernetes-specific capabilities that recognize the platform's unique attack surface. It automatically discovers service account tokens mounted at /var/run/secrets/kubernetes.io/serviceaccount/, tests their permissions against the API server, and can enumerate pods, secrets, and configmaps. For cloud environments, it includes metadata service clients for AWS, Azure, and GCP that attempt to extract IAM credentials or instance information—valuable for lateral movement beyond the container itself.
The binary itself is compiled with CGO_ENABLED=0 to produce a truly static binary. This means it contains its own implementation of even low-level networking and system call interfaces, with no reliance on glibc or musl. The resulting binary is typically 10-15MB—small enough to transfer over slow network connections or exfiltrate if needed, but comprehensive enough to replace a full pentesting toolkit.
Gotcha
CDK's offensive focus is both its strength and limitation. It excels at exploiting misconfigurations but provides minimal guidance on remediation. After identifying that a container has CAP_SYS_ADMIN, it will show you how to exploit it, but won't help you architect capability-minimal deployments. The tool also lacks defensive features—no compliance checking, no policy enforcement, no continuous monitoring. It's a scalpel for authorized penetration testing, not a shield for ongoing security posture management.
Detection is another significant concern. CDK's techniques are well-documented in its public repository, meaning mature security monitoring solutions specifically watch for its signatures. The cgroup release_agent manipulation, Docker socket API calls, and capability abuse patterns all generate distinctive audit logs. Running CDK in production environments with modern runtime security tools (Falco, Aqua, Sysdig) will likely trigger alerts. Some exploits also require specific kernel versions or runtime configurations that may not match your target environment—the runc CVE exploits, for instance, only work against vulnerable versions. The evaluate module helps identify applicable exploits, but you may still waste time on techniques that won't work in your specific setup. Documentation fragmentation across wiki pages and code comments means you'll sometimes need to read the Go source to understand exact prerequisites or failure modes for specific exploits.
Verdict
Use CDK if: You're conducting authorized security assessments of containerized environments and need a tool that works in slim/distroless containers where traditional pentesting toolkits fail. It's particularly valuable for red team exercises focused on container escapes, testing Kubernetes security controls, or validating runtime security monitoring. The zero-dependency binary makes it ideal when you've gained initial access to a locked-down container and need to escalate privileges. Skip if: You need defensive security tooling, compliance scanning, or vulnerability management—CDK is explicitly offensive. Also skip if you're working without proper authorization; this tool is designed for authorized testing only and its use will likely be detected by modern security monitoring. For ongoing security posture management, static analysis, or CI/CD integration, look at Trivy, Falco, or OPA/Gatekeeper instead. CDK is for breaking in, not keeping adversaries out.