Audit log export
What Outbound's sealed audit log records, where it lives, its JSON Lines format, and how managed preferences copy it to a folder or send it to a SIEM.
Outbound’s network filter writes every connection decision, and events such as rule changes, approvals, feed installs and filter starts, to a sealed audit log: JSON Lines files per UTC day, each line chained to the one before. It keeps 30 days unless AuditRetentionDays (1 to 400) is forced. When the AuditExportPath managed preference is forced, the app mirrors those files into the directory you name, so a log collector can pick them up. Outbound can also send each line to a SIEM itself, over syslog with TLS or HTTPS; see Sending to a SIEM. Retention in your folder or SIEM is your organisation’s decision.
Where the log lives
Section titled “Where the log lives”The sealed log belongs to the network filter, which runs as root, in a folder only root can read: /var/root/Library/Application Support/com.outboundfirewall.outbound.filter/audit. The background agent keeps a copy in the audit folder beside the rules file for the app to read. Exports always read the sealed log, never that copy:
/var/root/Library/Application Support/com.outboundfirewall.outbound.filter/audit/2026-10-19.0.jsonlFiles are named YYYY-MM-DD.N.jsonl: the UTC date, then a segment number from 0. A new segment starts when the current one passes 16 MiB. If OUTBOUND_STORE_PATH moves the rules file, the agent’s copy moves with it; the sealed log does not. See Where Outbound keeps its data.
Day files older than the retention period (30 days, or the forced AuditRetentionDays) are deleted. Nothing else is pruned, and files in your export directory are never touched by this: what Outbound keeps locally and what your organisation keeps are separate decisions.
File format
Section titled “File format”Each line is one JSON object with sorted keys; absent optional fields are omitted. Dates are ISO-8601 strings.
{"flow":{"direction":"outgoing","path":"/Applications/Safari.app/Contents/MacOS/Safari","proto":"tcp","remoteAddress":"203.0.113.7","remoteHost":"example.com","remotePort":443,"signingID":"com.apple.Safari","teamID":"AAABBBCCCC"},"reason":"rule","ruleID":"…","timestamp":"2026-10-19T09:30:00Z","verdict":"deny"}| Field | Type | Meaning |
|---|---|---|
timestamp |
ISO-8601 date | When the decision was made. |
flow.signingID |
String, optional | The program’s signing identifier. |
flow.teamID |
String, optional | Its code-signing team. |
flow.path |
String, optional | The executable’s path. |
flow.remoteHost |
String, optional | The host name, when one is known. |
flow.remoteAddress |
String, optional | The remote address. |
flow.remotePort |
Number, optional | The remote port. |
flow.proto |
String | tcp, udp, icmp or any. |
flow.direction |
String | outgoing, incoming or any. |
verdict |
String | The final decision: allow or deny. |
ruleID |
UUID, optional | The rule that decided, if one did. |
reason |
String | Why: a rule matched, the mode default applied, a timeout expired, and so on. |
kind |
String, optional | What the line records: flow, config, change, approval, feed, licence or lifecycle. A line without it is a flow. |
action |
String, optional | The event on a non-flow line, such as filter.started. |
seq |
Number, optional | The line’s sequence number in the sealed log. |
prev |
String, optional | SHA-256 of the line before, which chains the log. |
mac |
String, optional | A keyed hash (HMAC) made with the filter’s key, which only root can read. |
host |
String, optional | The computer name, or a hash of the serial number when AuditHostIdentifier is serialHash. |
user |
Object, optional | The console user: uid and name. |
appVersion |
String, optional | The Outbound version that wrote the line. |
remoteRedacted |
String, optional | domain, hashed or keyUnavailable when AuditRemoteDetail hid part of the remote. |
The sealed fields are absent on lines written before the sealed log. Change and notice lines can also carry change, noticeID and eventID.
Connection verdicts are allow or deny; other records, such as gap markers and lifecycle events, can use ask: when an answer was deferred or a timeout decided, the final allow or deny is the verdict and the fuller state is kept in reason (for example ask-allow or timeout-deny). A gap in delivery is recorded as a line whose verdict is ask with a reason counting the lost events.
The export
Section titled “The export”With AuditExportPath forced, the background agent reads the sealed log from the filter, checks that the sequence numbers and the prev chain are unbroken (the mac field is not checked, because only root can read its key), and copies each day file into that directory:
- When the path is missing or differs in size from the copy, the file is copied. Today’s file is copied again as it grows.
- Only complete lines are copied. A line still being written is left for the next export, so a collector never sees a partial JSON line. A day file with no complete line yet is not exported at all.
- Each copy is written to a temporary file in the destination, then renamed, so a collector never reads half a file. The temporary name starts with a dot and does not end in
.jsonl. - The export runs at launch, when the administrator changes the path, and after new events are written, at most once a minute.
- An export that takes longer than 120 seconds is cancelled and reported as failed. A slow destination never delays the writing of the audit log itself.
- The destination directory is created with permissions 0700 and copied files are 0600.
AuditRemoteDetaildecides how much of each remote the copies keep:full,domain(the registrable domain, no address) orhashed(HMAC-SHA256 of host and address).- Nothing in the destination is ever deleted or modified except the day files Outbound copies. Retention there is your organization’s.
- A failure (a missing folder, no write permission, a disk full) is shown in Settings › General › Organization and retried with the next batch. The user running the app needs write permission in the directory; the collector needs read permission.
Sending to a SIEM
Section titled “Sending to a SIEM”A profile can have the network filter send a redacted copy of every sealed line to your log service. An unmanaged Mac has no sink and opens no such connection.
AuditSyslogURL: a syslog server,syslog+tls://host:port.AuditSyslogPinnedSHA256optionally pins the server’s certificate; delivery stops if it does not match.AuditHTTPURL: an HTTPS endpoint.AuditHTTPKindishec(Splunk),elastic(bulk) orgenericJSON. The token is never a profile value:AuditHTTPTokenKeychainLabelnames a System keychain item, orAuditHTTPTokenFilenames a root-owned file with mode 0600 or 0400, at most 8 KiB. The keychain label wins when both are set.AuditFormat:jsonl,cef,leeforecs.AuditUnifiedLog: true also writes redacted lines to the unified log.AuditSpoolMegabytes: how much each sink may queue, in MiB (1 to 2048, default 256).
sudo outboundctl audit sinks shows each sink’s last delivery, backlog and last error. sudo outboundctl audit test-sink sends one marked test event, which is not written to the sealed log.
Status in Settings
Section titled “Status in Settings”When AuditExportPath is forced, Settings › General shows an Organization section with the destination path and, after the first export, the time it last ran: “Audit export:
Exporting on demand
Section titled “Exporting on demand”sudo outboundctl audit export --to /path/to/audit-exportThe command copies the audit log into the directory with the same rules as the app’s export and prints the name of each file it copied, one per line. A destination that is already up to date prints nothing. It reads the sealed log, so it has to run as root. Without sudo it exits 77 with “Run with sudo to export the sealed log”. When AuditRemoteDetail is forced to domain or hashed, it exits 77 and names the AuditExportPath your organisation collects from.
Before removing Outbound for every user
Section titled “Before removing Outbound for every user”When an administrator removes Outbound and its data for every local user, the sealed audit log is deleted too. To keep it, turn on Export the sealed audit log before deleting data in Settings › General › Remove Outbound and choose an empty folder outside the paths being removed. Outbound exports the log there and checks the copy first. If the export or the check fails, nothing is deleted. On a Mac whose audit export your organisation manages, use the managed destination instead. See Removing Outbound for every user.