CL-0030: Host-disclosure capability (SYSLOG)¶
Severity: HIGH
Derivation (see severity model):
- Baseline: A — the attacker already has code execution in this container, as the workload uid
- Precondition: Direct —
syslog(2)alone returns the buffer. No published technique, no second defect, and no other key in the file - Impact: Host — the kernel ring buffer is a single host-wide log; it is not namespaced, so what the container reads is the host's
- Qualifier/modifier: read-only — the realised loss is disclosure. The capability grants no write to the buffer and no execution anywhere, so the tier drops one from CRITICAL
- Derived: Direct × Host + read-only = HIGH
- Shipped: HIGH
- Scoping assumptions: none. The reach needs nothing else in the file, and — measured — does not depend on the host's
kernel.dmesg_restricteither (see Evidence) - Evidence:
_cl0030_sysloginscripts/validate_rule_premises.pyasserts the grant against a live daemon:dmesgreturns no lines at--cap-drop ALLand returns the host's buffer with--cap-add SYSLOG. The check compares line counts, never content — the host's kernel log is not something a CI log should carry. Measured on Docker 29.4.3: 0 lines capless against 1,967 with the capability, on a host wherekernel.dmesg_restrict=1blocks an unprivileged host user from reading the same buffer. The independence from that sysctl was measured rather than assumed: withkernel.dmesg_restrict=0a capless container still read 0 lines, because Docker's own default seccomp profile admits thesyslog(2)syscall only forCAP_SYSLOG. The reach is therefore gated by the capability on any host, hardened or not
References: - OWASP Docker Security Rule #3 - CIS Docker Benchmark 5.4 — Ensure that Linux kernel capabilities are restricted within containers
What it detects¶
cap_add entries naming a capability that reads host state:
| Capability | Grants | Why it is not CRITICAL |
|---|---|---|
SYSLOG |
syslog(2) against the kernel ring buffer, and the ability to read it regardless of kernel.dmesg_restrict |
Pure observation. It writes nothing, runs nothing, and breaks nothing — the loss is confidentiality alone |
CAP_-prefixed and lowercase spellings are equivalent and are matched the same
way: Docker treats CAP_SYSLOG and SYSLOG as the same capability.
Why it matters¶
The kernel ring buffer is one log for the whole machine. A container holding
SYSLOG reads the host's boot messages, its hardware and driver state, its
filesystem and network events — and on a host that leaves kernel.kptr_restrict
at 0, kernel pointers along with them, which is the address-layout
information a local exploit wants.
It reads what the host itself hides. On a host with
kernel.dmesg_restrict=1 — the hardened default on most distributions — an
unprivileged user on the host cannot read that buffer. A container granted
this one capability can. The container is not a smaller trust domain than the
host user in that comparison; it is a larger one.
The grant does not depend on the host being hardened. Docker's default
seccomp profile admits syslog(2) only when CAP_SYSLOG is held, so a capless
container reads nothing even where kernel.dmesg_restrict=0 would let any host
user read everything. That was measured, not assumed, and it is why this rule
does not carry a "depends on host configuration" caveat.
Fix¶
Remove the capability. The kernel log belongs to the host, and so does reading it:
# Before
services:
monitor:
image: myapp:1.0
cap_add:
- SYSLOG
# After — collect kernel messages on the host, not from inside a container
services:
monitor:
image: myapp:1.0
Read the buffer on the host with journalctl -k, or run the log shipper there.
A workload that needs kernel messages about its own device should be given
that device explicitly — see CL-0016 — rather than the whole
machine's log.
When to suppress¶
A host-level monitoring agent deliberately deployed as a container is the real
case: it is doing the host's job, and reading the kernel log is the job. Such
an agent usually announces itself with pid: host or a host bind mount as
well. Suppress per service with a reason: naming the agent, rather than
disabling the rule globally — the next service to ask for SYSLOG is unlikely
to be a monitoring agent.
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 |
|---|---|
| T1613 Container and Resource Discovery | Discovery |