CL-0009: Disabled seccomp and AppArmor profiles¶
Severity: HIGH
Derivation (see severity model):
- Baseline: A — the attacker already has code execution in this container, as the workload uid
- Precondition: Second flaw — removing the syscall filter and the LSM profile grants nothing on its own. It widens the kernel attack surface, and landing an escape still needs a kernel defect
- Impact: Cross-container — the exposed surface is the kernel, shared by every container on the host
- Qualifier/modifier: none
- Derived: Second flaw × Cross-container = HIGH
- Shipped: HIGH
- Evidence:
_cl0009(a seccomp filter is active by default). The gate is capability-shaped rather than absolute: at default capabilitiesbpf(2)andinit_module(2)return EPERM, and with the matching capability added they reach the kernel and fail on their arguments instead (EINVAL, ENOEXEC) — verified live on Docker 29.1.3
References: - OWASP Docker Security Rule #6 - CIS Docker Benchmark 5.22 — Ensure that the default seccomp profile is not Disabled - CIS Docker Benchmark 5.2 — Ensure that, if applicable, an AppArmor Profile is enabled - CIS Docker Benchmark 5.3 — Ensure that, if applicable, SELinux security options are set
What it detects¶
Any service with seccomp:unconfined, apparmor:unconfined, or label:disable in security_opt.
This rule only flags explicitly disabled profiles. Services that omit security_opt entirely are not flagged — the host applies default profiles automatically. Custom profiles (e.g., seccomp:custom.json) and SELinux label overrides that don't disable confinement (e.g., label:user:system_u) are also not flagged. SELinux label:type:spc_t (super-privileged container) is functionally similar to label:disable but is currently out of scope for this rule — it requires SELinux-specific knowledge of type transitions to evaluate.
Why it matters¶
Linux distributions apply security profiles by default:
-
seccomp: Docker's default profile (
profiles/seccomp/default.json) blocks dozens of syscalls outright and gates many more behind a specific capability. Disabling it gives the container the kernel's full unrestricted syscall surface — a massively expanded attack surface for kernel exploits.The gate is mostly capability-shaped rather than absolute, which matters when reasoning about what the profile is actually protecting. At default capabilities
bpf(2)andinit_module(2)both return EPERM; addBPForSYS_MODULEand the same calls reach the kernel and fail on their arguments instead — EINVAL and ENOEXEC respectively (verified on Docker 29.1.3). So the default profile is not what stands between a container and those syscalls; the capability set is, and dropping capabilities (CL-0006) is the control that closes them.kexec_load(2)is the counter-example that stays shut: it returns EPERM even withSYS_BOOTheld. - AppArmor: Docker's default profile (docker-default) restricts file paths in/procand/sys, blocks ptrace of host processes, and deny-lists/proc/kcoreand similar. Disabling it removes those mandatory access controls beyond what capabilities alone enforce. - SELinux: On RHEL-family hosts, applies type enforcement via labels (container_t) that confine what files and processes a container can access.label:disableturns off type-enforcement confinement for the container; the container then runs in the calling user's domain, which on a typical container host isunconfined_t.
Explicitly disabling any of these is an intentional weakening of container isolation that should only be done with strong justification.
Fix¶
Remove the unconfined profile — Docker's defaults apply automatically:
# Before
services:
web:
image: nginx:1.27-alpine
security_opt:
- seccomp:unconfined
# After
services:
web:
image: nginx:1.27-alpine
security_opt:
- no-new-privileges:true
If your application requires specific syscalls blocked by the default profile, create a custom seccomp profile rather than disabling it entirely:
security_opt:
- seccomp:custom-seccomp.json
When to suppress¶
- A debugger or tracer that genuinely needs
ptraceof arbitrary syscalls — narrow to a custom profile if at all possible, and never run it on a production network. - Sandboxes that need to run their own seccomp profile (browsers, language runtimes) —
seccomp:unconfinedis sometimes the documented way to let the inner sandbox install its filter. Suppress only when verified.
ATT&CK coverage¶
Remediating this finding contributes to mitigating the following MITRE ATT&CK techniques (pinned to ATT&CK v18). compose-lint is a static analyser, so this is mitigation coverage — it detects nothing at runtime.
| Technique | Tactic |
|---|---|
| T1685 Disable or Modify Tools | Defense Impairment |