Skip to content

CL-0005: Ports published on 0.0.0.0 (all interfaces)

Severity: MEDIUM

Derivation (see severity model):

  • Baseline: A — the attacker already has code execution in this container, as the workload uid
  • Precondition: Second flaw — an exposed port is only a compromise if the service behind it has an exploitable defect or a weak credential
  • Impact: Single container — the service the port belongs to
  • Qualifier/modifier: pre-foothold reach — no foothold anywhere is required to reach the port, which is what this modifier prices
  • Derived: Second flaw × Single container + pre-foothold reach = HIGH
  • Shipped: MEDIUM — override detection-precision — the dangerous case is the binding that was not meant to be public, and the file does not say which is which. An exposed datastore is serious; an exposed web server is the design. Well-known datastore and admin ports are a usable proxy, so the path off this override is a split rather than a smarter matcher (ADR-020 Appendix B)
  • Evidence: _cl0005 — a bare published port binds all interfaces, verified live. Docker publishes ports by writing iptables rules directly, so the binding is reachable even where UFW or firewalld would deny it

References: - OWASP Docker Security Rule #5a - CIS Docker Benchmark 5.14 — Ensure that incoming container traffic is bound to a specific host interface

What it detects

Port mappings that don't specify a bind address or that bind to a wildcard, in both short syntax ("8080:80", "0.0.0.0:8080:80", "[::]:8080:80") and long syntax (published: without host_ip:, or with host_ip: "0.0.0.0" / host_ip: "::"). A bare short-syntax port with no colon ("80", 3001, a "3000-3005" range) is also flagged: Docker still publishes it, assigning a random (ephemeral) host port bound to all interfaces (docker compose config normalizes - "80" to a published target, and docker compose up binds it on 0.0.0.0). Bind it with 127.0.0.1::80 to keep the ephemeral port on localhost. The bind address is decided by parsing it, not by matching the spelling: every way of writing the unspecified address is the same address and publishes on every interface — 0.0.0.0, ::, [::], [::0], [0:0:0:0:0:0:0:0], [::ffff:0.0.0.0]. Specific bind addresses including loopback (127.0.0.1, [::1]) are not flagged, and a value that is not an address at all (a hostname) is not treated as a wildcard.

Why it matters

Docker publishes ports by manipulating iptables directly, bypassing host firewalls like UFW and firewalld. A port published without a bind address is accessible on all network interfaces, potentially exposing services to the public internet even when host firewall rules would otherwise block the traffic.

Fix

# Instead of (binds to all interfaces, bypasses host firewall):
ports:
  - "8080:80"

# Bind to localhost only:
ports:
  - "127.0.0.1:8080:80"

# Long syntax:
ports:
  - target: 80
    published: 8080
    host_ip: "127.0.0.1"

If this service needs to be publicly accessible, place it behind a reverse proxy (Traefik, Caddy, nginx) that handles TLS termination, and bind only the reverse proxy's ports publicly.

For systemic mitigation, configure the DOCKER-USER iptables chain on the host so that Docker's bypass of UFW/firewalld becomes per-rule rather than per-service. This is documented in Docker and iptables. Per-service binding is whack-a-mole; the chain-level rule is the durable fix.

Swarm caveat

host_ip in the long syntax is not always honored under Swarm mode — Swarm uses an ingress mesh and may publish ports on all manager nodes regardless. If you're targeting Swarm, port publishing is a Swarm concern; this rule still flags the file but treat the fix as Swarm-specific.

When to suppress

  • Public-facing service on a VPS where the cloud provider's firewall is the security boundary and 0.0.0.0 is intended. Suppress with a reason: naming the firewall layer (e.g. reason: "GCP firewall enforces ingress; UFW disabled by design").

ATT&CK coverage

No adversary technique maps to this rule. That is a finding about the rule, not an omission — see below.

It does enable T1190 Exploit Public-Facing Application, but enabling is not the same as being a technique: the misconfiguration widens the attack surface an adversary can reach rather than supplying a step they execute.

See also

  • CL-0008network_mode: host (port-publish controls don't apply at all)