macOS includes two firewalls: the Application Firewall (socket filter) and pf (packet filter). Most users only touch the simple GUI toggle, missing the powerful pf rule engine that can statefully filter traffic, limit connections, and log anomalies. This lesson opens the hood on both layers, providing pf.conf examples that turn your Mac into a hardened endpoint that blocks unsolicited inbound connections and exfiltrates only what you allow.
The Application Firewall (System Preferences → Security → Firewall) allows or blocks incoming connections on a per-application basis. It's a higher-level socket filter, not a full packet filter. In 'Block all incoming connections' mode, only essential services (like mDNSResponder) are allowed. This is suitable for most users, but it doesn't filter outbound traffic or protect against network-based attacks on allowed services.
The socketfilterfw command-line tool allows scripting firewall settings for deployment.
pf is a stateful packet filter with a syntax similar to OpenBSD's pf. Configuration lives in /etc/pf.conf. You can create rules to block all inbound traffic except established, allow specific ports, and even filter outbound. pf is disabled by default; enable with pfctl -e. A minimal ruleset should block all inbound, allow loopback, and allow established. For advanced use, add table definitions to block known-bad IPs and implement egress filtering.
# /etc/pf.conf — block all inbound, allow established
set block-policy drop
set skip on lo0
block in all
pass out all keep state
# Optionally, block outbound to known malicious IPs
table <badhosts> persist file "/etc/pf.badhosts"
block drop out quick from any to <badhosts>💡 Use 'pfctl -sa' to see active rules, state table, and tables. Enable logging with 'block in log all' to capture denied packets in /var/log/pf.log.
| Firewall Type | Layer | Use Case |
|---|---|---|
| Application Firewall | Socket layer | Per-app inbound control, user-friendly |
| pf | Network layer 3/4 | Stateful packet filtering, egress control, threat intelligence |
For per-process outbound filtering, many security-conscious Mac users deploy Little Snitch or Lulu. These applications operate at the socket layer, prompting the user for each new outbound connection. Combined with pf for network-level filtering, this creates a robust two-tier firewall. However, malware with admin rights can disable these tools, so pairing with TCC restrictions and SIP is essential.
⚠️ pf rules are not persistent across reboots by default. Use 'sudo pfctl -f /etc/pf.conf' to load, and create a launchd plist to enable on boot (sudo pfctl -E -f /etc/pf.conf).
Verify exercises to earn ★ 150 XP and unlock next lab level.