Secure Docker containers with custom seccomp profiles. Block dangerous system calls and prevent container escape attacks programmatically.
The default Docker seccomp profile is a good starting point, but it is intentionally permissive to maintain broad compatibility. For production environments with high security requirements, writing a custom seccomp profile is one of the most effective ways to reduce the attack surface and block container escape techniques that rely on dangerous system calls.
I implemented custom seccomp profiles on several production Kubernetes clusters. This significantly reduced the risk of container breakout attacks and helped us pass strict compliance audits.
How Seccomp Works
Seccomp (Secure Computing Mode) allows you to define which Linux system calls a container is allowed to make. Docker uses a default profile that blocks around 40 dangerous syscalls. A custom profile can block many more based on your application’s actual needs.
Production-Grade Seccomp Profile
Here is a practical, hardened blacklist profile:
{
"defaultAction": "SCMP_ACT_ALLOW",
"architectures": [
"SCMP_ARCH_X86_64",
"SCMP_ARCH_X86",
"SCMP_ARCH_X32"
],
"syscalls": [
{
"comment": "Block privilege escalation, namespace manipulation, and container escapes",
"names": [
"ptrace",
"unshare",
"setns",
"clone3",
"kexec_load",
"kexec_file_load",
"stub_execveat",
"open_by_handle_at",
"mount",
"umount2",
"pivot_root"
],
"action": "SCMP_ACT_ERRNO"
},
{
"comment": "Block kernel module loading and kernel modification",
"names": [
"init_module",
"finit_module",
"delete_module",
"create_module",
"query_module"
],
"action": "SCMP_ACT_ERRNO"
},
{
"comment": "Log execution of raw socket creation or tracing to auditd instead of instant blocking",
"names": [
"perf_event_open",
"bpf",
"socket"
],
"action": "SCMP_ACT_LOG"
}
]
}Applying the Profile
For Docker:
docker run --security-opt seccomp=custom-seccomp.json \
--cap-drop=ALL \
your-imageFor Kubernetes:
securityContext:
seccompProfile:
type: Localhost
localhostProfile: custom-seccomp.jsonThe Multi-Arch Bypass Vector: Why Architecture Filtering Matters
If you look closely at our profile, we explicitly define the allowed processor architectures. This is a vital security defense. Modern 64-bit Linux kernels retain backward compatibility with 32-bit (x86) system calls via the system call multiplexer.
A 64-bit system call for write has a syscall number of 1. However, in the 32-bit ABI, syscall 1 points to exit. If an attacker compromises your 64-bit container and notices you have blocked ptrace (which is syscall 101 in x86_64), they can execute a 32-bit assembly instruction using int 0x80 instead of syscall. If your seccomp profile doesn't explicitly restrict the x86 architecture block, the kernel will execute the 32-bit equivalent of that system call, completely bypassing your x86_64 filter rules.
How to Build a Strict Whitelist Without Breaking Production
Building a Zero-Trust whitelist profile is the holy grail of seccomp, but guessing which syscalls your Node.js, Go, or Python application invokes is nearly impossible. Here is the operational pipeline to build one:
- Run your container in staging with the default action set to SCMP_ACT_LOG. This allows the application to run freely while logging all system calls to host journals.
- Simulate realistic heavy traffic on the container to trigger all execution branches.
- Extract the triggered syscalls directly from the host's system logs.
- Convert those hexadecimal system call numbers back to human-readable names using scmp_sys_resolver or a Python script.
- Populate your custom JSON profile with those mapped syscalls under SCMP_ACT_ALLOW, and apply it with confidence.
Final Thoughts
Relying on out-of-the-box container runtimes to secure multi-tenant microservices is an operational gamble. While Docker's default boundaries catch low-hanging security risks, writing custom, architecture-aware seccomp filters forces a hard boundary between user space and the host kernel. By transforming system call execution from a playground of implicit trust into a strictly enforced, audit-logged sandbox, you neutralize container escapes at the low-level API layer — well before an attacker can pivot to host infrastructure.

