Reading BSM Audit Logs on macOS
Understanding Basic Security Module audit logs — enabling auditing, reading with praudit, and tracking security events
What Is BSM?
The Basic Security Module (BSM) is an auditing framework inherited from Sun Microsystems’ Solaris, implemented on macOS through OpenBSM. While the unified logging system captures operational data for debugging and diagnostics, BSM serves a fundamentally different purpose: it provides a tamper-evident, security-grade audit trail of system events.
BSM records are written in a binary format to /var/audit/ and are designed for compliance, forensics, and security monitoring. Unlike unified logs, BSM audit logs are difficult to modify without detection and can capture granular events like individual file opens, process executions, and authentication attempts at the kernel level.
For Mac admins in regulated environments (healthcare, finance, government), BSM auditing is often a compliance requirement. Even outside those contexts, it is an invaluable forensic data source during incident response.
Audit Configuration Files
BSM behavior is controlled by three configuration files in /etc/security/:
/etc/security/audit_control
The primary configuration file that defines what gets audited and how audit files are managed:
# View the current audit configuration
cat /etc/security/audit_control
Key directives:
| Directive | Purpose | Example |
|---|---|---|
dir | Directory where audit trails are stored | dir:/var/audit |
flags | Default audit event classes for all users | flags:lo,aa,ad,pc,fc,fd |
minfree | Minimum free disk percentage before warning | minfree:5 |
naflags | Events audited even when no user is attributed | naflags:lo,aa |
policy | Audit policy flags | policy:cnt,argv,arge |
filesz | Maximum audit file size before rotation (0 = unlimited) | filesz:2M |
expire-after | Auto-purge old audit files | expire-after:10M |
/etc/security/audit_class
Maps two-letter class codes to bitmask values. The default macOS installation includes:
| Class | Code | Description |
|---|---|---|
lo | 0x00001000 | Login and logout events |
aa | 0x00000013 | Authentication and authorization |
ad | 0x00000800 | Administrative actions |
pc | 0x00000008 | Process creation and termination |
fc | 0x00000004 | File creation |
fd | 0x00000020 | File deletion |
fw | 0x00000002 | File write / modification |
fr | 0x00000001 | File read |
ex | 0x40000000 | Program execution |
nt | 0x00000400 | Network events |
/etc/security/audit_event
Maps numeric event IDs to human-readable names and their class membership. This file contains hundreds of entries covering every auditable system call.
Enabling and Managing Auditing
Check Audit Status
# Check if auditd is running
sudo launchctl list | grep auditd
# View the current audit session
sudo auditctl -s
# List current audit trail files
ls -lht /var/audit/
Enable Auditing
On modern macOS, auditd is typically loaded by default. If it is not running:
# Start the audit daemon
sudo launchctl load -w /System/Library/LaunchDaemons/com.apple.auditd.plist
Configure What to Audit
Edit /etc/security/audit_control to set the flags. A recommended configuration for security monitoring:
# Back up the original
sudo cp /etc/security/audit_control /etc/security/audit_control.bak
# A strong security-focused configuration:
# lo = login/logout
# aa = authentication/authorization
# ad = administrative actions
# pc = process operations
# fc = file creation
# fd = file deletion
# ex = program execution
sudo nano /etc/security/audit_control
After editing, refresh the audit daemon:
sudo audit -s
Warning: Enabling broad audit classes like
fr(file read) orfw(file write) on every user generates enormous volumes of data and measurable I/O overhead. Use these selectively with per-user flags orauditreducefiltering rather than system-wide.
Per-User Audit Flags
Override system defaults for specific users by editing /etc/security/audit_user:
# Audit all file operations for a specific admin account
admin_user:fr,fw,fc,fd,ex:no
Reading Audit Logs with praudit
BSM audit trails are binary. The praudit tool converts them to human-readable output:
# Read the most recent audit file in default (raw) format
sudo praudit /var/audit/current
# Read in short (one-line-per-event) format
sudo praudit -s /var/audit/current
# Read in XML format (useful for parsing)
sudo praudit -x /var/audit/current
# Pipe to less for navigation
sudo praudit -s /var/audit/current | less
Understanding Audit Tokens
Each audit record consists of multiple tokens that describe different aspects of the event:
| Token | Contains |
|---|---|
| header | Record length, event type, timestamp |
| subject | The user/process that triggered the event (UID, GID, PID, session ID) |
| return | Success or failure status of the system call |
| path | File path involved in the event |
| attribute | File attributes (permissions, owner, inode) |
| argument | System call arguments |
| exec arg | Command-line arguments for executed programs |
| ip addr | Network address information |
| text | Free-form text description |
A typical raw praudit record looks like this (one event, multiple tokens):
header,88,11,execve(2),0,Fri Feb 14 10:23:45 2026, + 312 msec
exec arg,/usr/bin/sudo
exec arg,log
exec arg,show
exec arg,--last
exec arg,5m
subject,admin_user,root,admin,admin,admin,1234,5678,40,192.168.1.10
return,success,0
This shows user admin_user executing sudo log show --last 5m and succeeding.
Filtering with auditreduce
The auditreduce tool filters binary audit trails before passing them to praudit. This is far more efficient than reading entire files:
# Filter events from a specific user
sudo auditreduce -u admin_user /var/audit/current | praudit -s
# Filter by event class (login/logout only)
sudo auditreduce -c lo /var/audit/current | praudit -s
# Filter by time range
sudo auditreduce -a 20260214090000 -b 20260214100000 /var/audit/current | praudit -s
# Filter for failed events only (useful for detecting brute force)
sudo auditreduce -r 1-255 /var/audit/current | praudit -s
# Combine filters: failed login attempts for a specific user
sudo auditreduce -c lo -u targeted_user -r 1-255 /var/audit/current | praudit -s
# Process all rotated audit files (not just current)
sudo auditreduce -c ex /var/audit/* | praudit -s
Practical Security Monitoring Examples
Detect Failed Authentication Attempts
# All failed login/auth events in the last audit trail
sudo auditreduce -c aa -r 1-255 /var/audit/current | praudit -s
Track Privilege Escalation
# All sudo and su executions
sudo auditreduce -c pc,ex /var/audit/current | praudit -s | grep -E "sudo|su "
Monitor File Deletions
# All file deletion events
sudo auditreduce -c fd /var/audit/current | praudit -s
# File deletions by a specific user
sudo auditreduce -c fd -u suspect_user /var/audit/current | praudit -s
Track Process Execution
# All programs executed (requires ex class to be enabled)
sudo auditreduce -c ex /var/audit/current | praudit -s
# Look for specific suspicious binaries
sudo auditreduce -c ex /var/audit/current | praudit | grep -i "curl\|wget\|nc\|ncat\|python\|osascript"
Investigate a Specific Time Window
When you know an incident occurred around a particular time:
# Extract events from 2:00 PM to 2:30 PM on Feb 14, 2026
sudo auditreduce -a 20260214140000 -b 20260214143000 /var/audit/* | praudit -s > /tmp/incident_window.txt
Connecting BSM to a SIEM
For fleet-wide security monitoring, forward BSM events to a centralized SIEM (Splunk, Elastic, etc.):
XML Export for Ingestion
# Export recent audit events as XML for SIEM ingestion
sudo auditreduce -a 20260214000000 /var/audit/current | praudit -x > /tmp/audit_export.xml
Continuous Forwarding with a LaunchDaemon
Create a script that periodically ships audit data to your SIEM endpoint, or use tools like osquery which can read OpenBSM events natively and forward them in structured JSON format.
# osquery can query BSM events directly
echo "SELECT * FROM process_events LIMIT 10;" | osqueryi --json
Tip: osquery’s
process_eventsandfile_eventstables consume OpenBSM audit data under the hood. If you already run osquery on your fleet, you may be getting BSM data without realizing it.
BSM vs. Unified Logging
These are complementary systems, not competitors:
| Aspect | BSM Audit | Unified Logging |
|---|---|---|
| Purpose | Security audit trail | Operational diagnostics |
| Format | Binary (tamper-evident) | Compressed binary |
| Persistence | All configured events persist | Depends on log level |
| Overhead | Moderate (kernel-level) | Low (designed for always-on) |
| Best for | Compliance, forensics, incident response | Troubleshooting, debugging, monitoring |
For Mac admins responsible for security, the recommendation is clear: use unified logging for daily troubleshooting and BSM auditing for the security audit trail you hope you never need but will be glad you have.