← All checks

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.

References

Scan your server free