Firewall audit + remediation Unified pf / nftables / iptables / ufw / firewalld / WFP audit with platform-specific fix commands.

digger ships a backend-agnostic firewall model under digger.firewall that normalizes the rules / status of every common firewall stack into a single FirewallState, runs eight checks against it, and emits remediation commands tailored to each backend. Commands are never auto-executed — they're printed, annotated where destructive, and the operator chooses.

Backends covered

Checks (seven)

IDSeverityWhat it catchesEmitted by
C1highNo default-deny inbound on the backenddigger.firewall.audit
C2infoPermissive default-allow outbound (high-assurance posture only)digger.firewall.audit
C3high/criticalInbound any-source allow on a sensitive port (database / management / SMB / RDP / Docker API) — parametric, fires once per matched portdigger.firewall.audit
C4highAny/any allow rule present (nullifies every other restriction)digger.firewall.audit
C5mediummacOS Application Firewall is OFFdigger.firewall.audit.audit_macos_appfw
C6highFirewall backend itself disableddigger.firewall.audit
C8mediumMultiple firewall backends configured simultaneously (rule precedence unclear)digger.detectors.firewall_audit (cross-backend check)

Note: the check numbering preserves slots for future additions (C7 is reserved for an IPv4-vs-IPv6 mismatch check that is not yet implemented).

Sensitive ports flagged when world-listening

22 / 23 / 111 / 135-139 / 445 / 1433 / 1521 / 2049 / 2375 (unauth Docker API!) / 3306 / 3389 / 5432 / 5900 / 5984 / 6379 / 7474 / 8086 / 8500 / 9200 / 9300 / 11211 / 27017-27018 / 28017 / 50070. Database + management ports are escalated to critical.

Remediation per backend

Each finding ships a Remedy with copy-pasteable shell commands for the matched backend. Every command routes through digger.ethics.contract.redact_dangerous_command before being shown, with a [DESTRUCTIVE] annotation on flagged ones.

Example (Linux iptables, no default-deny inbound):

$ digger firewall audit --case-dir /tmp/case --show-remedy

   1.  [    high]  iptables  C1.no-default-deny-inbound
       No default-deny inbound on iptables
       remedy:  Set iptables INPUT policy to DROP.
       why:     Default-deny inbound on both v4 and v6; preserve established + loopback.
         $ sudo iptables -P INPUT DROP
         $ sudo iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
         $ sudo iptables -A INPUT -i lo -j ACCEPT
         $ sudo ip6tables -P INPUT DROP
         $ sudo ip6tables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
         $ sudo ip6tables -A INPUT -i lo -j ACCEPT

NOTE: digger NEVER applies these commands itself. Review each one,
      then run the ones appropriate for your environment. Destructive
      commands are flagged so you can double-check before pasting.

Smoke test (real macOS host)

$ digger --no-banner collect --case-dir /tmp/fwcase \
    --only macos.firewall,macos.security_posture
$ digger --no-banner firewall audit --case-dir /tmp/fwcase --show-remedy

3 firewall finding(s):

   1.  [    high]         pf  C6.backend-disabled
       pf firewall is disabled
   2.  [    high]         pf  C1.no-default-deny-inbound
       No default-deny inbound on pf
   3.  [  medium]  socketfilterfw  C5.appfw-disabled
       macOS Application Firewall is disabled
       remedy:  Enable macOS Application Firewall.
         $ sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setglobalstate on
         $ sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setstealthmode on
         $ sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setloggingmode on

Why digger never auto-applies

P2 of the ethical contract is "observation by default". Modifying firewall posture is a non-trivial, hard-to-reverse, blast-radius-large operation. The remediation surface exists to make the operator's life easier (copy-paste vs Googling syntax), not to take agency away from them.