Skip to content

ExecutionLogs

Gatekeeper and XProtect Evidence on macOS

Gatekeeper, XProtect and XProtect Remediator leave log entries and databases that show which code was assessed, approved, flagged or removed.

Location
/var/db/SystemPolicyConfiguration/ExecPolicy
Proves
Whether macOS assessed, allowed, blocked or remediated a given program, and which behaviors it flagged
Timestamps
Unified log: shown in the time zone recorded with each entry unless --timezone is set; XPdb dt: text date-time; ExecPolicy: Unix seconds
Access
root; Full Disk Access; XPdb is a Data Vault on 26.2+
Retention
Unified log: days to weeks; databases: until rebuilt (varies)
Collection
Aftermath, mac_apt, UAC, log collect, sysdiagnose

What it is

Gatekeeper is the macOS policy that checks quarantined code on first launch: signature, Developer ID, notarization and XProtect signatures. It is implemented by syspolicyd. XProtect is Apple's signature-based anti-malware (YARA rules and related data in XProtect.bundle). XProtect Remediator is a set of scanners in XProtect.app that run periodically and can remove known malware. From macOS 13 Ventura, the XProtect Behavior Service (Bastion rules) records, but does not block, processes that touch sensitive locations.

None of these keep a single tidy history. Evidence is spread across the unified log, several SQLite databases and version plists.

Where it lives

ArtifactPathmacOSProtection
Gatekeeper and exec policy DB/var/db/SystemPolicyConfiguration/ExecPolicyDocumented since 10.14; provenance_tracking table from 13root
Notarization tickets DB/var/db/SystemPolicyConfiguration/TicketsDocumented since 10.14root
Gatekeeper policy DB/var/db/SystemPolicy (authority table); /var/db/SystemPolicyConfiguration/SystemPolicy on recent releasesLong-standing, location varies by releaseroot
Last Gatekeeper rejection/private/var/db/SystemPolicyConfiguration/.LastGKReject; older releases: /private/var/db/.LastGKRejectCurrent path in Apple's Security source from macOS 15; legacy path beforeroot
Gatekeeper data/private/var/db/gkopaque.bundle; gke.bundle in /private/var/db or /var/db/SystemPolicyConfiguration depending on releaseCurrent releasesroot
XProtect data (legacy)/Library/Apple/System/Library/CoreServices/XProtect.bundle10.15-14; fallback on 15+SIP
XProtect data (primary)/var/protected/xprotect/XProtect.bundle15 Sequoia+SIP
XProtect Remediator/Library/Apple/System/Library/CoreServices/XProtect.app12.3+SIP
Behavior Service DB/var/protected/xprotect/XPdb13 Ventura+root
Behavior Service DB (moved)/var/protected/xprotect/db/XPdbXProtectPayloads 156+Data Vault from 26.2
LogsUnified log (/private/var/db/diagnostics)Allroot to read

From macOS 26.2 the db folder is a Data Vault that even root cannot open on the running system; researchers report that it is readable from a mounted Data volume (Recovery or a local snapshot). The com.apple.provenance xattr (11 bytes) on app bundles holds a key into provenance_tracking.

What it proves

  • An app was assessed by Gatekeeper, and whether it was accepted or rejected (syspolicyd log entries, .LastGKReject).
  • A user explicitly overrode Gatekeeper (log entries; Endpoint Security ES_EVENT_TYPE_NOTIFY_GATEKEEPER_USER_OVERRIDE from macOS 15).
  • An app was first allowed to run after download and its cdhash at that time (provenance_tracking, Ventura+).
  • XProtect Remediator detected or remediated a named threat (log category XPEvent.structured; ES events ES_EVENT_TYPE_NOTIFY_XP_MALWARE_DETECTED / ..._REMEDIATED from macOS 13).
  • A process triggered a Behavior Service rule, with executable and responsible process hashes and team IDs (XPdb).
  • Which XProtect and Remediator versions were installed (bundle Info.plist).

A clean Gatekeeper or XProtect verdict does not prove code is benign; signatures cover known families only.

Key fields

XPdb events table (Ventura+): violated_rule, exec_path, exec_cdhash, exec_signing_id, exec_team_id, exec_sha256, exec_is_notarized, responsible_path, responsible_cdhash, responsible_signing_id, responsible_team_id, responsible_sha256, responsible_is_notarized, reported, profile_hash, dt.

ExecPolicy: provenance_tracking (Ventura+) stores per-app provenance with cdhash; older tables include legacy_exec_history_v4, scan_targets_v2 and executable_measurements_v2. Schemas are undocumented, so inspect with .tables and .schema.

Version plists: CFBundleShortVersionString in each bundle's Contents/Info.plist.

Timestamps

  • Unified log: log show does not follow TZ; without --timezone it prints each entry in the time zone recorded when it was written. Pass --timezone UTC for timelines (see Unified Logs).
  • XPdb dt: text date-time (for example 2023-06-30 06:34:28); verify the timezone on a test system.
  • ExecPolicy integer times are Unix seconds; APOLLO's ExecPolicy modules convert them with UNIXEPOCH.
SELECT dt, violated_rule, exec_path, exec_team_id, responsible_path
FROM events ORDER BY dt DESC;

Retention

Unified log entries age out with the log store (typically days to a few weeks, depending on volume). XPdb records each unique rule fingerprint once per process per boot and is uploaded to Apple; do not expect a complete history. ExecPolicy and SystemPolicy rows persist until macOS rebuilds them. XProtect bundles are replaced on each update.

Collection

# Logs first: they age out
sudo log collect --last 7d --output ./case/system.logarchive
# Databases (root, Full Disk Access)
sudo ditto /var/db/SystemPolicyConfiguration ./case/spc
# Older releases keep SystemPolicy and .LastGKReject in /var/db (the ditto above copies the current .LastGKReject)
sudo cp -p /var/db/SystemPolicy /private/var/db/.LastGKReject ./case/ 2>/dev/null
# db/ is a Data Vault on 26.2+: copy it from a snapshot or from Recovery
sudo cp -p /var/protected/xprotect/XPdb* /var/protected/xprotect/db/XPdb* ./case/ 2>/dev/null
spctl --status
  • Aftermath collects XProtect Behavior Service data (from the legacy /var/protected/xprotect/XPdb path, not db/XPdb), XProtect versions and Gatekeeper status.
  • UAC files/system/xprotect.yaml collects the XProtect, XProtect Remediator and MRT Info.plist files.
  • sysdiagnose includes a log archive.

Parsing

  • log on a live system or .logarchive:
log show ./case/system.logarchive --info \
  --predicate 'subsystem == "com.apple.XProtectFramework.PluginAPI" AND category == "XPEvent.structured"'
log show ./case/system.logarchive --info --predicate 'subsystem == "com.apple.syspolicy.exec"'
log show ./case/system.logarchive --info --predicate 'process == "syspolicyd"'
  • mac_apt XPROTECT plugin (XProtect diagnostic files and Behavior Service DB) and QUARANTINE plugin (.LastGKReject).
  • sqlite3 for XPdb and ExecPolicy, on copies.
  • Assess a sample on an analysis Mac: spctl --assess --type execute -vv <app>, codesign -dv --verbose=4 <app>.

Unified Log Parser opens a .logarchive, the diagnostics and uuidtext folders or a log show export in the browser, applies DFIR triage rules and exports CSV or Timesketch; nothing is uploaded.

Quarantine Parser reads .LastGKReject together with the quarantine database, so a rejection can be tied back to its download.

Investigator tips

  • Build the chain: quarantine event, then Gatekeeper assessment, then provenance_tracking row, then launchd persistence.
  • From macOS 15 the Control-click bypass is gone; overrides go through System Settings, so a user override is a deliberate act worth documenting.
  • XPdb responsible_path often names the parent app (Terminal, a browser, an installer), which helps attribute activity.
  • /var/protected/xprotect/XPdb on 26.2+ may be old or stale: check the db subfolder.
  • Record XProtect and Remediator versions at collection time: a detection that appears after an update tells you when coverage arrived, not when infection happened.
  • Paths under AppTranslocation in logs mean a quarantined app ran from a randomized read-only mount.
  • Correlate installer packages with install history and privacy grants with TCC.db.

See also