Description
Most host firewalls only filter incoming traffic. This control requires the default policy for outgoing packets to drop or reject them, so that the system can only reach the destinations and ports allowed by explicit rules (DNS, NTP, package mirrors, proxies, log collectors...):
- with ufw:
deny (outgoing)orreject (outgoing)inufw status verbose; - with nftables (when
nftables.serviceis enabled and ufw is not active): a base chain on theoutputhook withpolicy drop; - with iptables-persistent (when
netfilter-persistent.serviceis enabled and neither ufw nor nftables is):OUTPUTpolicyDROPfor iptables and, with IPv6, ip6tables.
Rationale
An outgoing allow list stops a compromised service from downloading a second stage, reaching a command and control server or sending data out directly. Blocked attempts also show up in the firewall logs.
Impact
Every outgoing flow the system needs must be listed beforehand, including DNS, NTP, package updates and replies handled outside connection tracking. A missing rule breaks updates, time synchronization or name resolution. There is no automatic fix for this reason.
Audit
- ufw:
ufw status verboseshowsdeny (outgoing)orreject (outgoing). - nftables:
nft list rulesethas a chain withhook outputandpolicy drop. - iptables-persistent:
iptables -Sandip6tables -Sshow-P OUTPUT DROP.
Automated: every check must pass. Scanners report each check by its id.
ufw-outgoing
ufw default policy for outgoing traffic.
script: |
ufw status 2>/dev/null | grep -q '^Status: active' || { echo 'ufw is not active'; exit 2; }
d=$(ufw status verbose 2>/dev/null | sed -n 's/^Default: //p')
echo "$d"
printf '%s' "$d" | grep -Eq '(deny|reject) \(outgoing\)'
nft-output
nftables output base chain with policy drop.
script: |
[ "$(systemctl is-enabled nftables.service 2>/dev/null)" = enabled ] || { echo 'nftables.service is not enabled'; exit 2; }
if command -v ufw >/dev/null 2>&1 && ufw status 2>/dev/null | grep -q '^Status: active'; then
echo 'ufw manages the firewall'; exit 2
fi
r=$(nft list ruleset 2>/dev/null) || exit 3
if printf '%s\n' "$r" | grep -Eq 'hook output .*policy drop'; then echo 'output: policy drop'; else echo 'output: no chain with policy drop'; exit 1; fi
iptables-output
iptables and ip6tables OUTPUT policy with iptables-persistent.
script: |
[ "$(systemctl is-enabled netfilter-persistent.service 2>/dev/null)" = enabled ] || { echo 'netfilter-persistent.service is not enabled'; exit 2; }
if command -v ufw >/dev/null 2>&1 && ufw status 2>/dev/null | grep -q '^Status: active'; then
echo 'ufw manages the firewall'; exit 2
fi
[ "$(systemctl is-enabled nftables.service 2>/dev/null)" = enabled ] && { echo 'nftables manages the firewall'; exit 2; }
PATH="$PATH:/usr/sbin"
rc=0
for t in iptables ip6tables; do
[ "$t" = ip6tables ] && [ ! -d /proc/sys/net/ipv6 ] && continue
r=$($t -S OUTPUT 2>/dev/null) || exit 3
if printf '%s\n' "$r" | grep -Eq '^-P OUTPUT (DROP|REJECT)$'; then echo "$t OUTPUT: DROP"; else echo "$t OUTPUT: not DROP"; rc=1; fi
done
exit "$rc"
Remediation
- List the outgoing flows the system needs (
ss -tunpover a typical day, the configured DNS, NTP and package mirrors, proxies, log and backup servers). - Allow them, then change the default:
- ufw:
ufw allow out 53,ufw allow out 123/udp,ufw allow out to <mirror> port 443 proto tcp... thenufw default deny outgoing; - nftables: add an
outputbase chain withpolicy drop;, a rulect state established,related accept,oif lo acceptand one rule per flow; - iptables-persistent: add the
OUTPUTrules for each flow, theniptables -P OUTPUT DROP(and ip6tables), andnetfilter-persistent save.
- ufw:
- Check name resolution, time synchronization and
apt updateright after the change.
Rollback
ufw: ufw default allow outgoing. nftables: set the output chain policy back to accept
and reload. iptables: iptables -P OUTPUT ACCEPT, ip6tables -P OUTPUT ACCEPT, then
netfilter-persistent save.
References
- ufw(8), Ubuntu manual pages Canonical, vendor-doc, accessed 2026-10-19
- nft(8), Ubuntu manual pages Canonical, vendor-doc, accessed 2026-10-19
- NIST SP 800-41 Rev. 1 - Guidelines on Firewalls and Firewall Policy NIST, guide, accessed 2026-10-19
Mappings
| Framework | ID | Relation | Note |
|---|---|---|---|
| NIST SP 800-53 Rev. 55.1.1 | SC-7(5) | partial |
How this control relates to the other framework's: equivalent, stricter, looser, partial or related.
Threats mitigated
Related controls
- requires
CB-UBU-NET-005Run exactly one host firewall
People and lifecycle
| Authors |
|
| Verified | 2026-10-19 by Sn0wAlice on 20.04, Proxmox VM, Ubuntu 20.04 cloud image, kernel 5.4.0-216-generic, BIOS boot. Profile server-hardened; ufw allow outgoing reported, deny outgoing passes with SSH still accepted; nftables output drop and iptables-persistent output policy checks tested. |
| Verified | 2026-10-19 by Sn0wAlice on 22.04, Proxmox VM, Ubuntu 22.04 cloud image, kernel 5.15.0-198-generic, BIOS boot. Profile server-hardened; ufw allow outgoing reported, deny outgoing passes with SSH still accepted. |
| Verified | 2026-10-19 by Sn0wAlice on 24.04, Proxmox VM, Ubuntu 24.04 cloud image, kernel 6.8.0-147-generic, BIOS boot. Profile server-hardened; ufw allow outgoing reported, deny outgoing passes with SSH still accepted. |
| Verified | 2026-10-19 by Sn0wAlice on 26.04, Proxmox VM, Ubuntu 26.04 cloud image, kernel 7.0.0-38-generic, BIOS boot. Profile server-hardened; ufw allow outgoing reported, deny outgoing passes with SSH still accepted; nftables output drop and iptables-persistent output policy checks tested. |
| Introduced in | v0.1.0 |
| Created, updated | 2026-10-19, 2026-10-19 |
| Translations | fr |