Host exposure
The agent scans the machine it runs on for services listening on a wildcard
address (0.0.0.0 / ::) that are not in the allowlist. Ephemeral sandboxes
never run this scan; it exists for the long-lived agent host.
Docker-published ports bypass ufw: docker-proxy inserts its DNAT rules
before ufw’s rules run, so docker run -p 5432:5432 is reachable from the
network even when ufw status shows only SSH. A dev database, Redis, or a
Docker API socket published that way stays internet-exposed until someone
notices.
What the scan checks
Section titled “What the scan checks”- Reads
/proc/net/tcpand/proc/net/tcp6— no root, noss. - Flags
LISTENsockets on a wildcard address. - Ignores the allowlist and the agent’s own listeners.
- Explicit binds (loopback, LAN, tailnet) are the operator’s call.
The first scan runs at agent startup, then every host_exposure_minutes
(default 60; 0 disables). A finding is logged and sent to the Discord
webhook once per change: a persistent exposure does not repeat, and clearing
it sends an all-clear.
Fixing a finding
Section titled “Fixing a finding”- Bind the service to loopback. For a published container port use
-p 127.0.0.1:5432:5432(Compose:"127.0.0.1:5432:5432"). - If the service must be reachable publicly (a reverse proxy, a Kubernetes
node port), add it to the allowlist, e.g.
host_exposure_allow_ports=22,80,443,10250. - The next scan reports the exposure cleared.
| Key | Default | Effect |
|---|---|---|
host_exposure_minutes | 60 | Scan interval in minutes. 0 disables. |
host_exposure_allow_ports | 22,80,443 | Public TCP ports the host is expected to serve. |