# CL-0016: Dangerous Host Device Exposed

**Severity:** HIGH

**References:**
- CIS Docker Benchmark 5.18 — Ensure that host devices are not directly exposed to containers

## What it detects

Services that expose dangerous host devices via `devices:`:

| Pattern | Risk |
|---------|------|
| `/dev/mem` | Raw physical memory access |
| `/dev/kmem` | Kernel virtual memory |
| `/dev/port` | Raw I/O port access |
| `/dev/sd*` | SCSI/SATA block devices — raw disk read/write |
| `/dev/nvme*` | NVMe block devices — raw disk read/write |
| `/dev/disk/*` | Block device symlinks — same risk as raw devices |
| `/dev/loop*` | Loop devices — mount arbitrary disk images |
| `/dev/dm-*`, `/dev/mapper/*` | Device mapper — encrypted/LVM volumes, raw block access |
| `/dev/zfs` | ZFS pool control — create/destroy/import any pool the host can see |
| `/dev/rbd*` | Ceph RBD — remote block device access |
| `/dev/raw*` | Raw character devices |
| `/dev/fuse` | Userspace filesystem mounts — enables mount-based container escapes |
| `/dev/kmsg` | Kernel log buffer — read or inject kernel messages |

Safe devices like `/dev/net/tun` are not flagged.

## Why it matters

Exposing raw memory or block devices bypasses all container isolation. Block device access enables reading and overwriting the host filesystem directly, regardless of mount permissions; loop and device-mapper access lets a container construct arbitrary block devices and mount them. ZFS and Ceph control devices grant pool/cluster-level operations that affect everything that runtime can see.

These are equivalent to giving the container full root access to the host's storage.

### Caveat on `/dev/mem` and `/dev/kmem`

On modern Linux distributions (`CONFIG_STRICT_DEVMEM=y`, the default on Debian, Ubuntu, RHEL, Arch), even root can only read a small set of architecture-mapped pages from `/dev/mem`. `CONFIG_IO_STRICT_DEVMEM` further restricts that to non-busy regions. `/dev/kmem` is not built into most modern kernels at all (`CONFIG_DEVKMEM` is off).

This rule still flags them — the worst-case kernel config (older or hardened-for-debugging hosts) gives full physical/virtual memory read/write, and the rule cannot inspect the host kernel from a static lint pass. Treat these findings as "this works against any kernel that allows it" and triage accordingly.

## Fix

Remove the dangerous device. If you need specific hardware access, prefer narrower mechanisms:

- `device_cgroup_rules:` — express exactly which devices the container may access
- A single specific device entry (e.g. `/dev/ttyUSB0`) instead of a wildcard or whole subtree
- Kernel-level offload (e.g. user-space NVMe via SPDK) where a container shouldn't need block-device access at all

## Fix

Remove the dangerous device. If you need specific hardware access, consider whether a more constrained approach exists:

```yaml
# Before
services:
  app:
    image: myapp:1.0
    devices:
      - /dev/sda:/dev/sda

# After — use volumes for disk data access
services:
  app:
    image: myapp:1.0
    volumes:
      - /data:/app/data:ro
```

If raw device access is genuinely required (e.g., for disk management tooling), the workload should not run in a container.

## See also

- [CL-0013](CL-0013.md) — bind-mounting `/dev` whole (parallel risk at the path-mount level)
- [CL-0002](CL-0002.md) — `privileged: true` (grants every device the host has)
