Files
our-claude-skills/custom-skills/81-mac-optimizer/skills/mac-optimizer/scripts/audit_security.sh
Andrew Yim 877db1aa0f refactor: reorganize skill numbering, remove obsolete skills, rename shared libs
- Rename: 00→80 claude-settings-optimizer, 88→79 dintel-skill-update,
  92→81 mac-optimizer, 93→82 tui-design-template
- Rename: dintel-shared → _dintel-shared (consistent with _ourdigital-shared)
- Remove: 61-gtm-manager, 62-gtm-guardian (obsolete), 99_archive
- Update all dintel-* skill refs (114 occurrences across 31 files)
- Sync README.md, CLAUDE.md, AGENTS.md with new structure

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 19:32:44 +09:00

123 lines
5.5 KiB
Bash
Executable File

#!/usr/bin/env bash
# audit_security.sh — Security posture assessment for macOS (read-only)
# Output: JSON lines to stdout, one per finding
set -euo pipefail
json_escape() { printf '%s' "$1" | sed 's/\\/\\\\/g; s/"/\\"/g; s/\t/\\t/g' | tr '\n' ' '; }
json_finding() {
local severity="$1" finding action details
finding=$(json_escape "$2")
action=$(json_escape "$3")
details=$(json_escape "$4")
printf '{"module":"security","severity":"%s","finding":"%s","action":"%s","details":"%s"}\n' \
"$severity" "$finding" "$action" "$details"
}
# --- SIP (System Integrity Protection) ---
sip_status=$(csrutil status 2>/dev/null || echo "unknown")
if echo "$sip_status" | grep -q "enabled"; then
json_finding "info" "SIP enabled" "none" ""
elif echo "$sip_status" | grep -q "disabled"; then
json_finding "critical" "SIP is disabled" "report" "System Integrity Protection should be enabled"
else
json_finding "warning" "SIP status unknown" "report" "$sip_status"
fi
# --- Gatekeeper ---
gatekeeper_status=$(spctl --status 2>/dev/null || echo "unknown")
if echo "$gatekeeper_status" | grep -q "assessments enabled"; then
json_finding "info" "Gatekeeper enabled" "none" ""
elif echo "$gatekeeper_status" | grep -q "assessments disabled"; then
json_finding "critical" "Gatekeeper is disabled" "report" "Enable via: sudo spctl --master-enable"
else
json_finding "warning" "Gatekeeper status unknown" "report" "$gatekeeper_status"
fi
# --- Firewall ---
fw_tool="/usr/libexec/ApplicationFirewall/socketfilterfw"
if [ -x "$fw_tool" ]; then
fw_status=$("$fw_tool" --getglobalstate 2>/dev/null || echo "unknown")
if echo "$fw_status" | grep -qi "enabled"; then
json_finding "info" "Firewall enabled" "none" ""
else
json_finding "critical" "Firewall is disabled" "report" "Enable in System Settings > Network > Firewall"
fi
else
# Fallback to defaults
fw_default=$(defaults read /Library/Preferences/com.apple.alf globalstate 2>/dev/null || echo "unknown")
case "$fw_default" in
0) json_finding "critical" "Firewall is disabled" "report" "Enable in System Settings > Network > Firewall" ;;
1|2) json_finding "info" "Firewall enabled" "none" "" ;;
*) json_finding "warning" "Firewall status unknown" "report" "" ;;
esac
fi
# --- FileVault ---
fv_status=$(fdesetup status 2>/dev/null || echo "unknown")
if echo "$fv_status" | grep -q "FileVault is On"; then
json_finding "info" "FileVault enabled (disk encryption)" "none" ""
elif echo "$fv_status" | grep -q "FileVault is Off"; then
json_finding "critical" "FileVault is off (disk not encrypted)" "report" "Enable in System Settings > Privacy and Security > FileVault"
else
json_finding "warning" "FileVault status unknown" "report" "$fv_status"
fi
# --- Open listening ports ---
listening_ports=$(lsof -iTCP -sTCP:LISTEN -nP 2>/dev/null | tail -n +2 || echo "")
port_count=$(echo "$listening_ports" | grep -c . 2>/dev/null || echo 0)
if [ "$port_count" -gt 0 ]; then
# Extract unique port/process combos
port_summary=$(echo "$listening_ports" | awk '{print $1":"$9}' | sort -u | head -10 | tr '\n' ', ' | sed 's/,$//')
json_finding "info" "${port_count} listening TCP connections" "review" "$port_summary"
fi
# --- SSH config ---
ssh_config="/etc/ssh/sshd_config"
if [ -f "$ssh_config" ]; then
# Check password auth
if grep -qi "^PasswordAuthentication yes" "$ssh_config" 2>/dev/null; then
json_finding "warning" "SSH password authentication enabled" "report" "Consider key-based auth only"
fi
# Check root login
if grep -qi "^PermitRootLogin yes" "$ssh_config" 2>/dev/null; then
json_finding "warning" "SSH root login permitted" "report" "Consider disabling root SSH login"
fi
fi
# --- Remote login ---
remote_login=$(systemsetup -getremotelogin 2>/dev/null || echo "unknown")
if echo "$remote_login" | grep -qi "on"; then
json_finding "info" "Remote Login (SSH) is enabled" "review" "Disable if not needed: System Settings > General > Sharing"
fi
# --- Remote management ---
remote_mgmt=$(defaults read /Library/Preferences/com.apple.RemoteManagement ARD_AllLocalUsers 2>/dev/null || echo "not configured")
if [ "$remote_mgmt" = "1" ]; then
json_finding "warning" "Remote Management enabled for all users" "review" "Check System Settings > General > Sharing"
fi
# --- Software updates ---
# Just check if updates are available (this can be slow, so we time-limit it)
# macOS lacks GNU timeout — use perl alarm as a portable alternative
update_check=$(perl -e 'alarm 30; exec @ARGV' -- softwareupdate -l 2>&1 || echo "timeout or error")
if echo "$update_check" | grep -q "No new software available"; then
json_finding "info" "macOS software is up to date" "none" ""
elif echo "$update_check" | grep -q "timeout or error"; then
json_finding "info" "Software update check timed out" "none" "Run softwareupdate -l manually"
else
update_count=$(echo "$update_check" | grep -c "^\*" 2>/dev/null || echo 0)
json_finding "warning" "${update_count} software update(s) available" "softwareupdate" "Run: softwareupdate -l for details"
fi
# --- Screen lock ---
screen_lock_delay=$(defaults -currentHost read com.apple.screensaver idleTime 2>/dev/null || echo "not set")
ask_password=$(defaults read com.apple.screensaver askForPassword 2>/dev/null || echo "unknown")
if [ "$ask_password" = "0" ]; then
json_finding "warning" "Screen lock password not required" "report" "Enable in System Settings > Lock Screen"
elif [ "$screen_lock_delay" != "not set" ] && [ "$screen_lock_delay" -gt 300 ] 2>/dev/null; then
json_finding "info" "Screen lock delay: ${screen_lock_delay}s (consider reducing)" "report" ""
fi