Firewall cover for listening ports
high on-server
What it inspects
`ss -tln` for wildcard LISTEN sockets, evaluated against the parsed firewall (nftables, iptables or ufw). A port the firewall drops passes, as does one with an explicit allow rule. A port open only because the default policy is accept is exposed: 1 or 2 warn, 3 or more fail. Published container ports that INPUT rules cannot protect warn. With no readable firewall, or one that does nothing, it is skipped and points to firewall_protective.
Why it matters
A default-accept firewall lets every service that starts listening become reachable, with no one having decided that. Switching to default-deny turns each open port into a deliberate choice. A port the firewall already drops is the desired state; this check never asks you to open one.
How to verify
sudo ss -tln; sudo ufw status verbose 2>/dev/null; sudo nft list ruleset 2>/dev/null
How to fix
Judgement step: allow SSH and the services that must be public, then set the input policy to deny. Which ports stay open is your decision.
Move the firewall to default-deny with explicit allow rules needs your judgement
Any distro
# These ports are reachable only because the firewall's default is "accept": no rule says they should be open.
# Fix the policy, not the service list. Do not open ports to make this check pass: a port the firewall drops is the goal.
# Decide first which ports must stay public (for example 22, 80, 443). Then:
# ufw (Debian/Ubuntu):
# ufw allow <ssh port>/tcp (the port `sshd -T | grep ^port` shows, first)
# ufw allow <port>/tcp (one line per service that must be public)
# ufw default deny incoming
# ufw --force enable
# firewalld (RHEL family): the public zone rejects anything not allowed:
# firewall-cmd --permanent --add-port=<port>/tcp (SSH and every public service first)
# firewall-cmd --reload
# nftables or iptables: add these rules FIRST, then the allow rules for SSH and public services, and only then the drop policy,
# otherwise replies to your own connections and local traffic are dropped:
# nft: ct state established,related accept
# iif lo accept (both inside the input hook chain)
# then set `policy drop;` on that chain
# iptables: iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# iptables -A INPUT -i lo -j ACCEPT
# then iptables -P INPUT DROP, last of all
# Allow SSH before any default-deny change, or you lock yourself out. See the firewall_protective check for a full snippet.
# Alternative for services that should not be public at all: bind them to 127.0.0.1 (see public_listen_anomalies).
# Docker and Podman published ports are NAT-ed and bypass the INPUT chain: restrict them where they are published,
# for example -p 127.0.0.1:<port>:<port> or rules in the DOCKER-USER chain.
# This check warns for 1-2 exposed ports and fails for 3 or more. It skips when there is no firewall to compare against.