← All notes

Personal Mac Security: Run a Practical Local Check

Run a local security check on your personal Mac with NIST mSCP, keep reports in a temporary directory, and use the workflow manually or with an AI agent.

  • macos
  • security
  • mscp
  • cis
  • ai

TL;DR — If you want to check the security configuration of a Mac you administer yourself, use the personal profile in macos-mscp-scan. It builds a read-only audit from the NIST macOS Security Compliance Project (mSCP), never applies fixes or uploads the report, and can be run manually or prepared by an AI agent. Reports stay under your macOS temporary directory. The default command is zsh ./scan_cis.zsh; it prepares the scan, then stops and gives you one separate command to authorize in your normal Terminal.

I wanted to answer a practical question: how can I check whether my own Mac is configured securely?

macOS exposes individual controls such as FileVault, Gatekeeper, the firewall, screen locking and sharing services, but it does not provide one useful report that checks them together and explains failed settings. A malware scan does not answer this question either. I needed a security-configuration audit: a repeatable way to inspect protective settings without changing them.

That search led me to the macOS Security Compliance Project (mSCP). mSCP provides machine-readable security rules, baselines, generated guidance and audit scripts for macOS. It also supports tailoring a baseline and customizing individual rules.

The existing baselines are valuable, but a raw CIS result can assume that an organization manages the Mac through MDM. I therefore created a personal profile for a self-administered Mac. First, here is how to use it. The design and implementation decisions come after the practical workflow.

What this personal Mac security audit checks

The personal profile asks whether selected protections are effective on the Mac at scan time. It covers areas such as:

  • FileVault disk encryption and Gatekeeper;
  • macOS and App Store update settings;
  • the Application Firewall and stealth mode;
  • automatic login, the guest account and short sudo credential reuse;
  • screen locking and display-sleep timing;
  • Internet Sharing, Bluetooth Sharing, Remote Apple Events and SMB; and
  • privacy-relevant settings such as password hints and diagnostic submission.

It is a configuration audit, not a complete verdict that a Mac is “secure.” It does not scan for malware, inventory vulnerable applications, test external network reachability, enumerate every open port or verify that backups can be restored.

Use the default personal profile for a Mac you administer yourself and that is not controlled through organizational MDM. Use the unchanged cis_lvl1 or cis_lvl2 baseline when you specifically need a CIS compliance view or need to verify centrally enforced policy.

No tracking and no report upload

The macos-mscp-scan wrapper contains no analytics, telemetry or tracking code. It does not send the audit result to a server. The generated report, dependency cache and per-run files remain on the Mac under:

${TMPDIR%/}/macos-mscp-scan/

That location is private to the current user but intentionally temporary. macOS may purge it after a restart, during maintenance or under storage pressure. Copy a report to a permanent private directory only when you need to retain it.

Preparation still makes normal HTTPS requests to GitHub, PyPI and RubyGems to download pinned source and dependencies. Those services can observe ordinary download requests, but the wrapper does not send them the security findings.

A local AI agent can read the local report after you complete the audit. An external chat cannot do that unless you upload or paste the data yourself. Do not send an unredacted report to an external AI service: it can contain user names, host names, paths, installed software and security configuration.

The safe workflow in one minute

The scanner deliberately separates preparation from the privileged audit:

  1. Preparation downloads pinned dependencies, generates the selected audit and hashes its inputs. It runs without sudo and does not inspect security settings.
  2. The script prints PREPARATION COMPLETE — USER ACTION REQUIRED and one exact --run-prepared command.
  3. You run that command in a normal interactive Terminal, review the confirmation and allow macOS to request the administrator password.
  4. The generated mSCP script runs only in documented --check mode. The wrapper never invokes --fix or --cfc.
  5. You read the text, structured plist and generated HTML/PDF report before deciding whether to change anything.

This same boundary works for both manual and AI-assisted use. An agent may prepare the audit and later interpret its output, but only the user starts the privileged phase and enters the password.

Download and verify macos-mscp-scan

The following commands are for macOS and run as the current user; they do not use sudo. They download four assets for the signed v0.4.0 release, verify the checksum manifest and its detached SSH signature, and extract the source under /private/tmp. They require HTTPS access and write only to the newly created temporary directory.

Before trusting a signing key for the first time, compare its fingerprint with the release notes.

(
  set -e
  release_dir="$(mktemp -d /private/tmp/macos-mscp-scan-v0.4.0.XXXXXX)"
  cd "$release_dir"

  curl -fLO https://github.com/r4kh1m/macos-mscp-scan/releases/download/v0.4.0/macos-mscp-scan-v0.4.0.tar.gz
  curl -fLO https://github.com/r4kh1m/macos-mscp-scan/releases/download/v0.4.0/SHA256SUMS
  curl -fLO https://github.com/r4kh1m/macos-mscp-scan/releases/download/v0.4.0/SHA256SUMS.sig
  curl -fLO https://github.com/r4kh1m/macos-mscp-scan/releases/download/v0.4.0/r4kh1m-release-signing-key.pub

  shasum -a 256 -c SHA256SUMS
  {
    printf 'r4kh1m-release namespaces="file" '
    cat r4kh1m-release-signing-key.pub
  } > allowed_signers
  ssh-keygen -Y verify \
    -f allowed_signers \
    -I r4kh1m-release \
    -n file \
    -s SHA256SUMS.sig < SHA256SUMS

  tar -xzf macos-mscp-scan-v0.4.0.tar.gz
  printf '\nScanner directory: %s/macos-mscp-scan-v0.4.0\n' "$release_dir"
)

Keep the printed scanner path for the next step. The directory is disposable: after the audit, remove that exact path in Finder or with rm -rf only after checking it carefully. Removing it deletes the downloaded scanner copy, not the separate report and dependency directory under $TMPDIR.

The current release supports macOS 14 Sonoma, 15 Sequoia and 26 Tahoe on Apple Silicon and Intel. A complete run needs an administrator account, the bundled macOS command-line tools plus git, system ruby and gem, HTTPS access to GitHub, PyPI and RubyGems, and about 1 GB free on the volume backing $TMPDIR. Python and Ruby dependencies are isolated in scanner-owned temporary directories rather than installed into system or user package locations.

Option 1: run the audit with an AI agent

Give the extracted repository to an agent with local terminal access and use a request like this:

Follow AGENTS.md in this repository. Prepare the default personal security
audit, but stop before any command that needs sudo. Show me the exact
--run-prepared command and wait. After I run it in my normal Terminal, locate
the completed report and help me triage the findings without changing settings.

A correct agent workflow is:

  1. The agent reads the repository instructions and runs zsh ./scan_cis.zsh --baseline personal --prepare-only.
  2. The agent returns the exact printed command and stops.
  3. You run it yourself, approve the prompt and enter the password only into macOS Terminal.
  4. You tell the agent that the audit is complete.
  5. The agent follows the stable latest-personal.txt pointer, reads the report and explains each real finding in context.

Do not paste a password into chat or an AI-controlled terminal. Separating the workflow ensures that administrator authorization remains an explicit user action rather than something delegated to the agent.

Option 2: run the security audit manually

Open the extracted directory in Terminal and prepare the default profile:

cd /private/tmp/macos-mscp-scan-v0.4.0.EXAMPLE/macos-mscp-scan-v0.4.0
zsh ./scan_cis.zsh

Replace the example path with the one printed during extraction. The default command prepares personal and is equivalent to:

zsh ./scan_cis.zsh --baseline personal --prepare-only

Preparation does not request administrator access or inspect security settings. When it finishes, copy the exact command printed below USER ACTION REQUIRED and run it in the same normal Terminal.

The wrapper verifies that the prepared run, generated audit and pinned inputs have not changed. It explains the action and asks for confirmation before macOS requests the administrator password. The scan then runs in read-only check mode.

Do not invent a run-directory path or bypass a stale-preparation error. Prepare a new run instead.

Find and read the macOS security report

Everything owned by the wrapper is placed under the current user’s standard macOS temporary directory:

${TMPDIR%/}/macos-mscp-scan/
├── cache/                         # reusable, disposable dependencies
├── runs/personal.XXXXXX/report/  # one isolated audit and its evidence
├── latest-prepared-personal.txt  # run awaiting user action
└── latest-personal.txt           # latest completed run

Start with report/personal_check.txt. Use scan-output.audit.plist for structured results, the generated HTML or PDF for rule rationale and remediation guidance, and provenance.txt to see the exact macOS, wrapper, mSCP and dependency inputs.

Confirm that audit-completed.txt exists and records a zero process exit status before relying on pass/fail totals.

$TMPDIR is intentionally disposable. macOS can purge it after a restart, during maintenance or under storage pressure. Copy a report you need to retain to a permanent private location. Reports can expose user names, host names, paths, installed software and security configuration, so do not upload an unredacted report to an issue or an external AI service.

To remove only the reusable dependency cache while preserving report runs:

zsh ./scan_cis.zsh --clear-cache

That command deletes the scanner-owned cache beneath $TMPDIR; it does not change macOS security settings or remove completed report directories.

Interpret findings and decide what to fix first

The structured plist maps rule identifiers to a finding boolean:

  • finding = true means the check observed a non-compliant condition;
  • finding = false means it did not observe one.

Begin with the text report because it distinguishes an explicit pass from N/A, an execution error or a manual-review result. The plist itself is a flat result set: rule order and number do not encode severity, exploitability or urgency.

A practical triage order is:

  1. disk encryption, core OS protections and security updates;
  2. firewall state, exposed sharing services and remote access;
  3. privileged accounts, automatic login and authentication controls;
  4. screen locking and physical-access exposure; and
  5. lower-impact hardening after considering usability and compensating controls.

This is a human risk heuristic, not an mSCP or CIS severity score. For each finding, open the generated guidance, read the rationale, remediation and impact, decide whether the setting is intentional, change one thing at a time and rescan. The scanner intentionally does not automate remediation.

In one end-to-end validation on macOS 26 running on Apple Silicon, 48 applicable personal checks passed, there were zero findings, and Power Nap was reported as one architecture-appropriate N/A. That is a test result for one machine, not an expected score for every Mac.

Why the standard CIS baseline was not enough

At this point you can run and interpret the audit without understanding its implementation. The remaining sections explain why the profile exists and what was changed.

CIS Level 1 is a useful starting point, but some of its checks ask whether an organization delivered and enforced a configuration profile. That is not always the same as asking whether the protection is active now.

FileVault is the clearest example. A personal Mac may report FileVault is On while a raw rule still produces a finding because no MDM restriction prevents the owner from disabling it later. That result is valid for central enforcement, but it does not answer the personal owner’s immediate question.

Question Raw CIS baseline personal profile
Is FileVault on? May also require an MDM restriction Checks effective encryption state
Can a user later change the setting? Often verifies central enforcement Outside the default question
Are organizational audit records retained? Included where the benchmark requires them Optional forensic scope, excluded by default
Is this a formal CIS assessment? Yes, when run unchanged and interpreted correctly No
Does a removed rule count as passed? Not applicable No; it is explicitly out of scope

The personal profile starts from the mSCP CIS Level 1 rule selection, replaces selected profile-based checks with checks of effective local state, and removes rules that do not answer its stated question:

Which selected security protections are effective on this Mac now?

The original cis_lvl1 and cis_lvl2 baselines remain available unchanged. The personal profile is derived from CIS Level 1, but it is deliberately not a CIS compliance assessment.

How the personal profile was implemented

The central implementation choice is to measure effective local state whenever macOS exposes a stable interface. Examples include:

  • FileVault through fdesetup status, without requiring the MDM-only dontAllowFDEDisable restriction;
  • Gatekeeper through spctl --status;
  • the Application Firewall and stealth mode through socketfilterfw, with both normal enabled mode and Block all incoming connections accepted;
  • screen locking and display-sleep timing for the active user;
  • automatic App Store updates, Terminal Secure Keyboard Entry, password hints and Bluetooth Sharing in the active user’s context;
  • automatic login, the guest account, Internet Sharing and automatic network time; and
  • whether Remote Apple Events or SMB actually has a listener on its expected TCP ports.

The sudo credential cache illustrates a usability decision. Requiring zero reuse caused a password prompt for every privileged step. The personal profile accepts an effective timeout from zero through two minutes: short enough to limit unattended reuse, but usable for a brief administrative workflow.

At preparation time the wrapper generates the pinned upstream CIS Level 1 baseline, removes explicitly out-of-scope rules, adds the bundled local-state overrides and generates a new personal audit. Raw cis_lvl1 and cis_lvl2 runs use fresh mSCP trees without these changes.

The exact machine-readable inventory lives in profiles/personal/profile.yaml, and the replacement checks are published beside it. Every generated personal report also contains the profile definition, custom rules and their SHA-256 hashes, so the meaning of a result does not depend on a moving web page.

Which rules are outside the personal profile

Tailoring is useful only when exclusions are visible. The personal profile removes several categories by default:

  • MDM-only enforcement. MDM enrollment, organization-delivered Safari restrictions, software-update deferrals and similar policy-delivery checks do not prove the current local state on a personal Mac.
  • Forensic and compliance logging. Traditional BSM auditd, explicit sudo logging and log-retention requirements help investigations and formal audit programs, but they are not preventive boundaries. They may belong in a future opt-in forensic profile.
  • Global password policy. Rotation and password-history rules do not measure the strength of the current local password and are poor universal advice for a single-user personal device.
  • Organization-specific controls. A fixed corporate time server, a login banner and restrictions on System Settings panes make sense in managed fleets, not as universal personal defaults.
  • Privacy and interface choices. Analytics contribution, location-menu visibility and requiring separate user-name entry at login are choices with context-dependent value. Hiding the account list adds little protection on a typical single-user Mac while making every login less convenient.
  • Cross-user administration. Preventing one administrator from unlocking another user’s active session addresses a multi-user threat model, so it is outside the default single-user profile.

Excluded means not assessed, never “secure” or “passed.” Run the unchanged CIS profile when central enforcement, formal compliance, forensic logging or a managed multi-user environment is the actual subject of the audit.

What “read-only” means in practice

The wrapper never applies a remediation. The audit still has to execute and read system configuration, so read-only does not mean that the operating system records no activity.

mSCP temporarily creates a result plist under /Library/Preferences and a log under /Library/Logs. The wrapper copies the result into the private report, then restores pre-existing files or removes files created by the run. Normal macOS records of sudo authentication and process execution remain.

This is also why the AI workflow stops before the privileged phase. The agent can work with reproducible files and reports, while the user retains control of the administrator prompt.

Personal Mac security audit FAQ

Is the personal profile CIS compliant?

No. It changes the scope and some checks. Use --baseline cis_lvl1 or --baseline cis_lvl2 for the unchanged upstream compliance view. The separate CIS audit guide explains that workflow.

Do I need MDM to use it?

No. The profile was created for a personally administered Mac that is not enrolled in organizational MDM. On a managed work Mac, follow the organization’s policy and use its approved assessment process.

Does it scan every open network port?

No. It checks expected listener ports for specific baseline controls such as Remote Apple Events and SMB. It is not a general port scanner, does not test reachability from another device and does not inventory vulnerable software.

Does the read-only scan change security settings?

No. The wrapper invokes mSCP only with --check; it does not apply fixes. Temporary mSCP result files under /Library are restored or removed after the run, while normal system records of the execution remain.

When should I run it again?

Rescan after a major macOS update, a meaningful configuration change or an unexpected security event. The profile measures current state, not whether the owner is permanently prevented from changing it later.

Start with the question, then choose the baseline

For someone who simply wants to review the security configuration of a personal Mac, mSCP provides a strong rule and documentation framework, and the personal profile adapts that framework to a self-administered machine. The scan can be run entirely by hand or split safely between an AI agent and the user.

Use personal to review effective protective state. Use raw CIS when formal benchmark alignment or central enforcement matters. Add an opt-in forensic profile when investigation-ready logging is worth its cost. Keeping those purposes separate produces fewer misleading findings and a more honest security conversation.

The source, exact profile decisions and workflow documentation are available in macos-mscp-scan. Use Discussions for usage questions and sanitized compatibility feedback, and Issues for reproducible bugs. Never attach an unredacted audit report.