| name | macos-security-privacy-hardening |
| description | Secure and harden macOS systems following enterprise-standard security practices and privacy guidelines |
| triggers | ["how do I secure my macOS system","harden macOS security settings","configure macOS privacy and security","setup FileVault and firmware password","configure macOS firewall and DNS encryption","secure macOS installation and setup","macOS security best practices","improve macOS privacy settings"] |
macOS Security and Privacy Hardening
Skill by ara.so — Security Skills collection.
This skill provides comprehensive guidance for securing and hardening macOS systems based on the drduh/macOS-Security-and-Privacy-Guide. It covers security configurations, privacy settings, encryption, firewalls, and monitoring for Apple silicon Macs running currently supported macOS versions.
Overview
The macOS Security and Privacy Guide provides enterprise-standard security practices for:
- System hardening: Firmware passwords, FileVault encryption, secure boot
- Privacy protection: Disabling telemetry, configuring DNS encryption, certificate management
- Network security: Firewalls, VPN configuration, DNS filtering
- Access control: User account separation, authentication policies
- Monitoring: System auditing, network monitoring, execution tracking
Important: This guide targets Apple silicon Macs. Intel Macs have unpatched hardware vulnerabilities and are not recommended.
Threat Modeling
Before applying security measures, create a threat model:
Identify Assets
List what you're protecting:
- Devices (phone, laptop)
- Data (passwords, browsing history, documents)
- Accounts (email, banking, social media)
Identify Adversaries
Define who you're defending against:
- Casual attacker: Roommate, opportunistic thief
- Criminal: Malware distribution, financial fraud
- Corporation: Data collection, behavioral tracking
- Nation state/APT: Targeted surveillance, advanced persistent threats
Example Threat Model Table
| Adversary | Motivation | Capabilities | Mitigation |
|--------------|-------------------|----------------------------|--------------------------------------|
| Roommate | Privacy invasion | Physical access to device | Use biometrics, screen lock |
| Thief | Financial gain | Steal unlocked device | Find My, device encryption |
| Criminal | Financial | Malware, social engineering| Sandboxing, automatic updates |
| Corporation | Data marketing | Telemetry collection | Block connections, disable telemetry |
| Nation State | Surveillance | Network monitoring | E2EE, strong passwords, hardware keys|
System Installation
Secure Installation Process
-
Download macOS: Use the latest supported version for your Mac
sw_vers
softwareupdate --list
sudo softwareupdate --install --all
-
Create bootable installer (if doing clean install):
sudo /Applications/Install\ macOS\ Sonoma.app/Contents/Resources/createinstallmedia \
--volume /Volumes/MyVolume
-
System Activation: Apple silicon Macs require activation with Apple servers during installation for theft prevention
Initial Setup
Skip Apple Account creation during setup if not needed. You can install system updates without an Apple Account:
sudo defaults write /Library/Preferences/com.apple.SoftwareUpdate AutomaticCheckEnabled -bool true
sudo defaults write /Library/Preferences/com.apple.SoftwareUpdate AutomaticDownload -bool true
sudo defaults write /Library/Preferences/com.apple.SoftwareUpdate AutomaticallyInstallMacOSUpdates -bool true
Admin and User Accounts
Principle of Least Privilege
Separate admin and standard user accounts:
dscl . list /Users | grep -v '^_'
sudo dscl . -create /Users/USERNAME
sudo dscl . -create /Users/USERNAME UserShell /bin/zsh
sudo dscl . -create /Users/USERNAME RealName "User Name"
sudo dscl . -create /Users/USERNAME UniqueID 501
sudo dscl . -create /Users/USERNAME PrimaryGroupID 20
sudo dscl . -create /Users/USERNAME NFSHomeDirectory /Users/USERNAME
sudo dscl . -passwd /Users/USERNAME
sudo dscl . -append /Groups/com.apple.access_ssh GroupMembership USERNAME
sudo createhomedir -c -u USERNAME
dscl . -read /Groups/admin GroupMembership
Require Administrator Password
sudo security authorizationdb write system.preferences authenticate-admin
sudo pwpolicy -setglobalpolicy "minChars=12 requiresAlpha=1 requiresNumeric=1"
Firmware Password
Set a firmware password to prevent booting from external media:
sudo firmwarepasswd -check
FileVault Encryption
Enable full-disk encryption:
sudo fdesetup status
sudo fdesetup enable
sudo fdesetup list
sudo fdesetup add -usertoadd USERNAME
sudo fdesetup changepassword -user USERNAME
Important: Save the recovery key in a secure location. Without it, data is unrecoverable if you forget your password.
Lockdown Mode
For high-threat models, enable Lockdown Mode:
defaults read /Library/Preferences/com.apple.security LockdownModeEnabled
Lockdown Mode restrictions:
- Most message attachments blocked
- Web technologies restricted (JIT, fonts)
- Wired connections blocked when locked
- Configuration profiles blocked
Firewall Configuration
Application Layer Firewall
sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setglobalstate on
sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setloggingmode on
sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setstealthmode on
sudo /usr/libexec/ApplicationFirewall/socketfilterfw --getglobalstate
Packet Filter (PF)
Create advanced firewall rules with PF:
sudo nano /etc/pf.conf
Example /etc/pf.conf:
# Interfaces
ext_if = "en0"
lo_if = "lo0"
# Default deny
set block-policy drop
set skip on lo
# Scrub incoming packets
scrub in all
# Block all by default
block log all
# Allow established connections
pass in quick proto tcp from any to any flags S/SA keep state
pass out quick keep state
# Allow DNS
pass out quick proto {tcp udp} to any port 53
# Allow HTTPS
pass out quick proto tcp to any port 443
# Allow NTP
pass out quick proto udp to any port 123
# Block Facebook, Google, etc. (example)
table <blocklist> persist file "/etc/pf.blocklist"
block drop quick from any to <blocklist>
Create blocklist:
sudo nano /etc/pf.blocklist
Example /etc/pf.blocklist:
# Facebook
31.13.64.0/18
66.220.144.0/20
69.63.176.0/20
# Google
216.58.192.0/19
172.217.0.0/16
Enable PF:
sudo pfctl -vnf /etc/pf.conf
sudo pfctl -ef /etc/pf.conf
sudo pfctl -sr
sudo pfctl -si
sudo pfctl -F all
Disable Services
Minimize attack surface by disabling unnecessary services:
defaults write com.apple.safari UniversalSearchEnabled -bool false
defaults write com.apple.safari SuppressSearchSuggestions -bool true
defaults write com.apple.assistant.support "Assistant Enabled" -bool false
launchctl disable "user/$UID/com.apple.assistantd"
launchctl disable "gui/$UID/com.apple.assistantd"
sudo launchctl disable 'system/com.apple.assistantd'
defaults write ~/Library/Preferences/ByHost/com.apple.coreservices.useractivityd ActivityAdvertisingAllowed -bool false
defaults write ~/Library/Preferences/ByHost/com.apple.coreservices.useractivityd ActivityReceivingAllowed -bool false
defaults write com.apple.NetworkBrowser DisableAirDrop -bool true
sudo defaults write /Library/Preferences/com.apple.mDNSResponder.plist NoMulticastAdvertisements -bool true
sudo defaults write /Library/Preferences/com.apple.driver.AppleIRController DeviceEnabled -bool false
sudo defaults write /Library/Preferences/com.apple.Bluetooth ControllerPowerState -int 0
sudo killall -HUP bluetoothd
DNS Configuration
DNS Encryption with DNSCrypt
Install and configure DNSCrypt-proxy:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
brew install dnscrypt-proxy
nano $(brew --prefix)/etc/dnscrypt-proxy.toml
Example DNSCrypt configuration:
server_names = ['cloudflare', 'cloudflare-ipv6']
listen_addresses = ['127.0.0.1:53']
max_clients = 250
ipv4_servers = true
ipv6_servers = true
dnscrypt_servers = true
doh_servers = true
require_dnssec = true
require_nolog = true
require_nofilter = false
force_tcp = false
[query_log]
file = '/var/log/dnscrypt-proxy/query.log'
[nx_log]
file = '/var/log/dnscrypt-proxy/nx.log'
[sources]
[sources.'public-resolvers']
urls = ['https://raw.githubusercontent.com/DNSCrypt/dnscrypt-resolvers/master/v3/public-resolvers.md']
cache_file = 'public-resolvers.md'
minisign_key = 'RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3'
refresh_delay = 72
Start DNSCrypt:
sudo mkdir -p /var/log/dnscrypt-proxy
sudo brew services start dnscrypt-proxy
networksetup -setdnsservers Wi-Fi 127.0.0.1
networksetup -setdnsservers Ethernet 127.0.0.1
scutil --dns
DNS Configuration Profiles
Create a configuration profile for encrypted DNS:
cat > ~/cloudflare-dns.mobileconfig << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PayloadContent</key>
<array>
<dict>
<key>DNSSettings</key>
<dict>
<key>DNSProtocol</key>
<string>HTTPS</string>
<key>ServerAddresses</key>
<array>
<string>1.1.1.1</string>
<string>1.0.0.1</string>
</array>
<key>ServerURL</key>
<string>https://cloudflare-dns.com/dns-query</string>
</dict>
<key>PayloadType</key>
<string>com.apple.dnsSettings.managed</string>
<key>PayloadIdentifier</key>
<string>com.cloudflare.1dot1dot1dot1</string>
<key>PayloadUUID</key>
<string>A1E3F4E3-5B4A-4F1E-8E3D-123456789ABC</string>
<key>PayloadDisplayName</key>
<string>Cloudflare DNS</string>
<key>PayloadVersion</key>
<integer>1</integer>
</dict>
</array>
<key>PayloadType</key>
<string>Configuration</string>
<key>PayloadIdentifier</key>
<string>com.cloudflare.1dot1dot1dot1</string>
<key>PayloadUUID</key>
<string>B2F4G5F4-6C5B-5G2F-9F4E-234567890BCD</string>
<key>PayloadDisplayName</key>
<string>Cloudflare DNS</string>
<key>PayloadVersion</key>
<integer>1</integer>
</dict>
</plist>
EOF
sudo profiles install -path ~/cloudflare-dns.mobileconfig
sudo profiles list
Hosts File Blocking
Block tracking domains via hosts file:
sudo cp /etc/hosts /etc/hosts.backup
curl https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts | \
sudo tee -a /etc/hosts
sudo nano /etc/hosts
Example custom hosts entries:
# Block Facebook
0.0.0.0 facebook.com
0.0.0.0 www.facebook.com
0.0.0.0 m.facebook.com
# Block Google Analytics
0.0.0.0 google-analytics.com
0.0.0.0 www.google-analytics.com
0.0.0.0 ssl.google-analytics.com
# Block ads
0.0.0.0 ads.example.com
0.0.0.0 tracking.example.com
Flush DNS cache:
sudo dscacheutil -flushcache
sudo killall -HUP mDNSResponder
Certificate Management
Manage trusted root certificates:
security dump-keychain -d /System/Library/Keychains/SystemRootCertificates.keychain
security export -k /System/Library/Keychains/SystemRootCertificates.keychain \
-t certs -o ~/root-certs.pem
sudo security delete-certificate -c "CNNIC ROOT" \
/System/Library/Keychains/SystemRootCertificates.keychain
sudo security add-trusted-cert -d -r trustRoot \
-k /Library/Keychains/System.keychain ~/custom-ca.crt
security find-certificate -c "Certificate Name" -p \
/System/Library/Keychains/SystemRootCertificates.keychain | \
openssl x509 -text -noout
Browser Security
Firefox Hardening
Install Firefox and configure for privacy:
brew install --cask firefox
Create user.js for privacy:
user_pref("toolkit.telemetry.enabled", false);
user_pref("toolkit.telemetry.unified", false);
user_pref("datareporting.healthreport.uploadEnabled", false);
user_pref("datareporting.policy.dataSubmissionEnabled", false);
user_pref("privacy.trackingprotection.enabled", true);
user_pref("privacy.trackingprotection.socialtracking.enabled", true);
user_pref("privacy.trackingprotection.fingerprinting.enabled", true);
user_pref("privacy.trackingprotection.cryptomining.enabled", true);
user_pref("dom.security.https_only_mode", true);
user_pref("dom.security.https_only_mode_ever_enabled", true);
user_pref("media.peerconnection.enabled", false);
user_pref("network.trr.mode", 2);
user_pref("network.trr.uri", "https://cloudflare-dns.com/dns-query");
(, );
(, );
(, );
(, );
(, );
(, );
(, );
Safari Hardening
defaults write com.apple.Safari PreloadTopHit -bool false
defaults write com.apple.Safari UniversalSearchEnabled -bool false
defaults write com.apple.Safari SuppressSearchSuggestions -bool true
defaults write com.apple.Safari WebKitPreferences.privateClickMeasurementEnabled -bool false
defaults write com.apple.Safari SendDoNotTrackHTTPHeader -bool true
defaults write com.apple.Safari AutoFillPasswords -bool false
defaults write com.apple.Safari AutoFillCreditCardData -bool false
defaults write com.apple.Safari WarnAboutFraudulentWebsites -bool true
defaults write com.apple.Safari com.apple.Safari.ContentPageGroupIdentifier.WebKit2JavaEnabled -bool false
defaults write com.apple.Safari com.apple.Safari.ContentPageGroupIdentifier.WebKit2JavaEnabledForLocalFiles -bool false
defaults write com.apple.Safari com.apple.Safari.ContentPageGroupIdentifier.WebKit2JavaScriptCanOpenWindowsAutomatically -bool false
VPN Configuration
WireGuard Setup
brew install wireguard-tools
umask 077
wg genkey | tee privatekey | wg pubkey > publickey
sudo nano /usr/local/etc/wireguard/wg0.conf
Example WireGuard configuration:
[Interface]
PrivateKey = <PRIVATE_KEY_FROM_FILE>
Address = 10.0.0.2/24
DNS = 1.1.1.1
[Peer]
PublicKey = <SERVER_PUBLIC_KEY>
Endpoint = vpn.example.com:51820
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 25
Start WireGuard:
sudo wg-quick up wg0
sudo wg show
sudo wg-quick down wg0
sudo ln -sf /usr/local/etc/wireguard/wg0.conf /usr/local/etc/wireguard/wg0.conf
PGP/GPG Configuration
Install and configure GPG:
brew install gnupg
gpg --full-generate-key
gpg --list-secret-keys --keyid-format LONG
gpg --armor --export YOUR_EMAIL > publickey.asc
gpg --armor --export-secret-keys YOUR_EMAIL > privatekey.asc
gpg --encrypt --recipient YOUR_EMAIL file.txt
gpg --decrypt file.txt.gpg > file.txt
gpg --sign file.txt
gpg --verify file.txt.gpg
Configure GPG agent:
mkdir -p ~/.gnupg
chmod 700 ~/.gnupg
nano ~/.gnupg/gpg-agent.conf
GPG agent configuration:
default-cache-ttl 600
max-cache-ttl 7200
enable-ssh-support
pinentry-program /usr/local/bin/pinentry-mac
gpgconf --kill gpg-agent
gpg-agent --daemon
System Monitoring
OpenBSM Audit
Enable system auditing:
sudo audit -s
sudo audit -i
sudo nano /etc/security/audit_control
Example audit configuration:
dir:/var/audit
flags:lo,ad,fd,fm,-all
minfree:5
naflags:lo,aa
policy:cnt,argv
filesz:2M
expire-after:10M
Start auditing:
sudo launchctl load -w /System/Library/LaunchDaemons/com.apple.auditd.plist
sudo praudit -xn /var/audit/current
Network Monitoring
Monitor network connections:
sudo lsof -i
sudo lsof -i :443
sudo lsof -iTCP -sTCP:LISTEN
sudo lsof -nP -iTCP -sTCP:LISTEN
tail -f /var/log/dnscrypt-proxy/query.log
nettop -m route
sudo tcpdump -i en0 -n
Process Monitoring
Monitor running processes:
lsof -i
sudo fs_usage -w -f filesystem
sudo fs_usage -f pathname $(pgrep ProcessName)
launchctl list
ps aux | grep -v root
fswatch -0 ~/Documents | xargs -0 -n 1 echo "Changed:"
Little Snitch Alternative (Free)
Use built-in tools for network monitoring:
cat > ~/network-monitor.sh << 'EOF'
while true; do
echo "=== $(date) ==="
lsof -i -P -n | grep ESTABLISHED
sleep 5
done
EOF
chmod +x ~/network-monitor.sh
~/network-monitor.sh > ~/network-connections.log 2>&1 &
SSH Hardening
Configure SSH for security:
ssh-keygen -t ed25519 -C "your_email@example.com"
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
nano ~/.ssh/config
Example SSH config:
# Global defaults
Host *
AddKeysToAgent yes
UseKeychain yes
IdentityFile ~/.ssh/id_ed25519
ServerAliveInterval 60
ServerAliveCountMax 3
# Specific host
Host myserver
HostName server.example.com
User username
Port 22
IdentityFile ~/.ssh/id_ed25519
# Use ProxyJump for bastion
Host private-server
HostName 10.0.1.5
User username
ProxyJump bastion.example.com
Harden SSH daemon (if running SSH server):
sudo nano /etc/ssh/sshd_config
Recommended sshd_config:
# Disable root login
PermitRootLogin no
# Disable password authentication
PasswordAuthentication no
ChallengeResponseAuthentication no
UsePAM no
# Enable public key authentication
PubkeyAuthentication yes
# Disable empty passwords
PermitEmptyPasswords no
# Limit users
AllowUsers your_username
# Change port (optional)
Port 2222
# Protocol
Protocol 2
# Logging
SyslogFacility AUTH
LogLevel INFO
# Disconnect idle sessions
ClientAliveInterval 300
ClientAliveCountMax 2
# Disable X11 forwarding (if not needed)
X11Forwarding no
# Disable TCP forwarding (if not needed)
AllowTcpForwarding no
Restart SSH:
sudo launchctl unload /System/Library/LaunchDaemons/ssh.plist
sudo launchctl load -w /System/Library/LaunchDaemons/ssh.plist
Physical Security
Lock Screen Settings
defaults write com.apple.screensaver askForPassword -int 1
defaults write com.apple.screensaver askForPasswordDelay -int 0
defaults -currentHost write com.apple.screensaver idleTime -int 300
defaults write com.apple.dock wvous-bl-corner -int 6
defaults write com.apple.dock wvous-bl-modifier -int 0
killall Dock
sudo defaults write /Library/Preferences/com.apple.loginwindow LoginwindowText \
"If found, please contact: +1-555-0100"
sudo defaults delete /Library/Preferences/com.apple.loginwindow autoLoginUser
sudo defaults write /Library/Preferences/com.apple.loginwindow GuestEnabled -bool false
Hibernate Mode
pmset -g | grep hibernatemode
sudo pmset -a hibernatemode 3
sudo defaults write /Library/Preferences/com.apple.virtualMemory UseEncryptedSwap -bool yes
sudo pmset -a destroyfvkeyonstandby 1
sudo pmset -a powernap 0
Metadata and Artifacts
Remove metadata from files:
xattr -cr /path/to/file
mdls /path/to/file
sudo mdutil -E /
exiftool -all= file.jpg
brew install --cask imageoptim
Clear system artifacts:
qlmanage -r cache
sudo rm -rf /var/log/*.log
sudo rm -rf ~/Library/Logs/*
cat /dev/null > ~/.bash_history && history -c
cat /dev/null > ~/.zsh_history && history -c
rm -P sensitive-file.txt
brew install srm
srm -v sensitive-file.txt
diskutil secureErase freespace 0 /Volumes/Macintosh\ HD
Password Management
Use built-in password manager or dedicated solution:
security find-generic-password -s "Service Name" -a "Account Name"
security add-generic-password -a "account" -s "service" -w "password"
openssl rand -base64 32
brew install pwgen
pwgen -sy 32 1
brew install diceware
diceware -n 6 --no-caps
KeePassXC Setup
brew install --cask keepassxc
Backup Strategy
Time Machine
tmutil destinationinfo
tmutil startbackup
tmutil addexclusion ~/Downloads
tmutil addexclusion ~/Movies
diskutil info /Volumes/Time\ Machine | grep Encrypted
Manual Encrypted Backup
hdiutil create -size 100g -encryption AES-256 \
-volname "Backup" -fs APFS ~/backup.dmg
hdiutil attach ~/backup.dmg
rsync -av --delete ~/Documents/ /Volumes/Backup/Documents/
hdiutil detach /Volumes/Backup
Wi-Fi Security
sudo networksetup -removepreferredwirelessnetwork en0 "NetworkName"
networksetup -setairportpower en0 off
ifconfig en0 | grep ether