A computer screen with a person in a mask behind bars AI-generated content may be incorrect.

How I Accidentally Fort Knox’d myself: A macOS Security Hardening Tale

Last Updated on February 26, 2025 by Oktay Sari

The Road to Better Security Is Paved with Infinite Login Loops

If you’re reading this, you probably care about macOS security hardening. And like me, you might be interested in hardening your macOS devices according to industry standards. But let me tell you a cautionary tale about implementing security measures without proper testing, or as I like to call it, “How I turned my Mac into Fort Knox and locked myself out.”

I’m sharing this somewhat embarrassing story because, well, why should you repeat my mistakes when mine were so spectacularly educational? I’ve already tested what not to do, so you don’t have to! This humbling experience taught me more about macOS security hardening in one evening (maybe a full night) than weeks of reading documentation ever could.

The Background: macOS Security and CIS Benchmarks

As a Consultant focused on security and Microsoft Intune, I thought I knew my way around device management and security hardening. The Windows domain was my comfort zone, but macOS? That was an exciting new frontier. Having worked with macOS for a little more than a year, I was still navigating the learning curve of Apple’s ecosystem while trying to apply the same rigorous security standards I was accustomed to in the Windows world.

Enter the macOS CIS Benchmarks ) comprehensive guidelines for securing various operating systems, including macOS security hardening. For some, these benchmarks are the gold standard for security hardening, and I was eager to implement them across my fleet of 3 Macbooks. If you didn’t read my previous posts on macOS security, here’s your chance.

The CIS benchmarks come with a handy build kit full of configuration profiles and scripts… if you’re willing to shell out for a subscription, that is. I started my macOS security journey with the free macOS Security Compliance Project on GitHub and the JAMF Compliance Editor – a free tool that assesses your device against CIS standards without costing you a kidney.

macOS Security and Compliance Project

What I found though, was that many of the security recommendations still need to be configured manually. And since my personal motto is “Why spend 5 minutes doing something when you can spend 5 hours automating it,” I dove headfirst into learning bash and dabbled in just enough Python to be dangerous. Nothing says “security professional” quite like frantically Googling “how to fix broken bash script” at 2 AM, right?

While methodically working my way through CIS Level 1 and eventually Level 2 recommendations to level up my macOS security hardening, I stumbled upon what seemed like a straightforward requirement: implementing audit logging using the built-in auditd subsystem. Level 1 merely asked for setting retention parameters, while Level 2 upped the ante by requiring specific audit flags.

The CIS Benchmark recommendations looked innocent enough:

  • 3.2 Ensure Security Auditing Flags For User-Attributable Events Are Configured Per Local Organizational Requirements
  • 3.4 Ensure Security Auditing Retention is Enabled

Both pointed to a single file: /etc/security/audit_control. So I went hunting for this mystical file, only to discover it… didn’t exist. Instead, I found audit_control.example in the directory.

Let’s take a peek inside, shall we?

# DEPRECATION NOTICE
#
# The audit(4) subsystem has been deprecated since macOS 11.0, disabled since
#
# macOS 14.0, and WILL BE REMOVED in a future version of macOS. Applications that require a security event stream should use the EndpointSecurity(7) API instead.
#
# On this version of macOS, you can re-enable audit(4) by renaming or copying
# /etc/security/audit_control.example to /etc/security/audit_control,
# re-enabling the system/com.apple.auditd service by running `launchctl enable
# system/com.apple.auditd` as root, and rebooting.
#
# $P4: //depot/projects/trustedbsd/openbsm/etc/audit_control(8) $
#
dir:/var/audit
flags:lo,aa
minfree:5
naflags:lo,aa
policy:cnt,argv
filesz:2M
expire-after:10M

Did you catch that “DEPRECATION NOTICE” at the top? No? Neither did I at first. Who has time to read warnings when there’s security to implement? It’s like those terms and conditions we all definitely read before clicking “I Agree.” With my “Hack the Planet” cap firmly in place and full focus on macOS security hardening, I decided to dive in headfirst. What could possibly go wrong?

Stuck at the logon screen

The Incident: Testing? What Testing?

Picture this: It’s a regular workday. My friend Somesh is about to release his awesome Fleetly tool for managing Intune devices from your phone. He asks me to test a simple reboot feature in his tool. “No problem,” I say confidently, hitting the reboot button on my mobile.

And that’s when everything went sideways.

Looking at Intune, I can tell the device got the reboot. A few seconds later, my macbook reboots, and after the reboot, I was greeted not by my familiar desktop, but by an endless login loop. Enter password, screen flashes, back to login. Enter password again, rinse, repeat. Ehh.. Somesh??

Although I was on the phone with Somesh, I clearly pictured him being horrified of what just happened . “Did my tool break your Mac?” he asked, with maybe a little bit of panic in his voice…

“No way,” I reassured him, though at that moment, I had no idea what had happened. The last thing I did, was reboot my device.

Since I have a few test devices, I fired another reboot to my 2 remaining MacBooks but this time I used Intune for the reboot. And what do you know… Three of my Macs were suddenly paperweights with Apple logos.

macbook fleet
My MacBook fleet stuck on logon screen

The Investigation: Diving into Recovery Mode

There was nothing to do but boot into Recovery Mode and start digging since I could not sign-in normally. After mounting the disk and poking around, I discovered the culprit: the `audit_control` file.

It turns out I had deployed a script that enabled the `auditd` service, but I hadn’t properly configured the `audit_control` file first. This first script I wrote, tried to add a line to the audit_control file that DID NOT EXIST.  The script was smart enough to create the audit_control file with only 1 line in it: expire-after:60D OR 5G . After the reboot, the auditd service was trying to start, failing to find proper configuration, and causing failures that prevented login. macOS security hardening at its best!

The Technical Details: What Went Wrong

For those interested in the nitty-gritty, here’s what happened:

  1. I deployed a script that enabled the `auditd` service using `launchctl enable system/com.apple.auditd`
  2. The script didn’t first check if `/etc/security/audit_control` existed or was properly configured
  3. When `auditd` started, (after reboot) it couldn’t find valid configuration and interfered with login processes
  4. Result: infinite login loop and three very expensive Apple paperweights

The correct sequence should have been:

  1. Copy `/etc/security/audit_control.example` to `/etc/security/audit_control`
  2. Configure the retention period
  3. Configure the recommended audit flags (`-fm,ad,-ex,aa,-fr,lo,-fw`) (Optional in CIS Level 1)
  4. Only then enable and start the `auditd` service

The Solution: More scripts to the Rescue

After about 3 or 4 hours, I recovered from this incident (and apologized to Somesh), I set out to create proper scripts that would handle this configuration safely, and Somesh finally got to release his tool that evening.

I eventually ended up with three scripts:

  1. Audit Flags Configuration Script: Sets the proper audit flags in the audit_control file (CIS Level 1)
  2. Audit Retention Configuration Script: Manages retention settings to prevent logs from consuming all disk space (CIS Level 2)
  3. Restore everything to normal Script: My fallback method (script deployed with Intune)

Both scripts 1 and 2 follow a careful sequence:

  • Check if the `audit_control` file exists, creating it from the example if needed
  • Make a backup before making any changes to files
  • Ensure atomic operations (using temporary files)
  • Set proper file permissions
  • Log everything
  • Only then handle service management

To prevent race conditions between these scripts, they use a shared lock file mechanism:

readonly LOCK_FILE="/var/run/audit_config.lock"

# File locking functions. We attempt to create a directory as a lock mechanism and retry for up to 40 seconds if unsuccessful, 
# logging an error and exiting if it fails. The release_lock() removes this directory to release the lock, ensuring the script runs exclusively at any given time.

acquire_lock() {
    local timeout=40
    local attempts=0
    
    while ! mkdir "$LOCK_FILE" 2>/dev/null; do
        attempts=$((attempts + 1))
        if [[ $attempts -ge $timeout ]]; then
            log "ERROR" "Failed to acquire lock after ${timeout} seconds"
            exit 1
        fi
        sleep 2
    done
}
release_lock() {
  rm -rf "$LOCK_FILE"
}

This ensures that only one script can modify the `audit_control` file at a time, preventing potential conflicts.

You can find the scripts on my GitHub page:

  1. Script 1: Set Audit Retention
  2. Script 2: Set Audit Flags
  3. Script 3: Restore auditd

These scripts are massive! Like novels in bash form. At least to me they are… When I finally got them (script 1 and 2) running almost simultaneously and watched the acquire_lock function perform its dance of file coordination, I felt like I’d just hacked into the mainframe in some 90s movie. Complete with sunglasses and dramatic keyboard typing.

But hey, when you’re a card-carrying member of a WhatsApp group called “MacIntune & Cheese” (possibly the greatest pun in IT history), you’re practically obligated to geek out over things like mutex locks and atomic file operations.

MacIntune & Cheese

The Importance of Proper Audit Flags

The CIS Benchmarks recommend enabling specific audit flags, but it’s worth understanding what they do and their potential impact. Each flag watches different activities, and together they create a comprehensive auditing system. Let’s see what activities the CIS recommendations want you to log (or not).

  • -fm : file attribute modify (Record failed events)
  • ad. : administrative actions
  • -ex : program execution (Record failed events)
  • aa : authentication and authorization
  • -fr : file read (Record failed events)
  • lo. : login_logout
  • -fw : file write (Record failed events)

Audit flags are a comma-delimited list of audit classes as defined in the audit_class file (/etc/security/audit_class) which contains descriptions of the auditable event classes on the system.

The following prefixes can be used for each class:

  • (none) Record both successful and failed events.
  • + Record successful events.
  • – Record failed events.
  • ^ Record neither successful nor failed events.
  • ^+ Do not record successful events
  • ^- Do not record failed events.

I hope you now understand the CIS recommended flags “-fm,ad,-ex,aa,-fr,lo,-fw” a little better. Consider yourself officially an insider! Next time someone drops “dash-fm-ad-dash-ex-aa-dash-fr-lo-dash-fw” at a party, you can nod knowingly instead of thinking they’re reciting a nuclear launch code.

Proper Retention settings

NOTE: These flags can generate a lot of log data, which is why proper retention settings are crucial:

Set retention to 60 days or 5G, whichever comes first. Did you notice the standard retention is set to 10M(=10 months)

Without this setting, your logs would eventually consume enough space to qualify your Mac as a portable data center rather than a computer. Trust me, “out of storage” errors are not the security feature you’re looking for.

Lessons Learned

Look, I know what you’re thinking: “Shouldn’t a professional already know all this?” And you’re absolutely right. These aren’t groundbreaking revelations. They’re 101 principles I’ve preached to clients for years. But there’s a vast difference between knowing best practices and religiously following them in every situation.

In the heat of the moment, when you’re on a roll configuring systems, it’s easy to skip steps and take shortcuts. “I’ll just enable this quickly,” you tell yourself. “I know what I’m doing.” These moments of overconfidence are precisely when disaster strikes. Fortunately, this doesn’t happen that often 🙂

  1. Always have a recovery plan before implementing security hardening
  2. Test thoroughly in isolated environments before deploying
  3. Create scripts that handle failure gracefully and verify prerequisites
  4. Most importantly; Fully understand what you are doing, before diving in. Complete comprehension of security implementations (or any other change), their potential side effects, and their impact on system functionality is critical.

Understanding the Audit Control Subsystem

If you’re craving a deep dive into audit control, follow the links below this post. But for those who prefer the “executive summary” version, let’s examine the example file and decode it into plain English.

# DEPRECATION NOTICE 
# 
# The audit(4) subsystem has been deprecated since macOS 11.0, disabled since # # macOS 14.0, and WILL BE REMOVED in a future version of macOS. Applications that require a security event stream should use the EndpointSecurity(7) API instead. 
# 
# On this version of macOS, you can re-enable audit(4) by renaming or copying 
# /etc/security/audit_control.example to /etc/security/audit_control, 
# re-enabling the system/com.apple.auditd service by running `launchctl enable 
# system/com.apple.auditd` as root, and rebooting. 
# 
# $P4: //depot/projects/trustedbsd/openbsm/etc/audit_control(8)$ 
#
dir:/var/audit 
flags:lo,aa 
minfree:5 
naflags:lo,aa 
policy:cnt,argv 
filesz:2M 
expire-after:10M

Let’s break down this configuration file:

dir:/var/audit
The digital filing cabinet where your Mac stores all its audit logs. Like that junk drawer in your kitchen, but much more organized.

flags:lo,aa
Your “what to track” list. This tells your Mac which user activities are interesting enough to write down. Here, it’s tracking logins/logouts (lo) and authentication attempts (aa).

minfree:5
The “panic button” setting. When your disk space drops below 5%, your Mac starts waving red flags saying, “I’m running out of room for all these logs!”

naflags:lo,aa
Similar to regular flags, but for mysterious events that can’t be traced to a specific user. Like finding fingerprints but not knowing whose they are.

policy:cnt,argv
The rulebook for how logging behaves. This particular setting ensures logging continues even if things go sideways and captures command arguments (the what) along with commands (the how).

  • Cnt – Allow processes to continue running even though events are not being audited
  • Argv – Audit command line arguments to execve(2)

filesz:2M
How fat each log file can get (2 megabytes) before your Mac starts a new one.

expire-after:10M
When to throw out old logs – in this case, after they reach a combined size of 10 megabytes.

A little bit of History – Way back in time

OpenBSM began as a project by McAfee Research (McAfee Inc.’s security division) in 2004, developed under contract for Apple Computer Inc. The TrustedBSD Project later adopted this implementation as the foundation for the broader OpenBSM distribution.

Authors

McAfee Research initially developed this security software under contract to Apple. Additional contributors to the project include Wayne Salamon, Robert Watson, and SPARTA Inc.

The underlying audit record format and event stream specifications (Basic Security Module or BSM) were originally created by Sun Microsystems.

Historical context and how this all started

Back around 2004, Apple wanted to prove their Mac computers were secure enough for government and business use. To do this, they submitted their operating system for an official security certification called “Common Criteria.”

To meet the security requirements, Apple needed a way to track what was happening on their computers. Instead of building this from scratch, they borrowed an open-source tool called OpenBSM, which was based on security software originally created by Sun Microsystems.

Apple passed the security test and got their certification. The tracking system they used (auditd) has remained part of macOS ever since, even though Apple is now slowly replacing it with newer security tools.

This explains why we’re dealing with this older auditing system today and why it has that “deprecated” warning.

A Warning for the Brave

If you’re considering implementing audit logging on macOS, proceed with caution. While it provides valuable security information, it can also lock you out of your system if misconfigured. Don’t believe me? Read this blog again…

CRITICAL WARNING – USE AT OWN RISK

The scripts and configurations mentioned in this blog can cause serious system issues including boot failures and login problems if not correctly implemented. Always test thoroughly in a controlled environment before deploying to production systems. Don’t just trust any script you find out there. Try to really understand what it does!

The Bottom Line

Security hardening is important but so is maintaining system usability. Finding the right balance requires careful planning, thorough testing, and sometimes learning the hard way. By now, you should have a clear understanding of macOS’s audit system, its origins as a certification requirement, its current deprecated status, and most importantly, how to implement it without locking yourself out of your Mac.

The audit subsystem may be a relic from the past, like finding an 8-track player in a Tesla. Until Apple fully replaces auditd with the EndpointSecurity framework, it remains an important tool in your macOS security arsenal.

As for Somesh’s Fleetly tool? It works beautifully and had nothing to do with my self-inflicted system lockout.

Stay secure, but test thoroughly!

Want to try these scripts yourself? You can find them on my GitHub.

For more information on macOS audit control subsystem:

5 2 votes
Article Rating

Oktay Sari

#Microsoft365 | #Intune |#MEM | #Security | Father | #Diver | #RC Pilot & #Magician in spare time | Microsoft MVP

Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments