Skip to content

mSCP and CIS Benchmarks: macOS Compliance Baselines

How to use the NIST macOS Security Compliance Project and CIS Apple macOS Benchmarks to build, tailor, deploy and continuously verify a Mac baseline.

Published on 8 min read

Most Mac fleets eventually have to answer the same question from an auditor, a customer questionnaire or a cyber insurer: "Which baseline do you follow, and how do you prove it?" On macOS the two reference points you will meet most often are the NIST macOS Security Compliance Project (mSCP) and the CIS Apple macOS Benchmarks. This guide explains what each one is, how they relate, and how to turn them into configuration you can deploy and verify continuously through MDM.

Neither project replaces engineering judgement. A baseline is a structured starting point: it tells you what to configure and how to check it, but you still decide which rules fit your users and document the ones you deliberately skip.

What mSCP is

The macOS Security Compliance Project is an open-source effort hosted on GitHub under the usnistgov/macos_security repository. It is maintained collaboratively by people from NIST, several US federal agencies and the wider Mac admin community. Its core idea is simple: every security setting is a rule written once in YAML, and baselines are just lists of rules. From that single source, the project's scripts generate human-readable guidance, configuration profiles, a compliance script and framework mappings.

The repository uses one branch per major macOS release (for example a Sequoia branch and a Tahoe branch). Always work from the branch that matches the OS you are hardening, because rule checks, fixes and profile keys change between releases.

Anatomy of a rule

Each rule file describes one control. The fields you will care about most are:

FieldPurpose
idStable rule name, such as os_sip_enable or system_settings_firewall_enable
title / discussionWhat the control does and why it matters
checkShell command that tests the current state
resultExpected output of the check for a compliant Mac
fixRemediation, either a script snippet or a pointer to a profile
referencesMappings to NIST 800-53, CIS Benchmark, CIS Controls v8, DISA STIG and others
tagsWhich baselines include the rule
mobileconfig / mobileconfig_infoWhether a profile enforces it and which payload keys it uses

Rule IDs follow a readable prefix convention: os_ for operating system settings, system_settings_ for things users see in System Settings, auth_, audit_, icloud_, pwpolicy_ and so on. Examples you will see in almost every baseline include os_sip_enable, os_gatekeeper_enable and system_settings_filevault_enforce.

Baselines shipped with the project

Baselines live in the baselines/ directory as YAML files. Depending on the branch you will find entries such as:

BaselineIntended use
cis_lvl1Aligned with CIS Apple macOS Benchmark Level 1
cis_lvl2Aligned with CIS Apple macOS Benchmark Level 2
cisv8Mapped to CIS Critical Security Controls v8
800-53r5_low / _moderate / _highNIST SP 800-53 Rev. 5 impact levels
800-171Protecting CUI in non-federal systems
stigAligned with the DISA macOS STIG
cmmc_lvl1 / cmmc_lvl2CMMC maturity levels

The exact file names differ slightly between branches, so list the directory rather than assuming.

Generating guidance with mSCP

The workflow runs on a Mac with Python 3 and the project's Python requirements installed. Clone the repository, check out the branch for your macOS version, and install dependencies:

git clone https://github.com/usnistgov/macos_security.git
cd macos_security
git checkout sequoia   # or the branch matching your target release
pip3 install -r requirements.txt

The main entry point is scripts/generate_guidance.py. Given a baseline file, it produces documentation and, with the right flags, configuration profiles and a compliance script:

./scripts/generate_guidance.py -p -s baselines/cis_lvl1.yaml

Here -p generates configuration profiles and -s generates the compliance script. Run the script with -h on your branch to see every option, since newer releases add outputs such as Declarative Device Management artifacts and spreadsheets.

Output lands in build/<baseline>/. Typically you get:

  • An AsciiDoc source plus rendered HTML (and PDF if the renderer is installed) documenting every rule.
  • A mobileconfigs/ folder with one unsigned profile per payload domain, plus plain preference plists.
  • <baseline>_compliance.sh, a script that can audit and optionally remediate.

Creating a custom baseline

You rarely deploy a stock baseline unchanged. scripts/generate_baseline.py builds a new baseline from rule tags, and has a tailoring mode that walks you through including or excluding each rule:

./scripts/generate_baseline.py -l          # list available tags
./scripts/generate_baseline.py -k cis_lvl1 -t

Organization-defined values (ODVs), such as the screen-saver timeout or minimum password length, can be overridden without editing the upstream rule by placing a matching rule file under custom/rules/. Keeping your changes in custom/ makes rebasing onto the next release branch far less painful.

The CIS Apple macOS Benchmarks

The Center for Internet Security publishes a separate benchmark document for each supported macOS release. It is free to download for non-commercial use after registering, and it is the document most customers and auditors mean when they ask for "CIS hardening".

Two classifications appear on every recommendation:

ClassificationMeaning
Level 1Practical, prudent settings with limited impact on usability
Level 2Defense-in-depth settings for high-security environments; may reduce functionality
AutomatedState can be checked programmatically
ManualRequires human review, often because the right answer depends on context

Manual recommendations matter. They often cover items like reviewing sharing services or approving specific apps, which no script can decide for you. Track them in your compliance evidence even when tooling reports them as "not assessed".

mSCP and CIS work closely together, and the mSCP cis_lvl1 and cis_lvl2 baselines map rules back to CIS recommendation numbers in the references field. Treat the published CIS document as the authority on wording and scope, and mSCP as a convenient implementation.

Tailoring and exemptions

No real fleet passes every rule. Developers need some freedoms, kiosk Macs need others locked tighter, and some Level 2 rules conflict with business tools. The goal is not 100 percent; it is every deviation explained.

A workable approach:

  1. Start from cis_lvl1 (or the NIST baseline your contract requires).
  2. Remove rules that genuinely conflict with business needs and write the justification down.
  3. Adjust ODVs to match your written policy, not the other way around.
  4. For rules that apply to most Macs but not all, keep them in the baseline and exempt specific devices.

The generated compliance script supports exemptions through a managed preference domain named after the baseline, for example org.cis_lvl1.audit. Each rule ID can be marked exempt with a reason, and the script reports it as exempt rather than failed. Deliver that plist through MDM to the relevant device group:

<key>os_airdrop_disable</key>
<dict>
    <key>exempt</key>
    <true/>
    <key>exempt_reason</key>
    <string>Design team approved exception, ticket SEC-1234</string>
</dict>

The rule shown is illustrative; use the exact rule IDs from your generated baseline.

Continuous compliance with MDM and the script

Configuration drifts. Users change settings that are not locked by a profile, updates reset defaults, and new Macs arrive half-enrolled. A sustainable model has three layers:

  1. Enforce with configuration profiles delivered through MDM. See the MDM and configuration profiles guide for signing and deployment.
  2. Audit on a schedule by running the compliance script through your MDM's scripting feature or a LaunchDaemon.
  3. Report by collecting the script's results into your MDM inventory or a SIEM.

The compliance script writes its last results to a plist under /Library/Preferences/ named after the baseline, and a log under /Library/Logs/. Many MDM products can read a value from that plist as a custom inventory attribute, giving you a fleet-wide pass/fail count per rule.

Be cautious with automatic remediation. The --fix path changes system settings; run it only after testing on pilot devices, and prefer profiles for anything that can be enforced declaratively.

Verify it

Run the compliance script interactively on a test Mac first:

sudo zsh build/cis_lvl1/cis_lvl1_compliance.sh --check
sudo zsh build/cis_lvl1/cis_lvl1_compliance.sh --stats

Spot-check high-value controls directly so you are not relying on a single tool:

csrutil status
fdesetup status
spctl --status
/usr/libexec/ApplicationFirewall/socketfilterfw --getglobalstate
profiles status -type enrollment

Expected output on a hardened Mac looks similar to:

System Integrity Protection status: enabled.
FileVault is On.
assessments enabled
Firewall is enabled. (State = 1)

The underlying controls are covered in depth in the System Integrity Protection guide, the FileVault guide, the Gatekeeper guide and the firewall guide.

Common pitfalls

  • Wrong branch. Generating Sequoia guidance for Tahoe Macs produces checks that fail or keys that no longer apply.
  • Duplicate payloads. Pushing an mSCP profile alongside an existing MDM profile for the same domain can create conflicts with undefined winners. Consolidate first.
  • Unsigned profiles in production. Sign generated profiles or rebuild them in your MDM's native format.
  • Treating the score as the goal. A high pass rate with undocumented exemptions is weaker evidence than a lower rate with written justifications.
  • Ignoring manual items. Keep a record of how manual CIS recommendations were reviewed.
  • Blind remediation. Some fixes restart services or change user-visible behaviour; test before running --fix fleet-wide.

Checklist

  • Chose the baseline your obligations require and recorded why
  • Cloned mSCP on the branch that matches your macOS version
  • Tailored rules and ODVs in custom/, with justifications
  • Reviewed, signed and piloted generated profiles
  • Deployed the compliance script on a schedule with results collected centrally
  • Documented exemptions through the audit preference domain
  • Scheduled a review for each new macOS release