machine-security-check
Performs a read-only posture audit of a macOS machine across system protections, persistence points, and credential surfaces, then writes the result to the shared data directory.
When to invoke
Trigger on phrases like: "check machine security", "security audit", "is my mac secure", "scan my machine", "audit my mac".
What to check
Run each check as a read-only shell command. Never prompt for or request sudo. If a command needs elevation and is not available without it, record the check with severity info and a detail of "not available without elevation" rather than requesting privileges.
System protections (severity guidance in parens)
- SIP —
csrutil status. Expect "enabled". If disabled, severity critical.
- Gatekeeper —
spctl --status. Expect "assessments enabled". If disabled, warn.
- FileVault —
fdesetup status. Expect "On". If "Off", critical. If not determinable, info.
- Application Firewall —
defaults read /Library/Preferences/com.apple.alf globalstate 2>/dev/null. 0 = off (warn), 1 or 2 = on (ok).
- Automatic Software Updates —
defaults read /Library/Preferences/com.apple.SoftwareUpdate AutomaticCheckEnabled 2>/dev/null and related keys. Off is info.
- Screen-lock —
defaults read com.apple.screensaver askForPassword 2>/dev/null. Unset or 0 is warn.
Persistence and startup
- Login items —
osascript -e 'tell application "System Events" to get the name of every login item' 2>/dev/null. List names; if any look unfamiliar, mark individual findings info.
- User LaunchAgents —
ls -la ~/Library/LaunchAgents 2>/dev/null. Report count and any with very recent mtime (<7 days) as info. Any unsigned binary target = warn.
- System LaunchAgents / Daemons —
ls /Library/LaunchAgents /Library/LaunchDaemons 2>/dev/null. Report counts only (avoid flooding findings).
- Cron / at —
crontab -l 2>/dev/null and atq 2>/dev/null. Any entries = info with the content in raw.
Credential surfaces
- SSH keys — enumerate
~/.ssh/id_* (not .pub). For each, report type and whether it is encrypted (grep -q "ENCRYPTED" <key> or ssh-keygen -y -P "" -f <key> >/dev/null 2>&1). Unencrypted private keys = warn.
- authorized_keys —
~/.ssh/authorized_keys. Report line count. >0 entries = info with the comment fields (last field) listed.
- Keychain —
security list-keychains. Just report names as raw, no severity.
Recent filesystem activity
- Modifications in sensitive dirs in last 7 days —
find /Library/LaunchAgents /Library/LaunchDaemons ~/Library/LaunchAgents ~/.ssh -type f -mtime -7 2>/dev/null. Any result = info, list up to 20 paths.
- Shell rc suspicious patterns — grep
~/.zshrc ~/.bashrc ~/.bash_profile ~/.profile for curl | sh, wget | sh, eval \"\$(curl, or base64-decoded eval. Matches = warn.
Output contract
After collection, construct a single JSON envelope matching the shared schema:
{
"skill": "machine-security-check",
"timestamp": "<ISO8601 UTC>",
"severity": "<highest finding severity: ok|info|warn|critical>",
"summary": "<one-line human summary, e.g. 'All protections on. 2 informational items.'>",
"findings": [
{ "id": "sip", "severity": "ok", "title": "SIP enabled", "detail": "System Integrity Protection: enabled." }
],
"raw": { "<key>": "<trimmed raw output>" }
}
Write it to ~/.mac-guardian/data/machine-security-check-<ISOdate>.json. Use the helpers in ${CLAUDE_PLUGIN_ROOT}/scripts/_common.sh when scripting; or write directly using date +%Y-%m-%d for the filename.
Handoff
After writing JSON:
- If invoked directly by the user (not by
daily-health-report), also render and open a standalone mini HTML report:
bash ${CLAUDE_PLUGIN_ROOT}/scripts/render-single.sh machine-security-check
- If invoked by
daily-health-report, return the JSON path only.
Safety
- Read-only. Never modify files. Never toggle SIP, FileVault, or firewall.
- Do not request
sudo. If elevation would be required for a check, record it as informational.
- Never print private key contents — only report their existence and encryption state.
1---2name: machine-security-check3description: This skill should be used when the user asks to "check machine security", "run a security audit", "is my mac secure", "scan my machine", "audit my mac", or mentions SIP, Gatekeeper, FileVault, firewall, login items, launch agents, SSH keys, or authorized_keys. Performs a read-only macOS security posture audit and writes a structured JSON result to ~/.mac-guardian/data/.4---56# machine-security-check78Performs a read-only posture audit of a macOS machine across system protections, persistence points, and credential surfaces, then writes the result to the shared data directory.910## When to invoke1112Trigger on phrases like: "check machine security", "security audit", "is my mac secure", "scan my machine", "audit my mac".1314## What to check1516Run each check as a read-only shell command. Never prompt for or request `sudo`. If a command needs elevation and is not available without it, record the check with severity `info` and a `detail` of "not available without elevation" rather than requesting privileges.1718**System protections (severity guidance in parens)**19201. **SIP** — `csrutil status`. Expect "enabled". If disabled, severity `critical`.212. **Gatekeeper** — `spctl --status`. Expect "assessments enabled". If disabled, `warn`.223. **FileVault** — `fdesetup status`. Expect "On". If "Off", `critical`. If not determinable, `info`.234. **Application Firewall** — `defaults read /Library/Preferences/com.apple.alf globalstate 2>/dev/null`. 0 = off (`warn`), 1 or 2 = on (`ok`).245. **Automatic Software Updates** — `defaults read /Library/Preferences/com.apple.SoftwareUpdate AutomaticCheckEnabled 2>/dev/null` and related keys. Off is `info`.256. **Screen-lock** — `defaults read com.apple.screensaver askForPassword 2>/dev/null`. Unset or 0 is `warn`.2627**Persistence and startup**28297. **Login items** — `osascript -e 'tell application "System Events" to get the name of every login item' 2>/dev/null`. List names; if any look unfamiliar, mark individual findings `info`.308. **User LaunchAgents** — `ls -la ~/Library/LaunchAgents 2>/dev/null`. Report count and any with very recent mtime (<7 days) as `info`. Any unsigned binary target = `warn`.319. **System LaunchAgents / Daemons** — `ls /Library/LaunchAgents /Library/LaunchDaemons 2>/dev/null`. Report counts only (avoid flooding findings).3210. **Cron / at** — `crontab -l 2>/dev/null` and `atq 2>/dev/null`. Any entries = `info` with the content in raw.3334**Credential surfaces**353611. **SSH keys** — enumerate `~/.ssh/id_*` (not `.pub`). For each, report type and whether it is encrypted (`grep -q "ENCRYPTED" <key>` or `ssh-keygen -y -P "" -f <key> >/dev/null 2>&1`). Unencrypted private keys = `warn`.3712. **authorized_keys** — `~/.ssh/authorized_keys`. Report line count. >0 entries = `info` with the comment fields (last field) listed.3813. **Keychain** — `security list-keychains`. Just report names as raw, no severity.3940**Recent filesystem activity**414214. **Modifications in sensitive dirs in last 7 days** — `find /Library/LaunchAgents /Library/LaunchDaemons ~/Library/LaunchAgents ~/.ssh -type f -mtime -7 2>/dev/null`. Any result = `info`, list up to 20 paths.4315. **Shell rc suspicious patterns** — grep `~/.zshrc ~/.bashrc ~/.bash_profile ~/.profile` for `curl | sh`, `wget | sh`, `eval \"\$(curl`, or base64-decoded eval. Matches = `warn`.4445## Output contract4647After collection, construct a single JSON envelope matching the shared schema:4849```json50{51 "skill": "machine-security-check",52 "timestamp": "<ISO8601 UTC>",53 "severity": "<highest finding severity: ok|info|warn|critical>",54 "summary": "<one-line human summary, e.g. 'All protections on. 2 informational items.'>",55 "findings": [56 { "id": "sip", "severity": "ok", "title": "SIP enabled", "detail": "System Integrity Protection: enabled." }57 ],58 "raw": { "<key>": "<trimmed raw output>" }59}60```6162Write it to `~/.mac-guardian/data/machine-security-check-<ISOdate>.json`. Use the helpers in `${CLAUDE_PLUGIN_ROOT}/scripts/_common.sh` when scripting; or write directly using `date +%Y-%m-%d` for the filename.6364## Handoff6566After writing JSON:6768- If invoked directly by the user (not by `daily-health-report`), also render and open a standalone mini HTML report:69 `bash ${CLAUDE_PLUGIN_ROOT}/scripts/render-single.sh machine-security-check`70- If invoked by `daily-health-report`, return the JSON path only.7172## Safety7374- Read-only. Never modify files. Never toggle SIP, FileVault, or firewall.75- Do not request `sudo`. If elevation would be required for a check, record it as informational.76- Never print private key contents — only report their existence and encryption state.