Check your Mac fleet against the NIS2 technical measures
Last updated: 2026-08-10
What this covers, and where it stops
Covers the Annex points of Commission Implementing Regulation (EU) 2024/2690 — which implements Article 21(2) of NIS2 — that a Mac's posture can evidence. That Regulation legally binds only eleven digital-infrastructure and digital-provider types; for every other NIS2 entity it is a benchmark, not an obligation. Article 21 also requires supply-chain security, incident handling, business continuity, HR security and governance, which no device signal can evidence.
Primary legal text: Commission Implementing Regulation (EU) 2024/2690.
Prepared using: NIST macOS Security Compliance Project (mSCP 2.0); Apple Platform Deployment; and Apple Device Management documentation. The mapping and interpretation are Nyvel's; these sources do not endorse this guide.
In plain terms: this guide gets you the device layer, by hand, on your own Macs. It will not get you an incident-response plan, a supplier register or a business-continuity policy, and any tool claiming to produce all of that from endpoint readings is overselling.
There is nothing to sign up for and nothing to install to follow this. Every check below is a command Apple ships with macOS. Commands that need an administrator password are shown with sudo. We ask you for nothing.
Rather see it working than read 29 commands? The live demo runs on a simulated fleet — no account, no MDM connection, and this framework is in the switcher.
How to run these
- Run them in Terminal on one representative Mac first, to learn what your fleet looks like. Several need
sudo. - These read state; none of them change anything. Each reports what is configured, not what a profile says should be — where a configuration profile and reality disagree, reality is the answer an auditor wants.
- A few settings exist per user and cannot be read on a Mac sitting at the login window. Those are marked. A machine with nobody signed in is not evidence in either direction.
- To do this across a fleet, run them through your MDM's script/command feature rather than by hand on each Mac.
- Each primary command below is the same read Nyvel performs, checked against posture script v18 on every build — so this page cannot drift into teaching a check the product has stopped doing. A separately labelled live verification may complement that read where a local network observation can prove exposure but cannot prove the absence of it.
The 11 Annex points mapped by default
Each heading is a cited Annex point. Under it are Nyvel's device-level evidence checks — not technologies prescribed by NIS2 or the implementing regulation. All mapped checks have to pass for this device-level projection to pass. A failed check does not by itself establish that the organization is non-compliant.
CIR-3.2.6 Monitoring and logging — time sources synchronised so logs can be correlated
Automatic time synchronization enabled
sudo systemsetup -getusingnetworktimePass: Network Time: On. Without it, timestamps across machines cannot be correlated.
This proves automatic synchronization is enabled, not that the Mac uses an organization-approved server. Nyvel does not currently evaluate the configured server address and therefore does not claim CIS 2.3.2.1 from this signal alone.
CIR-6.3.1 Configuration management — secure configurations established and monitored
System Integrity Protection enabled
csrutil statusPass: System Integrity Protection status: enabled.
Enrolled in MDM · Device supervised by MDM
profiles status -type enrollment- MDM enrollment: Yes. The output may add (User Approved).
- On macOS 11 or later, MDM enrollment: Yes (User Approved) means the Mac is managed and supervised. Enrolled via DEP: Yes only tells you that Automated Device Enrollment was used; it is not required for supervision.
For a direct visual check, open System Settings → General → Device Management and look for “This Mac is supervised and managed by …”.
Example output
Managed through Automated Device Enrollment
Enrolled via DEP: Yes
MDM enrollment: Yes (User Approved)
MDM server: https://mdm.example.com/mdmNot managed
Enrolled via DEP: No
MDM enrollment: NoSources: Apple Platform Deployment: Enrollment methods; Apple Platform Deployment: About Apple device supervision
CIR-6.6.1(a) Security patch management — patches applied within a reasonable time
Apple-provided software up to date
sudo softwareupdate --list --no-scanPass: No new software available, with a recent successful scan.
Do not cross-check this against RecommendedUpdates in com.apple.SoftwareUpdate. That key caches every recommendation macOS ever made, including optional developer downloads that are not patches and linger after installation.
Automatic macOS updates enabled
defaults read /Library/Preferences/com.apple.SoftwareUpdate AutomaticallyInstallMacOSUpdatesPass: 1.
Automatic security responses enabled
defaults read /Library/Preferences/com.apple.SoftwareUpdate CriticalUpdateInstallPass: 1. This covers Rapid Security Responses.
CIR-6.7.2(f) Network security — unneeded connections and services deactivated
Host firewall enabled
/usr/libexec/ApplicationFirewall/socketfilterfw --getglobalstatePass: Firewall is enabled.
This is a baseline check, not a complete inbound-access policy. Decide which apps and services need incoming connections, disable unnecessary sharing services, and review the firewall allow-list. Block all incoming connections, automatic allowances and stealth mode are risk decisions — NIS2 does not prescribe one setting for every Mac.
Remote Login (SSH) disabled
sudo systemsetup -getremoteloginPass: Remote Login: Off.
Screen Sharing disabled
launchctl print-disabled system | grep screensharing
launchctl print system/com.apple.screensharing >/dev/null 2>&1 && echo "Screen Sharing is running"Pass: The first command prints nothing or com.apple.screensharing => disabled, and the second command prints nothing.
Fail: The first command prints com.apple.screensharing => enabled, or the second prints Screen Sharing is running.
On an untouched Mac with Screen Sharing off, neither command normally prints anything. Nyvel also checks whether the live service is running, because that overrides the list.
File Sharing disabled
launchctl print-disabled system | grep smbd
launchctl print system/com.apple.smbd >/dev/null 2>&1 && echo "File Sharing is running"Pass: The first command prints nothing or com.apple.smbd => disabled, and the second command prints nothing.
Fail: The first command prints com.apple.smbd => enabled, or the second prints File Sharing is running.
No entry is normal when File Sharing is off. Mounting an SMB share from another Mac does not start this Mac’s File Sharing server, so the live-service check does not confuse outbound SMB use with an inbound server.
Remote Management (ARD) disabled
defaults read /Library/Preferences/com.apple.RemoteManagement ARD_AllLocalUsers; pgrep -x ARDAgentPass: The key does not exist and no ARDAgent is running.
Remote Management (ARD) and Screen Sharing are different services with different keys. A Mac with Screen Sharing on does not have ARD configured, and checking one tells you nothing about the other.
Guest access to shared folders disabled
sysadminctl -smbGuestAccess statusPass: guest access disabled.
CIR-6.9.2 Protection against malicious and unauthorised software
Malware protection (Gatekeeper) enabled
spctl --statusPass: assessments enabled.
Automatic XProtect/Gatekeeper data updates enabled
defaults read /Library/Preferences/com.apple.SoftwareUpdate ConfigDataInstallPass: 1. This is the XProtect and Gatekeeper data channel, separate from OS updates.
CIR-9.2(a) Cryptography — data at rest protected on endpoints
Disk encryption (FileVault) enabled
fdesetup statusPass: FileVault is On.
Says nothing about whether the recovery key is escrowed, which is a separate question your MDM answers.
CIR-11.3.2(c) Privileged accounts — administration privileges individualised and restricted
Root account disabled
dscl . -read /Users/root AuthenticationAuthorityPass: No such key — meaning the root account has no password and cannot log in.
Administrator password required for system-wide settings
for right in system.preferences system.preferences.energysaver system.preferences.network system.preferences.printing system.preferences.sharing system.preferences.softwareupdate system.preferences.startupdisk system.preferences.timemachine; do
output=$(security -q authorizationdb read "$right" 2>/dev/null)
if [ -z "$output" ]; then
echo "$right: could not read"
continue
fi
shared=$(printf '%s' "$output" | xmllint --xpath 'name(//*[text()="shared"]/following-sibling::*[1])' - 2>/dev/null)
group=$(printf '%s' "$output" | xmllint --xpath '//*[text()="group"]/following-sibling::*[1]/text()' - 2>/dev/null)
auth=$(printf '%s' "$output" | xmllint --xpath 'name(//*[text()="authenticate-user"]/following-sibling::*[1])' - 2>/dev/null)
owner=$(printf '%s' "$output" | xmllint --xpath 'name(//*[text()="session-owner"]/following-sibling::*[1])' - 2>/dev/null)
[ "$shared" = false ] && [ "$group" = admin ] && [ "$auth" = true ] && [ "$owner" = false ] || echo "$right: expected shared=false, group=admin, authenticate-user=true, session-owner=false"
donePass: No output. All eight System Settings rights require administrator authentication.
Fail: Any printed line identifies a right that could not be read or has a missing or incorrect authorization setting.
Each right must have shared=false, group=admin, authenticate-user=true and session-owner=false. Nyvel evaluates all eight together; any one with a missing or different value fails the check.
CIR-11.5.2(b) Identification — every identity linked to a single person
Guest account disabled
defaults read /Library/Preferences/com.apple.loginwindow GuestEnabledPass: 0, or the key does not exist, and Guest User is not offered after restarting the Mac.
Fail: 1. Guest User can still be offered before FileVault unlock, even when the normal login window says Guest User: Off.
Users & Groups reports the normal, post-unlock login window. With FileVault, macOS can separately offer a restricted Safari-only Guest session before the encrypted disk is unlocked, including for Find My. It is still unauthenticated access, so check both the lock screen and the first screen after restart.
CIR-11.6.1 Secure authentication — no unauthenticated sign-in
Automatic login disabled
defaults read /Library/Preferences/com.apple.loginwindow autoLoginUserPass: The key does not exist. Any username here means the Mac logs in without authenticating.
CIR-11.6.2(e) Authentication — inactive sessions terminated after a predefined period
Automatic screen lock enabled
sysadminctl -screenLock statusPass: A password is required, immediately or within 60 seconds — that grace period is a setting, and 60 is the default ceiling.
Runs in the context of the logged-in user, so it has no answer on a Mac with nobody signed in — which is why Nyvel reports this one as not applicable rather than passing on such a device.
Screen saver starts within 20 minutes
defaults -currentHost read com.apple.screensaver idleTimePass: A value above 0 and no more than 1200 — 20 minutes. 0 disables the screen-saver trigger and fails this check; display sleep is a separate trigger.
This is the screen-saver timer, not the “Turn display off when inactive” value in Lock Screen settings. For example, idleTime 300 means the screen saver starts after 5 minutes even if the display is set to turn off later; whichever event happens first can trigger the password requirement.
CIR-12.4.1 Asset inventory — device enrolled, observed, and changes recorded traceably
Enrolled in MDM
Already checked under CIR-6.3.1. The same result also evidences this Annex point.
Defensible to check, but not universally expected
These are worth tracking and some organisations are asked about them, but they are not part of the default set — reasonable people scope them out.
CIR-6.7.2(c) Network security — discovery and sharing services not required for operation
Internet Sharing disabled
plist=/Library/Preferences/SystemConfiguration/com.apple.nat.plist
if [ ! -e "$plist" ]; then
echo 0
elif ! plutil -lint "$plist" >/dev/null 2>&1; then
echo "ERROR: could not read $plist"
else
value=$(plutil -extract NAT.Enabled raw -o - "$plist" 2>/dev/null)
[ -z "$value" ] && echo 0 || echo "$value"
fiPass: 0. A missing file or root NAT.Enabled key also means Internet Sharing is off.
Fail: 1 or true.
Read the root NAT.Enabled value. The same plist contains nested interface dictionaries with their own Enabled keys; searching the whole plist can match the wrong one.
Remote Apple Events disabled
sudo systemsetup -getremoteappleeventsPass: Remote Apple Events: Off.
Printer Sharing disabled
cupsctl | grep _share_printersPass: _share_printers=0.
Bluetooth Sharing disabled
defaults -currentHost read com.apple.Bluetooth PrefKeyServicesEnabledPass: 0, or the key does not exist.
Per-user, so it has no answer when nobody is signed in.
Media Sharing disabled
for key in home-sharing-enabled photo-sharing-enabled public-sharing-enabled; do
value=$(defaults read com.apple.amp.mediasharingd "$key" 2>/dev/null)
[ -z "$value" ] && value=0
echo "$key: $value"
donePass: All three values are 0.
Fail: Any value is 1.
These are the live Home Sharing, photo-sharing and guest/public-sharing states for the signed-in user. Apple documents allowMediaSharingModification=false only as an optional MDM restriction that prevents changes; it does not prove the current state is off. There is no documented allowMediaSharing setting, so Nyvel does not rely on it.
AirDrop disabled
defaults read com.apple.sharingd DiscoverableModePass: Off. Contacts Only and Everyone both mean AirDrop is reachable.
DiscoverableMode is the authoritative key; com.apple.NetworkBrowser DisableAirDrop is only a fallback for Macs that have never had the setting touched, so reading that one alone reports a disabled AirDrop as enabled. A managed allowAirDrop restriction overrides both. Per-user, so it has no answer when nobody is signed in.
AirPlay Receiver disabled
managed=$(defaults read com.apple.applicationaccess allowAirPlayIncomingRequests 2>/dev/null)
case "$managed" in
0|false|False) echo "0 (disabled by MDM)" ;;
*)
value=$(defaults -currentHost read com.apple.controlcenter AirplayReceiverEnabled 2>/dev/null)
[ -z "$value" ] && value=$(defaults -currentHost read com.apple.controlcenter AirplayRecieverEnabled 2>/dev/null)
[ -z "$value" ] && echo "UNKNOWN: no applied restriction or saved toggle" || echo "$value"
;;
esacPass: 0, including 0 (disabled by MDM).
Fail: 1. The saved live toggle says AirPlay Receiver is on.
Unknown: UNKNOWN: no applied restriction or saved toggle. Open System Settings → General → AirDrop & Continuity, or use the live exposure check below.
The applied allowAirPlayIncomingRequests=false restriction is authoritative because macOS blocks incoming AirPlay. Without that restriction, both historical spellings of the per-user toggle have to be tried. An untouched Mac can have AirPlay Receiver on while both keys are absent, so absence is unknown rather than a pass.
Live exposure check for an unmanaged Mac
name=$(/usr/sbin/scutil --get ComputerName)
out=$(
/usr/bin/dns-sd -B _airplay._tcp local 2>&1 &
pid=$!
/bin/sleep 4
/bin/kill "$pid" 2>/dev/null
wait "$pid" 2>/dev/null
)
printf 'This Mac: %s\n' "$name"
if printf '%s\n' "$out" | /usr/bin/grep -Fq "$name"; then
echo "FAIL: this Mac is advertising AirPlay Receiver"
else
echo "NO ADVERTISEMENT: confirm in System Settings or with MDM"
fiFail: FAIL: this Mac is advertising AirPlay Receiver. Bonjour saw an Add record for this Mac's Computer Name.
Unknown: NO ADVERTISEMENT is supporting evidence, not a pass by itself. Confirm the toggle in System Settings or apply the MDM restriction.
This four-second Bonjour browse is for a person checking one Mac. Nyvel does not run network discovery in its fleet posture script; an Add proves exposure, but missing advertisements can result from network conditions.
Wake for network access disabled
pmset -g custom | grep wompPass: womp 0 on every power source.
An easier way to manage continuous compliance across your fleet
These commands are useful when checking one Mac. Across a fleet, the same device facts — FileVault, firewall, updates, screen lock and sharing — can support several frameworks, standards and regulatory requirements. They should be collected once and mapped wherever they are relevant, rather than checked separately for every framework.
Nyvel provides that continuous view through the MDM you already run. It maps device evidence to every supported framework and questionnaire — NIS2, Cyber Insurance, CIS Level 1, SOC 2, ISO 27001 and HIPAA; shows which Macs pass, fail or lack evidence; and verifies whether changes you make in the MDM reached the fleet.
It is read-only by construction — it never writes to your MDM and enforces nothing. Remediation stays yours; what we add is the record.
You can judge all of that without talking to anyone: the live demo runs on a simulated fleet with no account and no MDM connection, and the coverage page lists every check, clause by clause, including what we deliberately do not evidence.
Limits of this guide, and of Nyvel
- External security logging. Annex point 3.2.3(g) is not mapped. Local auditd state and the legacy macOS firewall preference do not prove that events reach an EDR, SIEM, server or network-logging system, or that they are retained, searchable, monitored and reviewed. mSCP 2 marks native macOS audit off-loading unsupported and expects an enterprise auditing mechanism.
- macOS only. iPhones and iPads are not covered here and are not collected by Nyvel.
- Mosyle and SimpleMDM. Those are the MDMs Nyvel reads today.
- Most of these are not in an MDM's inventory API. Nearly all of them need a read on the device itself rather than an inventory field.
- Readings expire. In Nyvel, script-collected signals older than 7 days are dropped and their checks report unknown rather than trusting stale evidence. An unknown never quietly counts as a pass.