# Santa Documentation
> Documentation for Santa, a binary and file access authorization system for macOS from North Pole Security
This file contains all documentation content in a single document following the llmstxt.org standard.
## Custom Branding
Santa can display your organization's name or logo on every window it shows, so that users can tell who manages the machine and who to contact.
Branding is configured with three keys, all documented on the [Configuration: Keys](/configuration/keys) page: `BrandingCompanyName`, `BrandingCompanyLogo`, and `BrandingCompanyLogoDark`.
All three were added in Santa 2026.1.
When any of them is set, Santa adds a "Managed by:" footer to the bottom of all notification dialogs (e.g. execution blocked, file access blocked, network flow blocked).
## Company name
`BrandingCompanyName` is the simplest option: the name is shown as text.
```xml
BrandingCompanyNameAcme Corporation
```
## Company logo
`BrandingCompanyLogo` replaces the name with an image.
The image is scaled down to fit within 84x28 points, so a wide wordmark works better than a tall or square logo.
Supply the artwork at twice that size so that it stays sharp on a Retina display.
Only the `file://` and `data:` URL schemes are supported.
HTTP and HTTPS URLs are not, as Santa will not fetch a logo over the network:
```xml
BrandingCompanyLogofile:///Library/Application%20Support/Acme/logo.png
```
If you use a `file://` URL, deploy the image alongside the profile and put it somewhere that is readable by all users.
Otherwise, embed the image directly in the profile with a `data:` URL:
```xml
BrandingCompanyLogodata:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKgAAAA4CAYAAAC...
```
### Dark mode
Santa's windows follow the user's appearance setting, so a single-color logo that reads well on a light background can disappear on a dark one.
`BrandingCompanyLogoDark` is used instead of `BrandingCompanyLogo` whenever the window is drawn in dark mode:
```xml
BrandingCompanyLogofile:///Library/Application%20Support/Acme/logo.pngBrandingCompanyLogoDarkfile:///Library/Application%20Support/Acme/logo-dark.png
```
The example below uses a dark wordmark for light windows and a light one for dark windows.
**Light appearance**
**Dark appearance**
## Precedence
Only one piece of branding is ever displayed.
The keys are evaluated in this order:
| Order | Key | Used when |
| ----- | ------------------------- | --------------------------------------------- |
| 1 | `BrandingCompanyLogoDark` | The window is in dark mode and the key is set |
| 2 | `BrandingCompanyLogo` | The key is set |
| 3 | `BrandingCompanyName` | Neither logo key applies |
A logo URL that uses any other scheme is ignored, as if the key was not set at all.
If a logo URL is accepted but the image cannot be loaded - for example the file is missing, or is not an image format that macOS can read - Santa falls back to `BrandingCompanyName`.
Set that key alongside the logo keys so that there is always something to display.
## Terminal messages
Blocks that happen in a terminal are also branded, but only ever with `BrandingCompanyName`, as logos cannot be drawn on a TTY:
```text
Santa
The following application has been blocked from executing
because its trustworthiness cannot be determined
Reason: No matching rule
Path: /Applications/Malware.app/Contents/MacOS/Malware
Identifier: 60055b1f6fb276bfacf61f91505a72201987f20ad8b6867cce3058f4c0f0f5e5
Parent: bash (2511)
Managed by: Acme Corporation
```
## Custom messages
Branding covers who manages the machine.
To change what the dialogs _say_, see the `UnknownBlockMessage`, `BannedBlockMessage`, `FileAccessBlockMessage`, `BannedUSBBlockMessage`, `EventDetailURL`, and `EventDetailText` keys on the [Configuration: Keys](/configuration/keys) page.
Rules synced from a server can also carry their own message and URL, which override the configured defaults.
---
## File-Access Authorization
File Access Authorization (FAA) policies are defined using a plist configuration
file. The policy can be specified either in a
[separate file](/configuration/keys#FileAccessPolicyPlist) or
[in-line](/configuration/keys#FileAccessPolicy) with the rest of the Santa
configuration.
If the policy is specified in a separate file, Santa will periodically re-read
this file. By default this will occur every 10 minutes but the interval can be
[overridden](/configuration/keys#FileAccessPolicyUpdateIntervalSec).
## Policy Structure
The policy file has a hierarchical structure with root-level configuration and
individual watch rules.
### Root Level Keys
- `Version` (required): Policy version identifier that will be reported in events
- `EventDetailURL` (optional): URL displayed when users receive block notifications. Supports [variable substitution](#eventdetailurl-placeholders) (e.g., `%hostname%`, `%rule_name%`, `%file_identifier%`)
- `EventDetailText` (optional): Button label text for the notification dialog, maximum 48 characters. Defaults to 'Open'.
- `WatchItems` (optional): Dictionary containing the individual monitoring rules
:::tip
If you want a default URL and button text for all file access events without
configuring them in every FAA policy, you can set the global
[FileAccessEventDetailURL](/configuration/keys#FileAccessEventDetailURL) and
[FileAccessEventDetailText](/configuration/keys#FileAccessEventDetailText)
configuration keys. Per-policy `EventDetailURL` and `EventDetailText` values
(and per-rule overrides) will take precedence over these global defaults.
:::
### Watch Item Structure
Each entry in the `WatchItems` dictionary represents a single rule. The key for
each entry is the rule name, which will be used in logs and in the block
notification UI.
:::info
Rule names (the `WatchItems` dictionary keys) must be 1-64 characters long and
match the regular expression `^[A-Za-z0-9._:-]+$`, containing only letters,
digits, periods, colons, hyphens, and underscores. For example, `ChromeCookies`,
`my_rule_1`, and `my-rule.v2` are valid, but `My Rule` and `rule=1` are not.
Invalid names will be rejected and an error will be logged.
:::
Each rule contains three main components:
- `Paths`: Array of path patterns to monitor
- `Processes`: List of allowed/denied processes with specific identifiers
- `Options`: Settings for rule behavior
## Basic Example
```xml
Versionv0.1EventDetailURLhttps://my-server/faa/%hostname%/%rule_name%/%file_identifier%WatchItemsUserFooPathsPath/Users/*/tmp/fooIsPrefixOptionsAllowReadAccessAuditOnlyRuleTypePathsWithAllowedProcessesProcessesTeamIDEQHXZ8M8AVSigningIDcom.google.Chrome.helper
```
## Path Configuration
Paths can be specified using exact matches or wildcard patterns:
- Exact paths: `/etc/sudoers`
- Wildcards: `/Users/*/Documents/*`
Each path entry can include:
- `Path` (required): The path pattern to monitor
- `IsPrefix` (optional): Boolean indicating whether the path represents prefix matching. When `true`, the rule will match files nested inside directories. When `false` or omitted, wildcards only match files/directories at that level without recursing.
:::important
If a configuration contains multiple rules with overlapping configured paths,
only one rule will be applied. Which rule will be applied is undefined, so take
care not to define rules with duplicate paths.
:::
### Path Globs
Path globs represent a point-in-time snapshot. Globs are expanded when a
configuration is applied and periodically re-evaluated based on the
[FileAccessPolicyUpdateIntervalSec](/configuration/keys#FileAccessPolicyUpdateIntervalSec)
setting.
When multiple path globs or prefixes match an operation, the rule with the "most
specific" or longest match is applied.
Glob pattern support is provided by the libc
[`glob(3)`](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/glob.3.html)
function. Extended glob patterns, such as globstar (`**`), are not supported.
### Path Resolution
All configured paths are case-sensitive and must match the case as stored on the
filesystem.
Due to system limitations, Santa cannot reliably monitor hard-linked resources.
To help mitigate bypasses, Santa will not allow the creation of hard links for
monitored paths. If hard links previously existed for monitored paths, Santa
cannot guarantee that access via these other links will be monitored.
Configured path globs must refer to resolved paths only. Monitoring access on
symbolic links is not supported. This is important as some common macOS paths
are symbolic links (e.g., `/tmp` and `/var` are both symlinks into `/private`).
## Process Matching
Processes can be matched using several identifiers:
- **Signing ID**: Specified with the `SigningID` key (e.g., `EQHXZ8M8AV:com.google.Chrome.helper`)
- **Team ID**: Specified with the `TeamID` key (e.g., `ZMCG7MLDV9`)
- **Platform Binary**: Specified with the `PlatformBinary` boolean key
- **CDHash**: Specified with the `CDHash` key (e.g., `397d55ebec87943ea3c3fe6b4d4f47edc490d25e`)
- **Leaf Certificate Hash**: Specified with the `CertificateSha256` key
- **Binary Path**: Specified with the `BinaryPath` key (e.g., `/Applications/Safari.app/Contents/MacOS/Safari`)
:::tip
Signing IDs must be scoped to a specific TeamID. You can use the same format as
binary authorization rules where the SigningID is prefixed with the TeamID (e.g.
`TeamID:SigningID`. For platform binaries, you can use the hard coded string
`platform` as the TeamID (e.g. `platform:com.apple.yes`).
:::
:::warning
Specifying binaries by full path using `BinaryPath` is not very secure, as
binaries can easily be moved. This should only be used as a last resort.
Additionally, the `BinaryPath` key does not support glob patterns (`*`).
:::
## Rule Options
The `Options` dictionary within each rule supports the following keys:
- `RuleType` (required): Defines whether the rule is data-centric or process-centric:
- `PathsWithAllowedProcesses`: Data-centric, only listed processes can access the paths
- `PathsWithDeniedProcesses`: Data-centric, listed processes cannot access the paths
- `ProcessesWithAllowedPaths`: Process-centric, listed processes can only access specified paths
- `ProcessesWithDeniedPaths`: Process-centric, listed processes cannot access specified paths
- `AllowReadAccess` (optional): Boolean controlling whether read access is allowed. When `false`, both read and write access are monitored/blocked. When `true`, only write access is monitored/blocked. Defaults to `true` if not specified.
- `AuditOnly` (optional): Boolean. When `true`, violations are logged but not blocked. Defaults to `true`.
- `EventDetailURL` (optional): Rule-specific URL that overrides the top-level EventDetailURL.
- `EventDetailText` (optional): Custom button label text for this specific rule, overriding the root-level setting.
- `BlockMessage` (optional): Custom message to be shown in the dialog presented to users upon a violation. Defaults to a reasonable, generic message that the action was blocked.
- `EnableSilentMode` (optional): Boolean. When `true`, violations are logged but no notification is shown to the user. Defaults to `false`.
- `EnableSilentTTYMode` (optional): Boolean. When `true`, violations are logged, but no notification is sent to the controlling TTY. Defaults to `false`.
## Rule Type Selection
Choose your rule type based on what you're protecting:
| Goal | Rule Type |
| ----------------------------------------------------- | --------------------------------------------------------- |
| Protect specific files/paths from unauthorized access | `PathsWithAllowedProcesses` or `PathsWithDeniedProcesses` |
| Restrict what a specific process can access | `ProcessesWithAllowedPaths` or `ProcessesWithDeniedPaths` |
**Data-centric example**: Protect browser cookies from theft by limiting access to the cookie files to only the browser processes.
**Process-centric example**: Prevent AirDrop processes from reading files in folders containing sensitive corporate data.
## EventDetailURL placeholders
When an FAA rule blocks access to a file, the user will be presented with a block notification dialog. On this dialog a
button can be displayed which will take the user to a page with more information about that event. For the button to
appear you must populate the `EventDetailURL` field, either at the top-level of the configuration or in an individual
rule. This URL can contain placeholders, which will be populated at runtime; the supported placeholders are:
| Placeholder | Description |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| `%rule_version%` | Version of the rule that was violated |
| `%rule_name%` | Name of the rule that was violated |
| `%file_identifier%` | SHA-256 of the binary that was being executed |
| `%accessed_path%` | The path that was being accessed |
| `%username%` | The executing user |
| `%team_id%` | The team ID that signed this binary, if any |
| `%signing_id%` | The signing ID of this binary, if any |
| `%cdhash%` | The binary's CDHash, if any |
| `%machine_id%` | The ID of the machine, usually the hardware UUID unless [overridden](https://northpole.dev/configuration/keys/#MachineID) |
| `%serial%` | The serial number of the machine |
| `%uuid%` | The hardware UUID of the machine |
| `%hostname%` | The system's full hostname |
## More Information
For complete example policies and use-cases, see the [File-Access Authorization
feature documentation](/features/faa) and the [FAA cookbook](/cookbook/faa).
---
## Config Generator
:::warning
This generator is still under active development and there are known rough
edges with some of the more complex configuration keys as well as more features
that will be coming soon. Please give it a try!
:::
Use this form to generate a valid Santa configuration, ready to put inside a
configuration profile and deploy to your machines. The generator will ensure
that the configuration is valid and help storing default values.
:::info
The generation is all done inside your browser; the data you input never leaves
your machine.
:::
## General
---
## Sync
---
## GUI
---
## FAA
---
## Rules
---
## Telemetry
---
## Removable Media (e.g. USB mass storage device)
---
## Metrics
---
## Generate
Click the button to generate and download the generated configuration file.
---
## Keys
This page describes all of the available configuration options recognized by
Santa.
The configuration keys are broken down into sections to make it easier to find
what you're looking for but in the configuration profile all the keys should be
set together.
Some keys (or available values for a key) will have a badge showing which Santa
version they were added or deprecated in. Where a key has been deprecated, the
description will list an alternative if one is available.
A key with next to the type can be
overridden by a sync server.
## General
General options
## Sync
Options related to syncing
## GUI
Options controlling how the GUI functions
## FAA
Options controlling file-access authorization
## Rules
Options controlling binary authorization rules
## Telemetry
Options controlling the output of telemetry data
## Removable Media (e.g. USB device)
Options controlling the Removable Media (e.g. USB device) mount control feature
## Metrics
Options controlling the export of agent metrics
---
## CEL Playground
Test and validate your [CEL expressions](/features/binary-authorization#cel) before deploying them. Enter a CEL expression and provide sample execution context as YAML, then evaluate to see the result and whether it would be cacheable.
See the [CEL expressions cookbook](/cookbook/cel/) for example expressions.
{() => {
const CELPlayground = require('@site/src/components/CELPlayground').default;
return ;
}}
:::info
The evaluation is all done inside your browser; the data you input never leaves
your machine.
:::
---
## Common Expression Language (CEL)
This page lists well-known and/or community-contributed CEL expressions.
CEL ([Common Expression Language](https://cel.dev/)) rules allow for more
complex policies than would normally be possible. Read how to configure CEL
rules in the [Binary Authorization](/features/binary-authorization#cel)
documentation.
## Apps signed since X
This will prevent executions of an app where the specific binary was signed
before the provided date. This is particularly useful when attached to a
`TEAMID` or `SIGNINGID` rule.
```clike
target.signing_time >= timestamp('2025-05-31T00:00:00Z')
```
= timestamp('2025-05-31T00:00:00Z')`}
context={`
target:
signing_time: "2025-06-01T00:00:00Z"
args:
- "--version"
envs:
HOME: "/Users/admin"
euid: 501
cwd: "/Applications"
`}
/>
## Apps signed within the last N days
This allows executions only when the binary was securely signed within a sliding
window — here, the last 90 days — and blocks anything older. Unlike a fixed
`timestamp(...)`, the window moves forward automatically each day, so the rule
never needs to be re-pushed. `today()` is the start of the current UTC day and
`days(n)` is `n`×24h (the standard `duration()` only parses units up to hours).
This requires [Workshop](https://northpole.security/), and because `today()`
changes daily the result is not cached.
```clike
target.secure_signing_time > today() - days(90)
```
The example binary below was signed in 2020, so it falls outside the window and
is blocked:
today() - days(90)`}
context={`
target:
secure_signing_time: "2020-01-01T00:00:00Z"
args:
- "--version"
envs:
HOME: "/Users/admin"
euid: 501
cwd: "/Applications"
`}
/>
## Prevent users from disabling gatekeeper
Create a signing ID rule for `platform:com.apple.spctl` and attach the following CEL program
```clike
[
'--global-disable',
'--master-disable',
'--disable',
'--add',
'--remove'
].exists(flag, flag in args) ? BLOCKLIST : ALLOWLIST
```
## Prevent Timestomping of LaunchAgents and LaunchDaemons
Malware like those produced by the Chollima groups use "timestomping" to reset the
timestamps of LaunchAgents and LaunchDaemons using touch. This can be prevented
/ detected by creating a SigningID rule for `platform:com.apple.touch` with the
following CEL program.
This technique was recently discussed by [Jaron
Bradely](https://themittenmac.com/author/jaron-bradley/) at [Objective by the
Sea v8](https://objectivebythesea.org/v8/talks.html#Speaker_24)
```clike
args.exists(arg, arg in [
'-a', '-m', '-r', '-A', '-t'
]) && args.join(" ").contains("Library/Launch") ? BLOCKLIST : ALLOWLIST
```
Note this will not stop using the system calls directly or otherwise
programmatically modifying the timestamps. Also this won't cover modifications
if the process' current working directory is already in the LaunchDaemons /
LaunchAgents directories.
## Prevent OSAScript From Popping Password Dialogs
A lot of malware on macOS will attempt to get users to enter their passwords
into a dialog box via osascript. This is a basic rule to stop directly asking
for a password dialog.
Make a SigningID rule for `platform:com.apple.osascript` with the following CEL
Program
```clike
(
args.join(" ").lowerAscii().matches(".*\\W+with\\W+hidden\\W+answer.*") ||
args.join(" ").lowerAscii().contains("password")
) &&
args.join(" ").lowerAscii().matches(
".*\\W+display\\W+dialog.*") ? BLOCKLIST : ALLOWLIST
```
Note: This will not stop obfuscated osascript that's evaluated at runtime or
any other malicious behavior triggered through osascript. For better security
block osascript all together if you can. Be aware software like the Google
Cloud SDK installer and AI tools like claude code use osascript.
Also if you're using osascript to do this legitimately this will break your
usage.
## Prevent users from enabling SSH and Remote Apple Events
As called out in [loobins](https://www.loobins.io/binaries/systemsetup/) the
systemsetup command can be used to enable SSH and Remote Apple Events via
command line options.
To block this create a signing ID rule for `platform:com.apple.systemsetup` and
attach the following CEL program:
```clike
args.join(" ").contains("-setremotelogin on") ||
args.join(" ").contains("-setremoteappleevents on") ? BLOCKLIST : ALLOWLIST
```
## Prevent Users from Taking and Mounting Time Machine Snapshots
As was presented at [Kawaiicon 2025](https://kawaiicon.org/) by [Calum Hall](https://www.youtube.com/watch?v=hIeNuqq12sk&t=1390s), Time Machine snapshots can be used to bypass [File Access Authorization rules](https://www.youtube.com/watch?v=hIeNuqq12sk&t=1390s).
You can stop the taking of local snapshots by creating a signing ID for
`platform:com.apple.tmutil` and attaching the following CEL program:
```clike
'localsnapshot' in args ? BLOCKLIST : ALLOWLIST
```
This will break taking local snapshots via the command line. Alternatively if
you need to still be able to take time machine snapshots but don't want users
to mount them locally you can stop the mount of local snapshots with a signing
ID rule `platform:com.apple.mount_apfs` with the following CEL program
```clike
('-s' in args &&
args.exists(arg, arg.contains("com.apple.TimeMachine."))) ? BLOCKLIST : ALLOWLIST
```
---
## File-Access Authorization (2)
This page lists well-known and/or community-contributed file-access
authorization policy fragments.
## Chrome Browser Cookies
This policy will prevent reads of cookies from Google Chrome, from any profile
managed by any user, except to Chrome itself and the Spotlight indexing
process.
```xml
ChromeCookiesPathsPath/Users/*/Library/Application Support/Google/Chrome/*/CookiesIsPrefixOptionsAllowReadAccessAuditOnlyRuleTypePathsWithAllowedProcessesProcessesSigningIDcom.google.Chrome*TeamIDEQHXZ8M8AVSigningIDcom.apple.mdworker_sharedPlatformBinarySigningIDcom.apple.mdsPlatformBinary
```
## Chrome Extensions Directory
This policy will prevent reads and writes of extensions used by Google Chrome, in any profile
managed by any user, excepting Chrome itself and the Spotlight indexing
process.
```xml
ChromeExtensionsPathsPath/Users/*/Library/Application Support/Google/Chrome/*/Extensions/IsPrefixOptionsAuditOnlyAllowReadAccessRuleTypePathsWithAllowedProcessesProcessesSigningIDcom.google.Chrome*TeamIDEQHXZ8M8AVSigningIDcom.apple.mdworker_sharedPlatformBinarySigningIDcom.apple.mdsPlatformBinarySigningIDcom.apple.mdsyncPlatformBinarySigningIDcom.apple.XProtectFramework.plugins.*PlatformBinary
```
## Slack Cookies
This policy will prevent reads of cookies from the Slack app, except to Slack
itself and the Spotlight indexing process. This is almost identical to the
Chrome Browser rule above because Slack is built with Electron.
The utility of this was highlighted by SpecterOps in their talk
[Modern macOS Read Teaming Tactics](https://www.youtube.com/watch?v=t_L2bdbXkp0&t=2863s)
```xml
SlackCookiesPathsPath/Users/*/Library/Application Support/Slack/CookiesIsPrefixPath/Users/*/Library/Application Support/Slack/StaleCookiesIsPrefixPath/Users/*/Library/Containers/com.tinyspeck.slackmacgap/Data/Library/Application Support/Slack/CookiesIsPrefixPath/Users/*/Library/Containers/com.tinyspeck.slackmacgap/Data/Library/Application Support/Slack/StaleCookiesIsPrefixOptionsAllowReadAccessAuditOnlyRuleTypePathsWithAllowedProcessesProcessesSigningIDcom.tinyspeck.slackmacgap*TeamIDBQR82RBBHLSigningIDcom.apple.mdworker_sharedPlatformBinary
```
## Sudoers
This policy prevents the sudoers config file from being modified by any process
except sudo itself. With this installed, users will have to use
`sudo -e /etc/sudoers` to modify the policy.
```xml
SudoersPathsPath/private/etc/sudoersPath/private/etc/sudoers.d/*IsPrefixPath/private/var/db/sudo/ts/*IsPrefixOptionsAllowReadAccessAuditOnlyRuleTypePathsWithAllowedProcessesProcessesSigningIDcom.apple.sudoPlatformBinary
```
## Lockdown Spotlight Importers
Spotlight importers have been used as [a persistence trick for a
while](https://theevilbit.github.io/beyond/beyond_0011/), going back to Patrick Wardle's [talks in 2015](https://www.blackhat.com/docs/us-15/materials/us-15-Wardle-Writing-Bad-A-Malware-For-OS-X.pdf). This was recently used in the
[Sploitlight exploit](https://www.microsoft.com/en-us/security/blog/2025/07/28/sploitlight-analyzing-a-spotlight-based-macos-tcc-vulnerability/).
```xml
SpotlightImporterProtectionPathsPath/Users/*/Library/SpotlightIsPrefixPath/Library/SpotlightIsPrefixOptionsAllowReadAccessAuditOnlyEnableSilentModeRuleTypePathsWithAllowedProcessesProcessesSigningIDcom.apple.mdsPlatformBinarySigningIDcom.apple.mdworkerPlatformBinarySigningIDcom.apple.mdworker_sharedPlatformBinarySigningIDcom.apple.mdimportPlatformBinarySigningIDcom.apple.installerPlatformBinary
```
## Lockdown Docker Desktop Settings
As seen in the [BYOB: Bring your own Blackbox - Containerized Defense Evasion
on macOS](https://www.youtube.com/watch?v=AMbxs2Nh-Rc&t=1s) talk by [Colson
Wilhoit](https://x.com/defsecsentinel) at OBTSv8 you can abuse the Docker
Desktop settings files to get a container running that will evade tools built on
the Endpoint Security Framework. Like Colson said in the talk you can use
Santa's FAA to block access to the Docker settings files, which prevents some
of the attacks.
```xml
DockerSettingsPathsPath/Users/*/Library/Group Containers/group.com.docker/IsPrefixOptionsAllowReadAccessAuditOnlyRuleTypePathsWithAllowedProcessesBlockMessageOnly Docker Desktop can modify these settings.ProcessesTeamID9BNSXJN65R
```
---
## Transitive Allowlisting
This page lists well-known and/or community-contributed Transitive Allowlisting
rules for various compiler toolchains.
For each toolchain it's important to note that the last binary that writes to
the new binary is the one that should have a rule.
## Xcode
To cover Xcode you will either need `ld`, `lipo`, or `codesign`, depending on
how the project is configured:
* `platform:com.apple.ld`
* `platform:com.apple.lipo`
* `platform:com.apple.security.codesign`
One important caveat: adding an `ALLOWLIST_COMPILER` rule for the codesign
utility could potentially allow any binary to be re-signed and executed.
---
## Getting Started
Due to the security features built-in to macOS, deployment of Santa requires
several pre-requisite steps. It is possible to skip these steps but doing so
will require manual intervention to get Santa running and cause pop-ups that
might be confusing to your users.
It is recommended to go through all of the pages in this section
in order.
:::info
If you just want to get Santa running on a single machine for experimentation,
you can skip to the [Install Santa Package](/deployment/install-package) page.
:::
---
## Install Santa Package
With all of the profiles configured you are finally ready to install the Santa
package. We assume that your organization has some mechanism for deploying
packages already, whether that's with an MDM or a packaging tool like Munki.
## Releases
The latest release of Santa is always available
[on GitHub](https://github.com/northpolesec/santa/releases/latest).
Every release includes detailed notes about what has been added and changed and
includes 3 asset files:
- A DMG file, which contains the PKG file. This file is largely unnecessary
nowadays but is still released for historical reasons.
- A PKG file, which installs Santa and immediately loads it. If an existing
Santa install is running, the package will seamlessly upgrade.
- A `.tar.gz` file containing the signed `Santa.app` bundle that is installed
by the PKG file, many configuration files and scripts involved in configuring
and signing, and a folder containing all of the debug symbols for that
release.
## Deployment
### MDM
If you already used an MDM to install the configuration profiles, you can also
use the MDM to install the package. The exact steps to configure this will
differ depending on which MDM you are using, but all should support this
ability.
When configuring this your MDM may support different kinds of applications to
be installed, Santa should be configured as an "Installer Package (.pkg)".
The packages that we distribute are signed and notarized, and in a format
suitable for direct MDM deployment.
The package contains preinstall and postinstall scripts to handle ensure Santa
is fully loaded once the package install is complete, so you should not need to
add extra scripts if this is sorted.
If your MDM supports it, an "Audit and Enforce" mode is ideal as this will
ensure that the Santa package is installed and not removed.
### Munki
Munki is a very popular open-source software management tool for macOS. Munki
is a client that runs on each macOS machine and retrieves packages from a server
managed by the company.
Munki natively supports macOS installer packages and can enforce that the
package is installed and re-install if the user attempts to remove it. It is
recommended to install Santa as one of the `managed_installs` in your
manifest.
Here's an example PkgInfo that can be imported into a catalog:
```xml
nameSantaversion2025.3descriptionSanta, the friendly security tool for macOSinstallstypeapplicationpath/Applications/Santa.appCFBundleIdentifiercom.northpolesec.santaCFBundleNameSantaCFBundleShortVersionString2025.3blocking_applicationsreceiptspackageidcom.northpolesec.santaversion2025.3installer_item_hash06a33253a015be318503523df054771786a2d71d99f5e679329f32968d808cc1installer_item_location ~ you must populate this with the path to santa-2025.3.pkg ~ uninstallableunattended_install
```
### Manual Install
If you're installing Santa on a small number of machines and/or don't have an
MDM, you can manually install the Santa package. This can be done either by
double-clicking the package file in Finder, or using the command-line:
```shell
sudo installer -pkg santa-2025.3.pkg -tgt /
```
### Homebrew
If you're installing Santa on a small number of machines and/or don't have an
MDM, you can install Santa from homebrew:
```shell
brew install santa
```
You will likely be prompted for your sudo password during installation, this is
expected; Santa cannot be installed in a user folder like normal homebrew
packages.
:::info
The Santa homebrew cask is **not** maintained by the Santa team.
Homebrew has automation that updates the cask version within a few hours of a
new release being published and the install method just installs the package so
everything _should_ work but we cannot offer support for it.
:::
## Verification
You can check that Santa is installed and running using `santactl`:
```shell title="santactl version"
santad | 2025.3 (build 97, commit 10bdfcc2)
santactl | 2025.3 (build 97, commit 10bdfcc2)
SantaGUI | 2025.3 (build 97, commit 10bdfcc2)
```
```shell title="santactl status"
>>> Daemon Info
Mode | Monitor
Log Type | file
File Logging | No
Removable Media Blocking | Yes
Removable Media Remounting Mode | rdonly, nosuid, noowners
On Start Removable Media Options | None
Watchdog CPU Events | 0 (Peak: 3.31%)
Watchdog RAM Events | 0 (Peak: 15.19MB)
>>> Cache Info
Root cache count | 133
Non-root cache count | 3
>>> Database Info
Binary Rules | 1
Certificate Rules | 0
TeamID Rules | 8
SigningID Rules | 4
CDHash Rules | 2
Compiler Rules | 2
Transitive Rules | 0
Events Pending Upload | 117
>>> Static Rules
Rules | 1
>>> Watch Items
Enabled | Yes
Policy Version | v1.1
Rule Count | 1
Config Path | /var/db/santa/faa.plist
Last Policy Update | 2025/04/17 12:55:46 -0400
>>> Sync Info
Sync Server | https://my-sync-server/santa/
Clean Sync Required | No
Last Successful Full Sync | 2025/04/17 12:56:01 -0400
Last Successful Rule Sync | 2025/04/17 12:56:01 -0400
Push Notifications | Connected
Bundle Scanning | Yes
```
---
## Lite Package
Alongside the regular Santa deployment package, we also make available a "lite"
package, which is named `santa-lite-YYYY.X.pkg`. This package has Workshop-only
components removed.
## Why does the Lite package exist?
Santa includes an optional network extension for adding telemetry of network
events. While this extension can only be activated by Workshop customers, its
mere presence on disk concerns some users, despite being inert without being
connected to Workshop.
## What's the downside of the Lite package?
The Lite package is built from the same artifacts as the full package, then
re-signed and re-notarized after removing components. It receives less testing -
we run upgrade testing for each release but do not include the Lite variant, as
it would significantly expand our test matrix.
Should you ever want to activate the removed features, you'll need to do a
migration from Lite to full package.
## Should I use the Lite package?
If you're a Workshop customer: no, this will prevent certain features from
working.
If you're not a Workshop customer: we recommend the full package. The Lite
package only saves a few megabytes, and the removed components are inert without
Workshop.
## Can I upgrade from Lite to full package?
_Yes_, but the Santa system extension will not be replaced unless the version
number is higher. In practice the code for the running extension should be
identical, but this scenario is not one we test. You may also find systems
reporting that they're running the Lite version after being replaced with the
full version until the machines reboot.
## Can I downgrade from the full package to Lite?
_Yes_ with the same caveat as above and another exception: if Santa is connected
to Workshop it will block a downgrade to the Lite package to avoid breaking
functionality.
---
## Migration
This guide outlines the migration process from Google Santa to North Pole
Security (NPS) Santa, designed to ensure a smooth transition with minimal
security coverage gaps.
If you are not currently running Google Santa, you should instead read the
[Getting Started](/deployment/getting-started) page.
## Pre-requisites
- Active Google Santa installation
- MDM (Mobile Device Management)
- If you do not use an MDM jump to [installing NPS Santa](#2-install-nps-santa)
- A method to deploy the NPS Santa installer package
## Migration Steps
### 1. Configure System Extensions
- (Optional) Add a Team ID rule for North Pole Security's Team ID (`ZMCG7MLDV9`)
to Gogle Santa. This is to gauarantee that complex MDM setups don't allow Google
Santa to block NPS Santa if they try to start simultaneously.
- Either add it as a Static Rule, use `santactl rule` or via your sync server.
- Update your MDM configuration to allow both Google and NPS Santa system
extensions simultaneously. This dual-authorization is temporary but necessary
for a seamless transition.
- Deploy an updated TCC profile for NPS Santa also
- See the prior pages in this section for how to configure profiles.
### 2. Install NPS Santa
Deploy the [latest NPS Santa
release](https://github.com/northpolesec/santa/releases/latest) to your systems.
The installer is designed with migration support.
- NPS Santa will remain dormant after installation - It will automatically
monitor for the removal of Google Santa - At this point in time, NPS Santa will
**not** appear in `systemextensionsctl list` output.
:::warning
To avoid system extension authorization popups, ensure the MDM has
applied the configurations from step #1 before deploying the NPS Santa
installer.
:::
### 3. Remove Google Santa
Through your MDM:
- Remove Google Santa from the allowed system extensions list - This will
trigger the automatic unloading of Google Santa - NPS Santa will detect the
removal and finish loading itself within a few seconds
:::warning
To minimize security coverage downtime, ensure the NPS Santa
installer has run before removing Google Santa from the allowed system
extensions list
:::
If you do not use an MDM:
- Remove Google Santa by dragging `/Applications/Santa.app` to the trash
- Respond affirmitively to the admin authorization popup dialog
### 4. Verification
NPS Santa should now be installed and running:
```shell
$ systemextensionsctl list
2 extension(s)
--- com.apple.system_extension.endpoint_security
enabled active teamID bundleID (version) name [state]
EQHXZ8M8AV com.google.santa.daemon (2024.9/2024.9.674285143) santad [terminated waiting to uninstall on reboot]
* * ZMCG7MLDV9 com.northpolesec.santa.daemon (2024.10/2024.10.49) santad [activated enabled]
```
The terminated Google Santa entry will be cleared on the next reboot. In a
terminated state, Google Santa does not affect NPS Santa.
You should also verify that `santactl version` reports the NPS Santa version
that you installed:
```shell
$ santactl version
santad | 2025.3 (build 94, commit 63bc558d)
santactl | 2025.3 (build 94, commit 63bc558d)
SantaGUI | 2025.3 (build 94, commit 63bc558d)
```
---
## Network Extension
Santa includes an optional network [system
extension](https://developer.apple.com/documentation/systemextensions) that can
monitor and control network traffic. It provides two capabilities: a content
filter for monitoring network flows and a DNS proxy for intercepting DNS queries.
:::info
The network extension requires a [Workshop](https://northpole.security/) subscription
and will not activate without one.
:::
## Installation
### Enabling the feature
Workshop customers must enable the network extension on a
[tag](https://docs.workshop.cloud/tags). Navigate to the tag's sync
settings and enable the **Network Extension** setting. The network extension
will only be installed on hosts that are members of a tag with this setting
enabled.
### Automatic installation
The network extension is lazily installed by default. Activating a network
extension tears down all existing network connections, which can disrupt users.
To minimize impact, Santa will automatically install or upgrade the network
extension when:
- The system reboots
- The system wakes from sleep (e.g. when the laptop lid opens)
The network extension [profiles](profile-network-extension.md) must be installed
for automatic installation to succeed silently. If the profiles are not installed
and a user is logged in, macOS will display its standard prompt asking the user
to approve the extension.
### Manual installation
If you need to install the network extension immediately, you can trigger it
manually:
```text
sudo santactl install --network-extension
```
:::caution
This will tear down existing network connections and can interrupt active
network operations. Use with care.
:::
## Verification
You can check the status of the network extension using `santactl status`. The
output includes a Network Extension section:
```text title="santactl status"
>>> Network Extension
Enabled | Yes
Loaded | Yes
```
- **Enabled** means the appropriate Workshop settings have been configured to
allow the network extension to run on the system.
- **Loaded** means the network extension has been installed and activated via the
network extension provider configuration.
You can also run `santactl version` to view version information:
```text title="santactl version"
santad | 2026.3 (build 187, commit 47a21b0d)
santactl | 2026.3 (build 187, commit 47a21b0d)
SantaGUI | 2026.3 (build 187, commit 47a21b0d)
santanetd (BETA) | 2026.3 (build 187, commit 2149a1ce)
```
If a newer version of the network extension is available, it will be noted in the
output and installed on the next reboot or sleep/wake cycle.
---
## Profiles: Background Apps
Santa has components that run in the background (e.g. for presenting
notifications to users, for syncing, etc.). Starting in macOS 13 Ventura, users
will receive notifications whenever a piece of software is installed that is
able to run in the background and so installing the Santa package can cause
these "Background Items Added" notifications to appear. These notifications can
be suppressed by installing a profile with your MDM.
## Generating the profile
The process for adding a "Service Management" profile to your machines will
differ depending on which MDM you are using. Many MDMs have specific support for
this kind of profile, usually labelled as a "Login & Background Items" or
"Service Management" profile.
You will need the following information to configure this profile:
- Identifier Type: Team Identifier
- Identifier: `ZMCG7MLDV9`
## Example profile
If your MDM doesn't have an option to add a Service Management profile but does
have the option for deploying custom profiles, you can use the following
example as a template.
```xml showLineNumbers title="santa-background.mobileconfig"
PayloadUUIDC5F3332F-9DEA-4FE5-924E-81708D962874PayloadTypeConfigurationPayloadOrganizationMy CompanyPayloadIdentifiercom.mycompany.santa.servicemanagement.C5F3332F-9DEA-4FE5-924E-81708D962874PayloadDisplayNameSanta: Background AppsPayloadDescriptionSuppress notifications about Santa background appsPayloadScopeSystemPayloadVersion1PayloadEnabledPayloadRemovalDisallowedPayloadContentPayloadUUID1161A7ED-2E7B-4744-B933-D3B9F58A1AAEPayloadTypecom.apple.servicemanagementPayloadOrganizationMy CompanyPayloadIdentifiercom.mycompany.santa.servicemanagement.1161A7ED-2E7B-4744-B933-D3B9F58A1AAEPayloadDisplayNameBackground AppsPayloadDescriptionAllows Santa background tasks without notificationsPayloadVersion1RulesRuleTypeTeamIdentifierRuleValueZMCG7MLDV9
```
---
## Profiles: Santa Configuration
Santa has _many_ configuration options controlling its behavior. The
configuration is expected to be deployed as a macOS [configuration
profile](https://developer.apple.com/business/documentation/Configuration-Profile-Reference.pdf)
by an MDM.
## Generating the profile
As Santa's profile is not part of macOS, there is no built-in support in any
MDM and you will instead need to deploy the configuration as a "Custom Profile".
The full set of configuration options is detailed on the
[Configuration: Keys](/configuration/keys) page and you can generate a profile
using the [Configuration: Generator](/configuration/generator) page.
Once you have the completed profile, you can upload or paste it into your MDM's
configuration page for deployment. The details of how to do this differ between
MDM vendors so you may need to refer to your MDM documentation for assistance.
## Example profile
Below is an example configuration profile that includes a _subset_ of the keys
available.
```xml showLineNumbers title="santa-configuration.mobileconfig"
PayloadContentClientMode1EnableSilentModeEventDetailTextOpen sync serverEventDetailURLhttps://sync-server-hostname/blockables/%file_sha%FileChangesRegex^/(?!(?:private/tmp|Library/(?:Caches|Managed Installs/Logs|(?:Managed )?Preferences))/)MachineIDKeyMachineUUIDMachineIDPlist/Library/Preferences/com.company.machine-mapping.plistMachineOwnerKeyOwnerMachineOwnerPlist/Library/Preferences/com.company.machine-mapping.plistModeNotificationLockdownEntering Lockdown modeModeNotificationMonitorEntering Monitor mode<br/>Please be careful!MoreInfoURLhttps://sync-server-hostname/moreinfoStaticRulesidentifierZMCG7MLDV9policyALLOWLISTrule_typeTEAMIDidentifierb7c1e3fd640c5f211c89b02c2c6122f78ce322aa5c56eb0bb54bc422a8f8b670policyBLOCKLISTrule_typeBINARYSyncBaseURLhttps://sync-server-hostname/api/santa/PayloadDisplayNameSanta ConfigurationPayloadIdentifiercom.mycompany.santa.359E3C7D-396F-4C45-99E7-F429620B9B21PayloadTypecom.northpolesec.santaPayloadVersion1PayloadDescriptionManages Santa's configurationPayloadDisplayNameSanta: ConfigurationPayloadIdentifiercom.mycompany.santaPayloadOrganizationMy CompanyPayloadRemovalDisallowedPayloadScopeSystemPayloadTypeConfigurationPayloadUUIDAFA02DE3-ACA6-49C4-9980-A3664E22E446PayloadVersion1
```
---
## Profiles: Network Extension
Santa includes an optional network [system
extension](https://developer.apple.com/documentation/systemextensions) that can
monitor and control network traffic. It provides two capabilities: a content
filter for monitoring network flows and a DNS proxy for intercepting DNS queries.
:::info
The network extension requires a [Workshop](https://northpole.security/) subscription
and will not activate without one.
:::
Like the endpoint security system extension, loading the network extension
requires approval. For organizations deploying Santa, this step can be automated
by sending an appropriate profile via an MDM.
Enabling the network extension requires two separate payloads: a
[Web Content Filter](https://developer.apple.com/documentation/devicemanagement/webcontentfilter)
payload for the content filter provider and a
[DNS Proxy](https://developer.apple.com/documentation/devicemanagement/dnsproxy)
payload for the DNS proxy provider.
:::warning
You must also update your [system extension profile](profile-system-extension.md)
to allow the network extension. Without this, macOS will not permit the extension
to load without manual user intervention.
:::
For installation and verification steps, see the
[Network Extension](network-extension.md) page.
## Generating the profile
The process for adding these payloads to your machines will differ depending on
which MDM you are using. Many MDMs have specific support for these kinds of
profiles. In that case, you will need the following information:
### Content Filter
- Filter Type: `Plugin`
- Plugin Bundle ID: `com.northpolesec.santa`
- Filter Data Provider Bundle Identifier: `com.northpolesec.santa.netd`
- Filter Data Provider Designated Requirement: `identifier "com.northpolesec.santa.netd" and anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] and certificate leaf[field.1.2.840.113635.100.6.1.13] and certificate leaf[subject.OU] = "ZMCG7MLDV9"`
- Filter Sockets: `true`
- Filter Packets: `false`
### DNS Proxy
- App Bundle Identifier: `com.northpolesec.santa`
- Provider Bundle Identifier: `com.northpolesec.santa.netd`
## Example Profile
If your MDM doesn't have an option to add Content Filter or DNS Proxy profiles
but does have the option for deploying custom profiles, you can use the following
example as a template.
```xml showLineNumbers title="santa-network-extension.mobileconfig"
PayloadContentPayloadTypecom.apple.webcontent-filterPayloadIdentifiercom.northpolesec.santa.content-filterPayloadUUIDA1B2C3D4-5555-6666-7777-888899990000PayloadVersion1PayloadDisplayNameSanta Content FilterUserDefinedNameSanta Content FilterFilterTypePluginPluginBundleIDcom.northpolesec.santaFilterDataProviderBundleIdentifiercom.northpolesec.santa.netdFilterDataProviderDesignatedRequirementidentifier "com.northpolesec.santa.netd" and anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] and certificate leaf[field.1.2.840.113635.100.6.1.13] and certificate leaf[subject.OU] = "ZMCG7MLDV9"FilterSocketsFilterPacketsPayloadTypecom.apple.dnsProxy.managedPayloadIdentifiercom.northpolesec.santa.dns-proxyPayloadUUIDA1B2C3D4-1111-2222-3333-444455556666PayloadVersion1PayloadDisplayNameSanta DNS ProxyAppBundleIdentifiercom.northpolesec.santaProviderBundleIdentifiercom.northpolesec.santa.netdPayloadDisplayNameSanta Network ExtensionPayloadIdentifiercom.northpolesec.santa.netd.profilePayloadUUIDA1B2C3D4-AAAA-BBBB-CCCC-DDDDEEEEFFFFPayloadTypeConfigurationPayloadVersion1PayloadScopeSystemPayloadDescriptionEnables the Santa network content filter and DNS proxy extensions.
```
---
## Profiles: Notifications
Santa can present native macOS notifications to users when it switches between
modes or when certain sync events happen. As these notifications go through the
native macOS notification system it is possible to manage how they are presented
using a profile.
:::note
These notifications are **not** related to the dialogs presented to users when
an action has been blocked, such as an application being prevented from
executing.
:::
## Generating the profile
The process for adding a "Notifications" profile to your machines will differ
depending on which MDM you are using. Many MDMs have specific support for this
kind of profile, usually labelled as a "Notifications" or "Notifications
Settings" profile.
You will need the following information to configure this profile:
- Bundle Identifier: `com.northpolesec.santa`
- Notifications Enabled: True
- Show In Notification Center: True
- Show In Lock Screen: True
- Alert Type: Temporary
- Badges Enabled: True
- Sounds Enabled: False
- Critical Alert Enabled: True
## Example profile
If your MDM doesn't have an option to add a Notifications profile but does have
the option for deploying custom profiles, you can use the following example as a
template.
```xml showLineNumbers title="santa-notifications.mobileconfig"
PayloadContentNotificationSettingsAlertType1BadgesEnabledBundleIdentifiercom.northpolesec.santaCriticalAlertEnabledNotificationsEnabledShowInLockScreenShowInNotificationCenterSoundsEnabledPayloadDisplayNameNotifications PayloadPayloadIdentifiercom.northpolesec.santa.notificationsettings.F1817DA0-0044-43DD-9540-36EBC60FDA8FPayloadOrganizationPayloadTypecom.apple.notificationsettingsPayloadUUID510236AE-D7F8-4131-A4CA-5CC930C51866PayloadVersion1PayloadDescriptionConfigures your Mac to automatically enable Notifications settings for SantaPayloadDisplayNameSanta: Notifications settingsPayloadEnabledPayloadIdentifiercom.mycompany.santa.notificationsettings.069CA123-6129-46A5-8FD1-49322E5A5755PayloadOrganizationPayloadRemovalDisallowedPayloadScopeSystemPayloadTypeConfigurationPayloadUUID069CA123-6129-46A5-8FD1-49322E5A5755PayloadVersion1
```
---
## Profiles: System Extension
One of the primary components of Santa is a [system
extension](https://developer.apple.com/documentation/systemextensions) that
receives callbacks from macOS when certain events occur and when appropriate
block those events from proceeding. Due to the high level of privilege this
grants, it is necessary to approve the loading of system extensions.
On a single user machine, allowing a system extension to load requires a trip to
the "Login Items & Extensions" pane in System Settings. However, for
organizations deploying Santa to all of their machines, this step can be skipped
by first sending an appropriate profile to the machine via an MDM.
## Generating the profile
The process for adding a System Extension profile to your machines will differ
depending on which MDM you are using. Many MDMs have specific support for this
kind of profile. In that case, you will need the following information:
- Team Identifier: `ZMCG7MLDV9`
* Allowed extension types: "Endpoint Security Extensions" or `EndpointSecurityExtension`.
- Allowed extensions: `com.northpolesec.santa.daemon`
:::tip
If your MDM requires you to pick between "Allow system extension types" or
"Allow specific system extensions", it is better to choose "Allow specific
system extensions".
:::
Your MDM _may_ also have options to prevent removal of the system extension,
either by itself or by a user (`NonRemovableSystemExtensions` or
`NonRemovableFromUISystemExtensions` keys). If these are available you should
strongly consider enabling them; they make it much more difficult for both users
and malicious scripts from bypassing Santa. If you decide at some later point to
uninstall Santa, you will need to remove the system extension profile before
attempting to uninstall.
:::info Network Extension
Enterprise deployments that include Santa's [network
extension](profile-network-extension.md) should also allow the following in this
profile:
- Allowed extension types: `NetworkExtension`
- Allowed extensions: `com.northpolesec.santa.netd`
The highlighted lines in the example below include the network extension. These
lines can be safely removed if you are not deploying the network extension.
:::
## Example Profile
If your MDM doesn't have an option to add a System Extension profile but does
have the option for deploying custom profiles, you can use the following
example as a template.
```xml showLineNumbers title="santa-system-extension.mobileconfig"
PayloadUUIDCAA3F5F6-4519-410D-960B-FDC323FA08E2PayloadTypeConfigurationPayloadOrganizationMy CompanyPayloadIdentifiercom.mycompany.santa.sysx-policy.CAA3F5F6-4519-410D-960B-FDC323FA08E2PayloadDisplayNameSanta: System ExtensionPayloadDescriptionAutomatically enable Santa's EndpointSecurityExtensionPayloadVersion1PayloadEnabledPayloadRemovalDisallowedPayloadScopeSystemPayloadContentPayloadUUID67EF74B6-F4FB-49FC-A086-5DE3E61B838APayloadTypecom.apple.system-extension-policyPayloadOrganizationMy CompanyPayloadIdentifiercom.mycompany.santa.sysx-policy.67EF74B6-F4FB-49FC-A086-5DE3E61B838APayloadDisplayNameSysxPayloadDescriptionAllow Santa's system extension and prevent removal.PayloadVersion1PayloadEnabledAllowedSystemExtensionsZMCG7MLDV9com.northpolesec.santa.daemoncom.northpolesec.santa.netdAllowedSystemExtensionTypesZMCG7MLDV9EndpointSecurityExtensionNetworkExtensionNonRemovableSystemExtensionsZMCG7MLDV9com.northpolesec.santa.daemoncom.northpolesec.santa.netd
```
---
## Profiles: TCC
macOS requires apps like Santa have "Full Disk Access" permissions in order to
perform authorization decisions and Santa cannot start until until this
permission is granted. On macOS, this access is controlled by a system called
[Transparency, Consent, and Control
(TCC)](https://support.apple.com/guide/security/controlling-app-access-to-files-secddd1d86a6/web),
which limits access to files and devices to only those applications you have
explicitly approved.
Users can manually grant this permission to applications in System Settings, but
organizations deploying Santa and utilizing an MDM can instead install a
configuration profile that grants this permission.
## Generating the profile
The process for adding a TCC profile to your machines will differ depending on
which MDM you are using. Many MDMs have specific support for this kind of
profile, usually labelled as a "Privacy Configuration Profile" or similar. You
will need the following information to configure this profile:
#### App/Process #1:
- Identifier type: "Bundle ID"
- Identifier: `com.northpolesec.santa.daemon`
- Code Requirement:
```
identifier "com.northpolesec.santa.daemon" and anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = ZMCG7MLDV9
```
- Statically validate this requirement: False
- Permission or Service: `SystemPolicyAllFiles` or `Full-disk Access`
- Access: Allow
#### App/Process #2 (Network Extension):
:::info Network Extension
This entry is only required if you are deploying the [network
extension](network-extension.md). It can be safely omitted otherwise.
:::
- Identifier type: "Bundle ID"
- Identifier: `com.northpolesec.santa.netd`
- Code Requirement:
```
identifier "com.northpolesec.santa.netd" and anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = ZMCG7MLDV9
```
- Statically validate this requirement: False
- Permission or Service: `SystemPolicyAllFiles` or `Full-disk Access`
- Access: Allow
#### App/Process #3:
- Identifier type: "Bundle ID"
- Identifier: `com.northpolesec.santa.bundleservice`
- Code Requirement:
```
identifier "com.northpolesec.santa.bundleservice" and anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = ZMCG7MLDV9
```
- Statically validate this requirement: False
- Permission or Service: `SystemPolicyAllFiles` or `Full-disk Access`
- Access: Allow
## Example profile
If your MDM doesn't have an option to add a TCC profile but does have the option
for deploying custom profiles, you can use the following example as a template.
```xml showLineNumbers title="santa-tcc.mobileconfig"
PayloadUUID9622A065-8AA4-4294-BDA3-71AA5C15BD93PayloadTypeConfigurationPayloadOrganizationMy CompanyPayloadIdentifiercom.mycompany.santa.tcc-policy.9622A065-8AA4-4294-BDA3-71AA5C15BD93PayloadDisplayNameSanta: TCCPayloadDescriptionGrant Santa full-disk accessPayloadVersion1PayloadEnabledPayloadRemovalDisallowedPayloadScopeSystemPayloadContentPayloadUUID8339162A-75E7-4E07-91DC-45DC939A4764PayloadTypecom.apple.TCC.configuration-profile-policyPayloadOrganizationMy CompanyPayloadIdentifiercom.mycompany.santa.tcc-policy.8339162A-75E7-4E07-91DC-45DC939A4764PayloadDisplayNameTCCPayloadDescriptionAllows full-disk access for SantaPayloadVersion1ServicesSystemPolicyAllFilesAllowedCodeRequirementidentifier "com.northpolesec.santa.daemon" and anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = ZMCG7MLDV9CommentIdentifiercom.northpolesec.santa.daemonIdentifierTypebundleIDStaticCodeAllowedCodeRequirementidentifier "com.northpolesec.santa.netd" and anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = ZMCG7MLDV9CommentNetwork extension - remove if not deploying santanetdIdentifiercom.northpolesec.santa.netdIdentifierTypebundleIDStaticCodeAllowedCodeRequirementidentifier "com.northpolesec.santa.bundleservice" and anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = ZMCG7MLDV9CommentIdentifiercom.northpolesec.santa.bundleserviceIdentifierTypebundleIDStaticCode
```
---
## Troubleshooting
This page outlines common troubleshooting steps for confirming proper Santa
daemon operation and steps to diagnose and correct common issues.
## Confirming Proper Santa Daemon Operation
The best way to start diagnosing the Santa daemon is by running:
```sh
/usr/local/bin/santactl status
```
If the daemon is up and running, you should see [normal status output](./install-package.md#verification).
However, if you see a message like "`An error occurred communicating with the
Santa daemon...`", then use the following tips to diagnose the issue.
## Run the doctor command
The doctor command checks Santa and its configuration for potential problems.
```sh
sudo santactl doctor
```
## Enabling Full Disk Access
The Santa daemon is required by the system to have "Full Disk Access" enabled
in order to function. On recent macOS versions, you can ensure this is enabled
using System Settings:
1. Open System Settings from the Apple menu
1. In the left pane, click on "Privacy & Security"
1. In the right pane, click on "Full Disk Access"
1. Ensure that `com.northpolesec.santa.daemon` is selected
If "Full Disk Access" wasn't enabled, re-check `santactl status` to see if the
issue is now resolved. Note that it may take up to 15 seconds for the daemon
to become active if no other issues are present.
## Enabling the System Extension
To confirm the Santa system extension is properly loaded, check the
output of the following command:
```sh
/usr/bin/systemextensionsctl list com.apple.system_extension.endpoint_security
```
Confirm that a line item exists for `com.northpolesec.santa.daemon` with the
expected version and the state is `activated enabled`.
If the extension is in the `activated waiting for the user` state, it must
first be approved to run using System Settings:
1. Open System Settings from the Apple menu.
1. In the left pane, click on "General"
1. In the right pane, click on "Login Items & Extensions"
1. Scroll to "Endpoint Security Extensions" and click the info button
1. Ensure that "Santa" is toggled on.
If Santa wasn't enabled, re-check `systemextensionsctl list`. If it's still
not in the `activated enabled` state, try forcing the extension to load:
```sh
/Applications/Santa.app/Contents/MacOS/Santa --load-system-extension
```
After loading, re-check the output of `systemextensionsctl list`. If issues
persist, reinstall Santa.
## Checking Santa Daemon Logs
The Santa daemon emits warning and error messages for encountered issues. If
it fails to start, check the logs for the cause. Daemon logs can be viewed
with the following command:
```sh
/usr/bin/log stream --level debug --predicate 'sender == "com.northpolesec.santa.daemon"'
```
## Enterprise Deployments
Enterprise deployments are typically managed via MDM, so administrators should
follow the guide on the [Getting Started](./getting-started.md) page for
information on creating the necessary configuration profiles.
To diagnose a user device, administrators should first confirm that the MDM is
supervising the computer (via DEP or UAMDM) using the following command:
```sh
/usr/bin/profiles status -type enrollment
```
Profile payloads that require a supervision relationship cannot be applied
manually for testing. Therefore, it's crucial to ensure the MDM connection is
working as expected during mass deployments.
Additionally, confirm the system extension and TCC/PPPC profiles are present, as
described in the [Getting Started](./getting-started.md) flow.
## Verifying Expected Functionality
After confirming that Santa is running, you can verify that settings are being
applied as expected by running `santactl status`.
Additionally, reviewing Santa's [logs](#checking-santa-daemon-logs) and
[telemetry](../features/telemetry.mdx) is helpful for understanding Santa's
operation. The documentation on [binary authorization](../features/binary-authorization.md)
explains precedence and decision-making.
---
## Building
Santa uses [Bazel](https://bazel.build) for building, testing, and releaseing.
The `main` branch on GitHub is always the source-of-truth.
## Installing Bazelisk
To ensure everyone is building with the correct version of Bazel, we use
[Bazelisk](https://bazel.build/install/bazelisk), which automatically downloads
the appropriate version of Bazel when run.
If you don't already have bazel/bazelisk installed, you can use homebrew:
```shell
brew install bazelisk
```
This will add both `bazelisk` and `bazel` to your `PATH`.
## Cloning
```shell
git clone https://github.com/northpolesec/santa
cd santa
```
By default your checkout will be in the `main` branch, ready to start developing
at head. As all releases are built from tagged commits, you can check out
a specific release if you wish:
```
git checkout 2025.2
```
If you want to see which tags are available, you can run:
```
git tag --sort=createordate
```
## Building
To make using bazel easier we also have a simple Makefile which just invokes
useful bazel commands. To ensure your changes are formatted correctly and build,
you can run `make` in the root of the Santa repo:
```
make
```
## Testing
To run the full suite of Santa tests, you can run `make test`:
```
make test
```
## Installing
While working on Santa, it is useful to have a quick way to reload all Santa
components. For this we have a special BUILD rule to handle this and it is
exposed as the make command `make reload`.
However, because Santa is a system extension with special entitlements it is not
as trivial to load Santa on a machine that is not registered as a machine owned
by North Pole Security. To work around this, it is possible to reload an "adhoc"
build, but only if you disable SIP:
1. Boot into recvoery mode:
- For Intel Macs, reboot and hold down `Command + R`
- For Apple Silicon Macs, power off then press and hold the Power button
until "Loading startup options" appears. Click Options, then Continue. If
asked, select a volume to recover then click Next.
2. From the Utilities menu click Terminal.
3. Run `csrutil disable` to turn SIP off.
4. Reboot.
Now you can build and run an adhoc build:
```
bazel run //:reload --define=SANTA_BUILD_TYPE=adhoc
```
## IDE Setup
If you want to use an IDE when developing Santa it is much more useful if your
IDE understands the codebase to make suggestions, allow renaming variables and
following definitions. You can have Bazel generate a compiler commands file that
will let `clangd` understand Santa:
1. Run `make compile_commands`. This will generate a `compile_commands.json`
file in the root of the workspace.
2. [Configure your
editor](https://github.com/hedronvision/bazel-compile-commands-extractor?tab=readme-ov-file#editor-setup--for-autocomplete-based-on-compile_commandsjson)
to use the `compile_commands.json` file for autocompletion.
---
## Contributing
## Before you contribute
Before we can use your code, you must sign the [North Pole Security Individual
Contributor License Agreement](https://cla-assistant.io/northpolesec/santa)
(CLA), which you can do online. The CLA is necessary mainly because you own the
copyright to your changes even after your contribution becomes part of our
codebase, so we need your permission to use and distribute your code. We also
need to be sure of various other things—for instance that you’ll tell us if you
know that your code infringes on other people’s patents. You don’t have to sign
the CLA until after you’ve submitted your code for review and a member has
approved it, but you must do it before we can put your code into our codebase.
Before you start working on a larger contribution, you should get in touch with
us first through the [issue
tracker](https://github.com/northpolesec/santa/issues) with your idea so that we
can help out and possibly guide you. Co-ordinating large changes ahead of time
can avoid frustration later on.
## Code Reviews
All submissions - including those by project members - **require** review. We
provide feedback and comments through GitHub's normal pull request mechanism.
If you receive feedback from one of the maintainers with suggestions or
requested changes, please make the appropriate changes and _upload a new
commit_, do not force-push an amended change or rebase, as this prevents GitHub
from presenting "changes since last review".
If you receive feedback that you are uncertain about, feel free to ask for more
details, but please note that we do have limited time so it may take time for
us to respond.
## Code Style
Santa's codebase is generally written to adhere to Google's
[C++](https://google.github.io/styleguide/cppguide.html) and
[Objective-C](https://google.github.io/styleguide/objcguide.xml) style guides.
To avoid wasting time discussing the finer points of code style, we use
clang-format to enforce cohesive styling. You can run `./Testing/fix.sh` in your
workspace to automatically format your code before submitting your PR. A GitHub
action workflow will present an error if your code does not match the expected
style.
---
## Version Support Policies
This document describes North Pole Security's policies on versioning as it
applies to Santa.
### Santa Version
When responding to help requests (in GitHub issues, MacAdmins Slack, etc.) we
will endeavour to support any version that is under 1 year old but we reserve
the right to request updating to the latest version.
### macOS Version
Santa will always support the latest 3 major releases of macOS.
When a new major version of macOS is released we will temporarily support up
to 4 major versions of macOS, for a period of no less than 3 months from the
date of release.
Features that require a new version of macOS may be included in Santa and
disabled on older OS's. Such features will be called out as such.
| OS Version | Supported | Comment |
| :----------------- | :-------: | :----------------- |
| macOS 14 (Sonoma) | ✅ | |
| macOS 15 (Sequoia) | ✅ | |
| macOS 26 (Tahoe) | ✅ | Since 2025.7 |
---
## Binary Authorization
Binary authorization, also known as binary allowlisting (and formerly, binary
whitelisting) is a feature that lets Santa control which binaries are run on
the same machine. This is a powerful control for both security and policy
enforcement.


With Santa running, any time a binary is executed on the machine, Santa will
decide whether the binary is allowed to be executed.
- If the execution is allowed, everything will proceed as normal and Santa
will cache its decision so that subsequent executions can avoid repetitive
processing and execute faster.
- If the execution is denied, Santa optionally presents a GUI notification over
the top of any other windows detailing what was blocked.
Santa supports multiple mechanisms for controlling which executables are allowed
to run, with as little friction as possible.
## Rules
The primary mechanism for deciding what is able to run is **Rules**. Rules can
be synchronized from a server, configured statically in a profile, or managed
locally with `santactl`.
### Rule Types
Santa supports several different rule types and follows a strict evaluation
order when determining which rule to enforce for a given execution. The
following diagram shows Santa's rule precedence:
```mermaid
flowchart TD
Start(["Execution Attempt"]) --> RuleCDHash("Rule: **CDHash**")
RuleCDHash --> RuleBinary("Rule: **BINARY**")
RuleBinary --> RuleSigningID("Rule: **SIGNINGID**")
RuleSigningID --> RuleCertificate("Rule: **CERTIFICATE**")
RuleCertificate --> RuleTeamID("Rule: **TEAMID**")
RuleTeamID --> Scope("**Scope**")
Scope --> ClientMode("**Client Mode**")
ClientMode --> End(["Decision"])
click RuleCDHash "#cdhash"
click RuleBinary "#binary"
click RuleSigningID "#signingid"
click RuleCertificate "#certificate"
click RuleTeamID "#teamid"
click Scope "#scope"
click ClientMode "#client-mode"
```
#### CDHash
Value: `CDHASH`
CDHash rules use a binary’s signed code directory hash as an identifier. This is
the most specific rule in Santa. The code directory hash identifies a specific
version of a program, similar to a file hash. Note that the operating system
evaluates the CDHash lazily, only verifying pages of code when they’re mapped
in. This means that it is possible for a file hash to change but a binary could
still execute as long as modified pages are never mapped in.
Santa only considers CDHash rules for processes that run under Apple's [Hardened
Runtime](https://developer.apple.com/documentation/security/hardened-runtime),
to ensure that a process will be killed if the CDHash was tampered with
(assuming the system has SIP enabled).
#### Binary
Value: `BINARY`
Binary rules use the SHA-256 hash of the entire binary file as an identifier.
This means that if the binary file is tampered with in any way then the rule
will not match.
#### SigningID
Value: `SIGNINGID`
Signing IDs are arbitrary identifiers under developer control that are given to
a binary at signing time. Typically, these use reverse domain name notation and
include the name of the binary (e.g. `com.google.Chrome`).
Because the signing IDs are arbitrary, the Santa rule identifier must be
prefixed with the Team ID associated with the Apple developer certificate used
to sign the application. For example, a signing ID rule for Google Chrome would
be: `EQHXZ8M8AV:com.google.Chrome`. For platform binaries (i.e. those binaries
shipped by Apple with the OS) which do not have a Team ID, the string `platform`
must be used (e.g. `platform:com.apple.curl`). The `santactl fileinfo` command
can be used to help find this information:
```shell
» santactl fileinfo /Applications/Santa.app
Path : /Applications/Santa.app/Contents/MacOS/Santa
SHA-256 : 66acf5c808ddb86c10137b5ae4c72cd14985ed2f90e5850d8e26ab962cb93c70
SHA-1 : 259f6b0ffc9cccc069eab2aee1496f5a12072ee7
Bundle Name : Santa
Bundle Version : 2025.3.97
Bundle Version Str : 2025.3
Team ID : ZMCG7MLDV9
# highlight-next-line
Signing ID : ZMCG7MLDV9:com.northpolesec.santa
CDHash : ea7c2330699c760b2d6c2c3e703fde01ca54e9b4
Type : Executable (arm64, x86_64)
Code-signed : Yes
Rule : Allowed (SigningID)
```
:::note
`SIGNINGID` rules only apply to applications signed with a production certificate.
To target code signed with a development certificate, you can use:
- A [`CDHASH`](#cdhash) or [`BINARY`](#binary) rule to target a specific executable
- A [`CERTIFICATE`](#certificate) rule to target a broader set of applications
:::
#### Certificate
Value: `CERTIFICATE`
Certificate rules are formed from the SHA-256 fingerprint of an X.509 leaf
signing certificate. This is a powerful rule type that has a much broader reach
than an individual binary rule. A signing certificate can sign any number of
binaries. Allowing or blocking just a few key signing certificates can cover the
bulk of an average user’s binaries. The leaf signing certificate is the only
part of the chain that is evaluated. Though the whole chain is available for
viewing.
Santa does not evaluate the Valid From or Valid Until fields, nor does it check
the Certificate Revocation List (CRL) or the Online Certificate Status Protocol
(OCSP) for revoked certificates. Adding rules for the certificate chain’s
intermediates or roots has no effect on binaries signed by a leaf. Santa
ignores the chain and is only concerned with the leaf certificate’s SHA-256
hash.
```shell
» santactl fileinfo /Applications/Santa.app
Path : /Applications/Santa.app/Contents/MacOS/Santa
SHA-256 : 66acf5c808ddb86c10137b5ae4c72cd14985ed2f90e5850d8e26ab962cb93c70
SHA-1 : 259f6b0ffc9cccc069eab2aee1496f5a12072ee7
Bundle Name : Santa
Bundle Version : 2025.3.97
Bundle Version Str : 2025.3
Team ID : ZMCG7MLDV9
Signing ID : ZMCG7MLDV9:com.northpolesec.santa
CDHash : ea7c2330699c760b2d6c2c3e703fde01ca54e9b4
Type : Executable (arm64, x86_64)
Code-signed : Yes
Rule : Allowed (SigningID)
Signing Chain:
# highlight-next-line
1. SHA-256 : 1afd16f5b920f0d3b5f841aace6e948d6190ea8b5156b02deb36572d1d082f64
SHA-1 : 42890bc8a2a8becda00d63bdf9a89a6756a0da49
Common Name : Developer ID Application: North Pole Security, Inc. (ZMCG7MLDV9)
Organization : North Pole Security, Inc.
Organizational Unit : ZMCG7MLDV9
Valid From : 2024/10/11 21:24:15 -0400
Valid Until : 2027/02/01 17:12:15 -0500
2. SHA-256 : 7afc9d01a62f03a2de9637936d4afe68090d2de18d03f29c88cfb0b1ba63587f
SHA-1 : 3b166c3b7dc4b751c9fe2afab9135641e388e186
Common Name : Developer ID Certification Authority
Organization : Apple Inc.
Organizational Unit : Apple Certification Authority
Valid From : 2012/02/01 17:12:15 -0500
Valid Until : 2027/02/01 17:12:15 -0500
3. SHA-256 : b0b1730ecbc7ff4505142c49f1295e6eda6bcaed7e2c68c5be91b5a11001f024
SHA-1 : 611e5b662c593a08ff58d14ae22452d198df6c60
Common Name : Apple Root CA
Organization : Apple Inc.
Organizational Unit : Apple Certification Authority
Valid From : 2006/04/25 17:40:36 -0400
Valid Until : 2035/02/09 16:40:36 -0500
```
#### TeamID
Value: `TEAMID`
The Apple Developer Program Team ID is a 10-character identifier issued by Apple
and tied to developer accounts/organizations. This is distinct from
Certificates, as a single developer account can and frequently will
request/rotate between multiple different signing certificates and entitlements.
This is an even more powerful rule with broader reach than individual
certificate rules and should be used with care.
:::note
`TEAMID` rules only apply to applications signed with a production certificate.
To target code signed with a development certificate, you can use:
- A [`CDHASH`](#cdhash) or [`BINARY`](#binary) rule to target a specific executable
- A [`CERTIFICATE`](#certificate) rule to target a broader set of applications
:::
```shell
» santactl fileinfo /Applications/Santa.app
Path : /Applications/Santa.app/Contents/MacOS/Santa
SHA-256 : 66acf5c808ddb86c10137b5ae4c72cd14985ed2f90e5850d8e26ab962cb93c70
SHA-1 : 259f6b0ffc9cccc069eab2aee1496f5a12072ee7
Bundle Name : Santa
Bundle Version : 2025.3.97
Bundle Version Str : 2025.3
# highlight-next-line
Team ID : ZMCG7MLDV9
Signing ID : ZMCG7MLDV9:com.northpolesec.santa
CDHash : ea7c2330699c760b2d6c2c3e703fde01ca54e9b4
Type : Executable (arm64, x86_64)
Code-signed : Yes
Rule : Allowed (SigningID)
```
### Policies
Once a rule has been found that matches a given executable, the action to take
is based on the policy attached to the rule. Santa supports several policies.
#### Allowlist
Value: `ALLOWLIST`
The binary is allowed to execute and this decision is cached such that
subsequent executions of the same binary will not be processed to increase
performance.
#### Allowlist Compiler
Value: `ALLOWLIST_COMPILER`
If Santa is configured to
[enable transitive allowlisting](https://northpole.dev/configuration/keys#EnableTransitiveRules)
then the binary is allowed to execute and any files that it writes will be
read upon closing (or renamed) to check whether they are Mach-O binaries.
When a Mach-O binary has been written by an allowed compiler, a transitive rule
will be created for it that is valid for 6 months. This rule will allow that
binary only on the machine that it was created on.
The purpose of transitive allowlisting is to allow developers to live in
Lockdown mode while still being able to do local development. Allowlisting the
final process in a build toolchain (usually a linker or the `codesign` tool)
will usually allow developers to work as normal.
:::note
While Santa tries to ensure all files created by allowlisted compilers are
scanned and transitive rules created as quickly as possible, there is a race
condition in certain scenarios that will cause execution to fail, especially if
a binary is executed _immediately_ after being created.
:::
If transitive allowlisting is _not_ enabled, the rule will be treated as if it
were a regular [Allowlist](#allowlist) rule.
#### Blocklist
Value: `BLOCKLIST`
The execution will be blocked. This will be the case even if the host is in
Monitor or Standalone mode, and it will not be possible to override.
Blocklist rules are intended to block applications that an organization deems
to be malicious or against policy. Rules can have custom messages attached to
them, which override the default message shown when Santa blocks an application.
This can be used in Blocklist rules to inform users _why_ a particular
application is blocked.
#### Silent Blocklist
Value: `SILENT_BLOCKLIST`
Silent Blocklist rules are identical to normal Blocklist rules but no
notification is shown when such a rule is triggered: both the GUI dialog and the
terminal (TTY) message are suppressed.
This rule type should be used sparingly. Blocking an application without
informing the user that it was Santa that did it can be a _very_ confusing
experience for users and lead to wasted time trying to determine the underlying
cause.
#### Silent GUI Blocklist
Value: `SILENT_GUI_BLOCKLIST`
Identical to [Silent Blocklist](#silent-blocklist) but suppresses only the GUI
dialog; the terminal (TTY) message is still shown.
#### Silent TTY Blocklist
Value: `SILENT_TTY_BLOCKLIST`
Identical to [Silent Blocklist](#silent-blocklist) but suppresses only the
terminal (TTY) message; the GUI dialog is still shown.
#### CEL {#cel}
Value: `CEL`
CEL (Common Expression Language) rules allow for more complex policies than
would normally be possible. A rule with this policy must also include a valid
[CEL expression](https://cel.dev/) which will be evaluated as part of making a
decision.
The input to the expression will be an
[santa.cel.v1.ExecutionContext](https://github.com/northpolesec/protos/blob/2a1ccb8059dccea5b4b9f9a2be77a9810cb0184d/cel/v1.proto#L42)
and the return value must either be a
[santa.cel.v1.ReturnValue](https://github.com/northpolesec/protos/blob/2a1ccb8059dccea5b4b9f9a2be77a9810cb0184d/cel/v1.proto#L20)
or a bool. If the return value is a bool, true will be treated as a
`ReturnValue.ALLOWLIST` and false will be treated as `ReturnValue.BLOCKLIST`.
The accessed fields in the `ExecutionContext` will determine whether the result
of the expression can be cached. This is very important to be aware of, as
overuse of CEL rules that prevent caching can have a negative impact on system
performance, especially for binaries that are executed frequently.
The following fields are available on the `target` object:
| Field | Type | Description |
| ----- | ---- | ----------- |
| `target.signing_id` | `string` | Signing ID of the target binary, prefixed with Team ID or `platform` (e.g. `EQHXZ8M8AV:com.google.Chrome` or `platform:com.apple.curl`) |
| `target.signing_time` | `timestamp` | Code signing timestamp (developer-provided) |
| `target.secure_signing_time` | `timestamp` | Secure code signing timestamp (from a timestamp authority) |
| `target.is_platform_binary` | `bool` | Whether the binary is signed with Apple platform certificates |
| `target.team_id` | `string` | Team ID from the binary's code signature |
The following additional fields are available in the execution context:
| Field | Type | Description |
| ----- | ---- | ----------- |
| `path` | `string` | File path of the executable |
| `args` | `list` | Command-line arguments passed to the binary |
| `envs` | `map` | Environment variables available to the process |
| `euid` | `int` | Effective user ID (0 for root, etc.) |
| `cwd` | `string` | Current working directory of the process |
| `ancestors` | `list` | Ancestor processes, ordered from the immediate parent at index `0` up to `launchd` at the end of the list. Only populated for [Workshop](https://northpole.security/) customers. Requires Santa 2026.2+ |
Each entry in `ancestors` has the following fields:
| Field | Type | Description |
| ----- | ---- | ----------- |
| `path` | `string` | File path of the ancestor's executable |
| `signing_id` | `string` | Signing ID of the ancestor, prefixed with Team ID or `platform` (e.g. `EQHXZ8M8AV:com.google.Chrome` or `platform:com.apple.bash`) |
| `team_id` | `string` | Team ID from the ancestor's code signature |
| `cdhash` | `string` | Code directory hash of the ancestor |
| `args` | `list` | Command-line arguments the ancestor was launched with. Requires Santa 2026.3+ |
:::note
Fields accessed from `target.*` are **cacheable** — their result is cached so
subsequent executions are faster. All other fields (`path`, `args`, `envs`,
`euid`, `cwd`, `ancestors`) are **not cacheable** and may impact performance
if used in rules for frequently-executed binaries.
:::
In addition to the [CEL standard library](https://github.com/google/cel-spec/blob/master/doc/langdef.md#standard-definitions)
(including `timestamp`, `duration`, and the arithmetic between them), the
following helper functions are available. They require [Workshop](https://northpole.security/):
| Function | Returns | Description |
| -------- | ------- | ----------- |
| `today()` | `timestamp` | The start of the current UTC day (`00:00:00Z`). Combine with duration arithmetic to compare against a sliding window, e.g. `target.secure_signing_time > today() - days(90)`. Any expression using `today()` is **not cacheable**, as its value changes each day. |
| `days(n)` | `duration` | A duration of `n` days (`n`×24h). Convenience for day-length windows, since the standard `duration()` only parses units up to hours (`days(90)` is equivalent to `duration('2160h')`). |
Some examples of valid CEL expressions:
```clike
// Only allow executing versions of an app signed on or after May 31st 2025.
// This expression will be cacheable.
target.signing_time >= timestamp('2025-05-31T00:00:00Z')
// Only allow apps securely signed within the last 90 days. The window slides
// automatically each day. Requires Workshop.
// This expression will NOT be cacheable.
target.secure_signing_time > today() - days(90)
// Only allow Chrome from this team, block other apps.
// Useful when attached to a TEAMID rule to allow a specific app.
// This expression will be cacheable.
target.signing_id.contains('com.google.Chrome') ? ALLOWLIST : BLOCKLIST
// Prevent using the --inspect flag.
// This expression will NOT be cacheable.
'--inspect' in args ? BLOCKLIST : ALLOWLIST
// Block all executions with DYLD_INSERT_LIBRARIES environment variable set.
// This expression will NOT be cacheable.
! has(envs.DYLD_INSERT_LIBRARIES)
// Only allow execution by non-root users. Requires Santa 2025.12+
euid != 0
// Disallow execution from inside /Library/LaunchDaemons. Requires Santa 2025.12+
cwd != '/Library/LaunchDaemons'
// Only allow platform binaries from a specific path.
// This expression will NOT be cacheable.
target.is_platform_binary && path.startsWith('/usr/bin/')
// Block executions whose immediate parent is Terminal. Requires Santa 2026.2+
// ancestors[0] is the immediate parent; the last entry is launchd.
size(ancestors) > 0 && ancestors[0].path.endsWith('/Terminal') ? BLOCKLIST : ALLOWLIST
```
### Rule Dictionary Format
When defining rules in a plist (for StaticRules or import/export), each rule
is represented as a dictionary with the following keys:
#### Keys
| Key | Type | Required | Description |
| --- | ---- | -------- | ----------- |
| `identifier` | String | Yes | The identifier for the rule. The format depends on the `rule_type` (see [Identifier Format](#identifier-format) below). |
| `policy` | String | Yes | The action to take when the rule matches. See [Supported Policies](#supported-policies). |
| `rule_type` | String | Yes | The type of rule. See [Rule Types](#rule-types) for values. |
| `custom_msg` | String | No | A custom message displayed in the block notification when this rule blocks execution. |
| `custom_url` | String | No | A custom URL the user can visit for more information when blocked. Supports the same placeholders as [`EventDetailURL`](/configuration/keys#EventDetailURL). |
| `comment` | String | No | A comment or note about the rule (for documentation purposes). |
| `cel_expr` | String | No | A CEL expression for the rule. **Required** if `policy` is `CEL`. |
:::note
Key names are case-insensitive. Values for `policy` and `rule_type` are also
case-insensitive.
:::
#### Identifier Format
The format of the `identifier` value depends on the `rule_type`:
| Rule Type | Identifier Format | Example |
| --------- | ----------------- | ------- |
| `BINARY` | SHA-256 hash (64 hex characters) | `a1b2c3d4...` (64 chars) |
| `CERTIFICATE` | SHA-256 hash (64 hex characters) | `a1b2c3d4...` (64 chars) |
| `TEAMID` | 10-character alphanumeric Team ID | `EQHXZ8M8AV` |
| `SIGNINGID` | `TeamID:SigningID` format | `EQHXZ8M8AV:com.google.Chrome` |
| `CDHASH` | Code Directory Hash (40 hex characters) | `ea7c2330699c760b2d6c2c3e703fde01ca54e9b4` |
For `SIGNINGID` rules targeting platform binaries (those shipped with macOS),
use `platform` as the Team ID prefix (e.g., `platform:com.apple.curl`).
#### Supported Policies
| Value | Description |
| ----- | ----------- |
| `ALLOWLIST` | Allow execution |
| `ALLOWLIST_COMPILER` | Allow execution and enable transitive allowlisting (if configured) |
| `BLOCKLIST` | Block execution |
| `SILENT_BLOCKLIST` | Block execution without showing any notification (GUI and TTY) |
| `SILENT_GUI_BLOCKLIST` | Block execution, suppressing only the GUI notification |
| `SILENT_TTY_BLOCKLIST` | Block execution, suppressing only the TTY notification |
| `CEL` | Evaluate a CEL expression to determine the action |
#### Example Rules
Rules are typically provided either as part of the
[`StaticRules`](/configuration/keys#StaticRules) configuration key or from a
sync server. Below are examples of individual rule dictionaries.
**Block a specific binary by SHA-256 hash:**
```xml
identifiera1b2c3d4e5f6...rule_typeBINARYpolicyBLOCKLISTcustom_msgThis application is not permitted by company policy.
```
**Allow all apps from a specific Team ID:**
```xml
identifierEQHXZ8M8AVrule_typeTEAMIDpolicyALLOWLIST
```
**Allow a specific Signing ID:**
```xml
identifierEQHXZ8M8AV:com.google.Chromerule_typeSIGNINGIDpolicyALLOWLIST
```
**CEL rule to only allow recently signed versions:**
```xml
identifierEQHXZ8M8AV:com.google.Chromerule_typeSIGNINGIDpolicyCELcel_exprtarget.signing_time >= timestamp('2025-01-01T00:00:00Z')
```
When using `StaticRules`, these dictionaries are placed in an array under the
`StaticRules` key in a configuration profile. When received from a sync server,
the same structure is used but in JSON format.
## Rule Layering
Since Santa is a first match system, there are some interesting ways you can
layer rules to achieve different policies.
For example if you want to allow all applications from a publisher (e.g. the
Acme software company) you might start with an allow rule for the TeamID
(ABCDEF1234) to allow all applications from that publisher.
However if you then need to prevent a specific cloud-storage application
written by the same provider, you can then use a higher precedence SigningID
rule to block that company’s cloud storage product.
Using `santactl` this would look like the following:
```
santactl rule --allow --teamid --identifier ABCDEF1234
santactl rule --block \
--signingid \
--identifier ABCDEF1234:com.acme-example.cloud-storage
```
You could also do the inverse and block everything by a publisher but allow a
specific application by having a TeamID block rule and a SigningID allow
rule.
For example if you instead wanted to block everything from the Acme company
except for the company's cloud storage product you'd make a TeamID block rule
for `ABCDEF1234` and a SigningID allow rule for the specific cloud storage
product.
Using `santactl` this would look like the following:
```
santactl rule --block --teamid --identifier ABCDEF1234
santactl rule --allow \
--signingid \
--identifier ABCDEF1234:com.acme-example.cloud-storage
```
## Scope
In addition to rules, Santa can allow or block based on scopes. Currently, only
a few scopes are implemented. Scopes are evaluated after rules, with block
evaluation preceding allow.
| Scope | Allow/Block | Configurable | Description |
| ------------------------ | ----------- | ------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| Blocked Path Regex | Block | [Yes](/configuration/keys#BlockedPathRegex) | A regex which the binary path is executed from is matched against. If the path matches the regex, the execution is blocked. |
| Bad Signature Protection | Block | [Yes](/configuration/keys#EnableBadSignatureProtection) | If enabled, a binary that is executed with a bad signing chain will be blocked. |
| Allowed Path Regex | Allow | [Yes](/configuration/keys#AllowedPathRegex) | A regex which the binary path is executed from is matched against. If the path matches the regex, the execution is allowed. |
| Not a Mach-O | Allow | No | Files which are not Mach-O binaries are ignored. |
:::note[A note about scripts]
We understand that the ability to manage the execution of "scripts" is desirable
but unfortunately this is not currently feasible to implement:
1. In the event that a script is executed directly (e.g. `./foo.sh`) it is
possible to implement authorization of these scripts. However, doing so would
require Santa to disable a layer of caching because otherwise any script that
uses an interpreter that has already been authorized to run would bypass the
authorization step. This would harm performance, quite significantly.
2. It would be very trivial to bypass the control above, for example by passing
the name of the script directly to the interpreter (e.g. `/bin/sh foo.sh`).
Protecting against this would require Santa to parse all of the command-line
arguments passed to an interpreter and there are many possible interpreters.
3. Further to the above, many interpreters support passing commands directly
(e.g. `/bin/bash -c`) or executing a script passed on standard input (e.g.
`echo foo.sh | /bin/bash`).
:::
:::danger[Warning: `AllowedPathRegex` and `BlockedPathRegex`]
While there are legitimate use-cases for using `AllowedPathRegex` and
`BlockedPathRegex`, we **strongly** discourage their use because they create an
extremely simple bypass of Santa's protection.
It's also important to understand that a binary that is executed from a path
covered by an `AllowedPathRegex` will be cached, such that if it is later moved
into a path that is not covered by the regex, it will still be allowed to
execute.
:::
## Client Mode
If Santa hasn't made a decision based on existing Rules or due to a scope, the
action that is taken depends on what mode Santa is running in. In
event/telemetry output this is the `UNKNOWN` case:
- Monitor: All unknown executions are allowed.
- Lockdown: All unknown executions are blocked.
- Standalone: All unknown executions are held until the user approves them,
either by using TouchID or entering their password. If they approve the
execution the execution is allowed to continue (without requiring
re-execution) and a local SigningID or SHA-256 rule is automatically created.
---
## File-Access Authorization (3)
File Access Authorization is a feature that lets Santa control which processes
are allowed access to read/write files. This can be used to monitor and log
access or even block access altogether.


## Use-cases
There are many possible use-cases for File-Access Authorization, here are a few
examples to get you started:
- Restricting read access to credentials files or API keys to specific
processes.
- Restricting read access to browser cookies only to browser processes.
- Restricting write access to important configuration files (sudoers, PAM,
sshd_config, etc.) to company-installed management tools.
- Restrict read access for a risky process to a specific set of paths.
## Policy Configuration
FAA policies are defined using a plist configuration, either in a [separate
file](/configuration/keys#FileAccessPolicyPlist) or
[in-line](/configuration/keys#FileAccessPolicy) with the rest of the Santa
configuration.
If the policy is specified in a separate file, Santa will periodically re-read
this file. By default this will occur every 10 minutes but the interval can be
[overridden](/configuration/keys#FileAccessPolicyUpdateIntervalSec).
The full keys available in the policy file are [documented
here](/configuration/faa.md)
### Basic Policy Structure
```xml
Versionv0.1EventDetailURLhttps://my-server/faa/%hostname%/%rule_name%/%file_identifier%WatchItemsUserFooPathsPath/Users/*/tmp/fooIsPrefixOptionsAllowReadAccessAuditOnlyRuleTypePathsWithAllowedProcessesEventDetailTextOnly some files can access the important file foo!ProcessesPlatformBinarySigningIDcom.apple.lsTeamIDEQHXZ8M8AVSigningIDcom.google.Chrome.helperTeamIDBQR82RBBHLBinaryPath/usr/local/bin/my_foo_writerTeamIDABCDEF1234
```
The top-level policy includes a version, some [GUI
configuration](/configuration/faa.md) and then a dictionary of individual
rules under the `WatchItems` key.
The key for each entry in the `WatchItems` dictionary is a name for that rule,
which will be used in logs and in the block UI.
:::info
Rule names (the `WatchItems` dictionary keys) must be 1-64 characters long and
match the regular expression `^[A-Za-z0-9._:-]+$`, containing only letters,
digits, periods, colons, hyphens, and underscores. For example, `ChromeCookies`,
`my_rule_1`, and `my-rule.v2` are valid, but `My Rule` and `rule=1` are not.
Invalid names will be rejected and an error will be logged.
:::
The rule then contains `Paths`, `Processes` and `Options` fields.
### Path Patterns
Paths can be specified using various patterns:
- Exact paths: `/etc/sudoers`
- Wildcards: `/Users/*/Documents/*`
:::important
If a configuration contains multiple rules with duplicate configured paths, only
one rule will be applied to the path. Which rule will be applied is undefined.
You should take care when crafting policies not to define rules with duplicate
paths.
:::
#### Globs
When an operation occurs on a path that matches multiple configured path
globs or prefixes, the rule that contains the "most specific" or longest match
is applied.
Path globs represent a point-in-time; globs are expanded when a configuration is
applied to generate the set of monitored paths and periodically re-evaluated.
This is not a _live_ representation of the filesystem. For instance, if a new
file or directory is added that would match a glob after the configuration is
already active, it would not immediately be monitored.
Within the main Santa configuration, the
[FileAccessPolicyUpdateIntervalSec](/configuration/keys.mdx#FileAccessPolicyUpdateIntervalSec)
key controls how often changes to the configuration are applied as well as how
often to re-evaluate path globs. This has a minimum value of 15 seconds.
The `BinaryPath` key does **not** support glob patterns (`*`).
Glob pattern support is provided by the libc
[`glob(3)`](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/glob.3.html)
function. Extended glob patterns, such as globstar (`**`), are not supported.
#### Prefix and Glob Evaluation
Combining path globs and the `IsPrefix` key in a configuration gives greater
control over the paths that should be matched.
A glob (`*`) will only ever match files/directories within a given path, it will
not recurse inside. Rules with `IsPrefix` set to true **will** match files
nested inside directories.
#### Path Resolution
All configured paths are case-sensitive (both paths specfied in the `Path` and
`BinaryPath` keys). The case must match the case of the path as it is stored on
the filesystem.
Due to system limitations, it is not feasible for Santa to know all of the links
for a given path. To help mitigate bypasses of this features, Santa will not
allow the creation of hard links for monitored paths. If hard links previously
existed for monitored paths, Santa cannot guarantee that access to watched
resources via these other links will be monitored.
Configured path globs must refer to resolved paths only. It is not supported to
monitor access on symbolic links. This is important as some common paths on
macOS are symbolic links (e.g. `/tmp` and `/var` are both symlinks into
`/private`)
### Process Matching
Processes can be matched using:
- Signing IDs: `com.google.Chrome.helper`
:::tip
Signing IDs are specified differently in FAA policies than in binary
authorization rules. Instead of prefixing the Signing ID with a TeamID or
`platform` you instead specify these in a separate `TeamID` or `PlatformBinary`
key.
:::
- Team IDs: `ZMCG7MLDV9`
- CDHash: `397d55ebec87943ea3c3fe6b4d4f47edc490d25e`
- Leaf Certificate Hash: `d84db96af8c2e60ac4c851a21ec460f6f84e0235beb17d24a78712b9b021ed57`
- Platform Binary: `false`
- Full paths: `/Applications/Safari.app/Contents/MacOS/Safari`
:::warning
Specifying binaries by full path is not very secure, given that binaries can
easily be moved. This should only be used as a last resort.
:::
### Data-centric vs Process-centric
FAA policies can be written to specify which processes can access a path (data-centric)
or which paths can be accessed by a process (process-centric).
As an example:
- To protect browser cookies from theft you could craft a policy that limits
access to the cookie files to only processes related to the respective
browser. This would be a **data-centric policy**.
- To protect against inadvertent uploads of company data outside, you could
craft a policy that prevents AirDrop processes from reading files in folders
that are known to contain potentially sensitive corporate data. This would
be a **process-centric policy**.
When writing the policy configuration the policy type is defined by the
`RuleType` key:
| `RuleType` | Process/Data Centric |
| --------------------------- | -------------------- |
| `PathsWithAllowedProcesses` | Data |
| `PathsWithDeniedProcesses` | Data |
| `ProcessesWithAllowedPaths` | Process |
| `ProcessesWithDeniedPaths` | Process |
## Example Policies
### Protecting Browser Cookies (Data-centric)
This example policy will protect the Chrome Cookies files across all users and
all Chrome profiles. There are three exceptions defined: One for Chrome using a
signing ID wildcard (`com.google.Chrome*`) to match Chrome itself and related
processes like the Chrome helper, and two for the macOS Spotlight feature which
accesses most things on the file system and can create unnecessary noise.
```xml
Versionv1.0WatchItemsChromeCookiesPathsPath/Users/*/Library/Application Support/Google/Chrome/*/CookiesIsPrefixOptionsAllowReadAccessAuditOnlyRuleTypePathsWithAllowedProcessesProcessesSigningIDcom.google.Chrome*TeamIDEQHXZ8M8AVSigningIDcom.apple.mdworker_sharedPlatformBinarySigningIDcom.apple.mdsPlatformBinary
```
### Restricting AirDrop Access (Process-centric)
This example policy will prevent any executions of the AirDrop process from
being able to access the defined paths.
This policy could easily be defined in a data-centric way as well, given the
small number of protected paths. However, as AirDrop is usually not opening
many files and the set of protected paths is otherwise accessed quite frequently
then specifying this policy in a process-centric way will be much more
performant.
```xml
Versionv1.0WatchItemsAirDropPathsPath/Users/*/Documents/confidential/*IsPrefixPath/Users/*/Desktop/sensitive/*IsPrefixOptionsRuleTypeProcessesWithDeniedPathsAuditOnlyProcessesSigningIDcom.apple.finder.Open-AirDropPlatformBinary
```
## Monitoring and Logging
When FAA is enabled, Santa will log all file access events that match your
policies. The logs include:
- Timestamp of the access attempt
- Process attempting the access
- File being accessed
- Action taken (allowed/denied)
- Policy that triggered the action
File access operations are evaluated against all defined rules to determine if
the operation violates any rule configuration. If a rule is matched, the
operation will be logged. Both string and protobuf logging are supported.
When the `EventLogType` configuration key is set to `syslog` or `file`, an
example log message will look like:
```
action=FILE_ACCESS|policy_version=v0.1-experimental|policy_name=UserFoo|path=/Users/local/tmp/foo/text.txt|access_type=OPEN|decision=AUDIT_ONLY|pid=12|ppid=56|process=cat|processpath=/bin/cat|uid=-2|user=nobody|gid=-1|group=nogroup|machineid=my_id
```
When the `EventLogType` configuration key is set to `protobuf`, a log is emitted
with the `FileAccess` message in the
[santa.proto](https://github.com/northpolesec/santa/blob/main/Source/common/santa.proto)
schema.
## Best Practices
1. **Start with monitoring**
Begin by creating policies with `AuditOnly` set to true so that you can
collect logs on what _would_ be blocked without inflicting pain on your
users.
2. **Use Specific Paths**
Be as specific as possible with path patterns to avoid unintended
consequences. Using wildcards is often necessary to create policies without
a huge amount of churn but use them sparingly as a large set of wild-card
policies can have a negative performance impact.
3. **Test Thoroughly**
Test policies in a controlled environment before deploying to production.
4. **Document Policies**
Maintain clear documentation of what each policy is protecting and why.
5. **Regular Review**
Periodically review and update policies as applications and security
requirements change.
---
## Removable Media (e.g. USB/SD device) Blocking
Removable Media blocking allows blocking removable media such as USB Mass Storage/SD Card storage from mounting, or
forcing devices to be remounted as read-only. This is intended to prevent
data exfiltration.


With this feature [configured](/configuration/keys#BlockUSBMount), any time
a storage device is mounted Santa will evaluate the mount properties; if the
device is _removable_, or _ejectable_, _connected by USB_, or is an _SD card_
and is **not** internal or virtual, then the mount will be processed.
If no re-mount options are configured, matching mounts will be rejected.
You can optionally [configure re-mount
flags](/configuration/keys#RemountUSBMode) to apply to
new mounts. When Santa evaluates a mount it will check the mount flags against
those configured. If they match the mount will be allowed to proceed. Otherwise,
the mount will be rejected and the device will be re-mounted using the
configured flags. This can be used to force a mount to always be read-only,
disable SUID binaries, disable execs from the mount, disable browsing, etc.
Another option that can be configured is what [action should be taken on
start](/configuration/keys#OnStartUSBOptions). By default, any devices that
are mounted when Santa starts are ignored, even if they would have been blocked.
You can instead configure Santa to unmount or remount.
---
## Sync Servers
Santa can be configured to synchronize with a central server, to control the
rules that Santa applies, the settings that apply to the host, and to upload
details about executions that have been blocked.
Using Santa with a large fleet of machines is greatly simplified with a sync
server involved. With a sync server configured, local rule management with
the `santactl rule` command is disabled.
## Protocol Overview
Santa's sync protocol is a simple HTTP protocol using [protobuf request/response
messages](https://buf.build/northpolesec/protos/docs/main:santa.sync.v1).
By default, Santa will send its request/responses in JSON form as this was
historically all that was supported. The
[SyncEnableProtoTransfer](/configuration/keys#SyncEnableProtoTransfer)
key can be used to enable binary proto transfers, which is faster to parse and
uses less bandwidth to transfer.
## Sync Flow
When syncing is configured, a process called `santasyncservice` runs in the
background and periodically triggers a sync.
A single sync is split into multiple stages, each responsible for something
different and the stages run in order:
```mermaid
flowchart LR
Preflight --> EventUpload --> RuleDownload --> Postflight
click Preflight "#preflight"
click EventUpload "#event-upload"
click RuleDownload "#rule-download"
click Postflight "#postflight"
```
- `Preflight` and `Postflight` stages are required and occur on every sync.
- `EventUpload` may be skipped if there are no events to upload.
- `RuleDownload` is required.
If any request to the server fails, or the server responds to a request with a
response other than `200 OK` then the client may attempt to repeat the request
up to 5 times. If none of these requests succeeds, or the original response
indicates that a retry is not worth attempting then the client will abandon the
sync and not move on to the next stage. If the failure occurs before the
`Postflight` request, then any settings that were received in the
`Preflight` will be reverted. If the `RuleDownload` stage had succeeded then
no reversion of rules will be done.
### Preflight
During `Preflight`, Santa sends data about the host (serial number, hostname, OS
version, model, etc.) and its Santa configuration (current rule counts) to the
server.
The server can respond with many configuration settings for the client to apply,
including the client mode, the event batch size, whether to enable transitive
rules, Removable Media (e.g. USB device) blocking configuration, etc.
The full
[request](https://buf.build/northpolesec/protos/docs/main:santa.sync.v1#santa.sync.v1.PreflightRequest)
and
[response](https://buf.build/northpolesec/protos/docs/main:santa.sync.v1#santa.sync.v1.PreflightResponse)
messages are documented at buf.build.
### Event Upload
During `EventUpload`, Santa sends data about execution events that the server
may need to know about. The primary purpose of `EventUpload` is to upload
information about executions that Santa has blocked so that a server may
possibly take action. Given this purpose, Santa will only upload events for
executions that were blocked or executions that _would_ have been blocked if
Santa is running in `MONITOR` mode.
When there are events to upload, the client will batch events based on the
`batch_size` field set in the Preflight response (or 50, if the server never
sets a batch size). If there are more events to upload than the batch size, then
the client will make multiple requests until it runs out of events to upload. If
the client has no events to upload, no EventUpload request will be made.
:::tip
Santa will only upload an event for executions when it makes an active uncached
decision. As Santa caches allowed executions aggressively, this implies that
events for executions that were allowed will be infrequent.
:::
It is possible to control which events are uploaded with the
[EnableAllEventUpload](/configuration/keys#EnableAllEventUpload)
and
[DisableUnknownEventUpload](/configuration/keys#DisableUnknownEventUpload)
configuration options.
The full
[request](https://buf.build/northpolesec/protos/docs/main:santa.sync.v1#santa.sync.v1.EventUploadRequest)
and
[response](https://buf.build/northpolesec/protos/docs/main:santa.sync.v1#santa.sync.v1.EventUploadResponse)
messages are documented at buf.build.
### Rule Download
During `RuleDownload`, Santa downloads rules from the server and stores them in
its local database ready for future execution requests.
Rules are generally expected to be applied progressively, so that the server
doesn't have to send the full set of rules on every sync. Instead, each time a
client initiates a sync, the server should send only the rules that have been
created/updated since the last time the client synced. Rules are applied in
the order they are received, so a rule of a given type and identifier will
update any existing rule.
To facilitate this progressive application, the server can include a `cursor` in
each RuleDownload response. If this string field is not empty, it signals to the
client that further RuleDownload requests are needed and the cursor is included
in the next request. The server can use this cursor to 'paginate' rules. As the
client downloads these batches of rules, it collects them in memory and then
applies them in a single transaction to the database.
:::note
Santa does not attempt to parse or understand the `cursor` field, it only checks
whether the string is empty or not and if not it makes a further request and
includes the cursor in that request. The format of this field is left up to the
sync server implementor, as long as it serializes to a string.
:::
A caveat to the progressive downloads, is that either the client or the server
can request a [_clean_
sync](https://buf.build/northpolesec/protos/docs/main:santa.sync.v1#santa.sync.v1.SyncType).
When the server tells the client during `Preflight` that it is doing a clean
sync, the client will collect all of the rules from each RuleDownload request as
normal and then apply them after deleting any existing rules. This all happens
within a transaction so the client is never left without any rules, unless the
server responds with an empty rule set.
The full
[request](https://buf.build/northpolesec/protos/docs/main:santa.sync.v1#santa.sync.v1.RuleDownloadRequest)
and
[response](https://buf.build/northpolesec/protos/docs/main:santa.sync.v1#santa.sync.v1.RuleDownloadResponse)
messages are documented at buf.build.
### Postflight
The `Postflight` stage is used by the client to inform the server that it has
successfully finished syncing.
The request indicates how many rules were received and successfully processed.
It is expected that in response to this request the server will record the last
successful sync time for this host.
The full
[request](https://buf.build/northpolesec/protos/docs/main:santa.sync.v1#santa.sync.v1.PostflightRequest)
and
[response](https://buf.build/northpolesec/protos/docs/main:santa.sync.v1#santa.sync.v1.PostflightResponse)
messages are documented at buf.build.
---
## Telemetry
Santa collects and outputs telemetry data about security events. This data is
used to provide insights into system activity, security events, and policy
enforcement decisions.
## Event Types
Santa can log various types of events based on system activity. The following
event types can be configured for logging:
:::warning
Some of these events are extremely noisy and will generate a lot of data.
`Fork`, `Exit`, and `Close`, in particular will generate a very large amount of
data, and should be used with caution.
:::
### Execution/Process
#### `Execution`
Binary execution events include detailed information about all allowed and
denied executions.
- The decision made by Santa
- The reason for the decision, which usually indicates the kind of rule that was
matched when making the decision
- The SHA-256 hash of the binary, if available
- The signing certificate SHA-256 and common name, if available
- The team ID from the code signature, if available
- The pid, pidversion and ppid of the process
- User and group IDs
- The executable path
- The arguments passed to the binary
`protobuf` and `json` logs will include far more data, including:
- The working directory
- Environment variables
- File descriptors
- Entitlements
#### `Fork`
Process fork events, emitted every time any process calls `fork()` or
`posix_spawn()`. This is often a precursor to an execution.
#### `Exit`
Process exit events, emitted every time a process exits, regardless of reason or
state.
- pid, pidversion and ppid of the process
- The uid and gid of the process
#### `CodesigningInvalidated`
This event is emitted any time a signed binary is running and its signature
became invalid during execution. This usually indicates that some part of the
binary has been modified.
- The code-signing flags of the process will be logged
### File
#### `Close`
Emitted any time a file descriptor/handle is closed *and* was modified. This
event is also emitted if a file was ever mapped writable (though a file being
mapped writable does not necessarily mean that it was actually written to).
- The path of the file
#### `Rename`
Emitted any time a file is renamed/moved.
- The original path
- The new path
#### `Unlink`
Emitted whenever a file is deleted.
- The path of the file
#### `Link`
Emitted whenever a file is hard-linked.
:::tip[Symlinks do not trigger this event]
:::
- The path of the file
- The newly linked path
#### `ExchangeData`
Emitted any time a file is updated using the
[`exchangedata(2)`](https://www.manpagez.com/man/2/exchangedata/)
function. This is a macOS-specific syscall that atomically swaps the contents
of two files that was supported on HFS+ formatted drives; it is not supported
on the modern APFS filesystem.
- The original path of the file
- The new path
#### `Clone`
Emitted whenever a file is cloned using the
[`clonefile(2)`](https://www.manpagez.com/man/2/clonefile/) system call.
- The source path
- The target path
#### `CopyFile`
Emitted whenever a file is copied using the `copyfile(2)` syscall. This is an
undocumented call with no public API exposed, so it is not generally used.
- The source path
- The target path
### Other
#### `Disk`
Emitted whenever a disk is mounted or unmounted. This event can be emitted even
if [Removable Media (e.g. USB device)](/features/removable-media-blocking) is not enabled and can be
useful to see if users are attaching external storage devices that may need to
monitored or blocked.
- The mount path
- The volume name
- The BSD device name
- The filesystem type
- The model of the device the mount is from
- The serial number of the device the mount is from
- The bus/protocol that the device is mounted from, e.g. `USB`
- The DMG path, if the mount is from a disk image.
#### `Bundle`
Emitted whenever Santa creates a bundle hash for an application bundle. This
only occurs when an application bundle is blocked, Santa is configured to synchronize
with a sync server, that sync server has previously indicated that it supports
Bundles and the GUI is presented to the user.
Bundle hashing is a potentially expensive operation, and it can be useful to
have these bundle hashes available in analysis separately from the events
uploaded to the sync server.
- The bundle path
- The bundle name
- The bundle ID
- The bundle hash
#### `Allowlist`
Emitted whenever Santa creates a local allowlist rule for a binary created by an
allowed compiler. This will only occur if Transitive Allowlisting is enabled and
the host has one or more `ALLOWLIST_COMPILER` rules.
- The pid and pidversion of the process that created the binary
- The path of the new binary
- The SHA-256 of the binary
#### `FileAccess`
Emitted whenever a File Access Authorization event occurs.
See the [File Access](/features/faa) documentation for more
details.
- The policy name and version
- The accessed path
- The access type (read, write, execute, etc.)
- The decision that was made
#### `LoginWindowSession`
Emitted whenever a user logs in, logs out, or locks/unlocks the screen locally.
- The username associated with the session
- The graphical session ID
#### `LoginLogout`
Emitted whenever a user logs in or out for a console session. This is not a very
common event.
- Whether the user is logging in or out
- The associated user
- Whether the login was successful
#### `ScreenSharing`
Emitted whenever a screen sharing session is started or ended.
When a new session is started, the event will include:
- Whether the session was successfully established
- The IP address of the connecting user
- If the user is connecting through iCloud: their Apple ID
- What kind of authentication method was used
- The authenticating user
- The local username of the session
- Whether the connection was made to an existing session
- The graphical session ID
:::note
This event is only emitted if the built-in Screen Sharing service is used.
:::
#### `OpenSSH`
Emitted whenever an incoming SSH connection is connected or disconnected.
The event will include:
- The remote IP address of the connection
- The username or UID of the user that connected
:::note
This event is only emitted if the built-in `sshd` is used.
:::
#### `Authentication`
Authentication events
#### `GatekeeperOverride` {#gatekeeper-override}
Emitted whenever a user overrides Gatekeeper for a binary.
The event will indicate:
- The binary path
- The binary's SHA-256 hash, if available
- Details about the binary's code signature, if it is signed
#### `TCCModification` {#tcc-modification}
Emitted whenever the Transparency, Consent, and Control database is modified.
This occurs when an application is granted or denied access to a protected
resource, such as the camera, microphone, or specific folders on disk.
The event will indicate:
- Whether it was a Create/Modify/Delete operation
- The TCC service being modified (e.g. `SystemPolicyDocumentsFolder`, `SystemPolicyAllFiles`, `Microphone`, `Camera`, etc.)
- An identifier for the application being granted/denied access
- The kind of application identifier (e.g. `BUNDLE_ID`, `EXECUTABLE_PATH`)
- Whether access is being granted or denied
- A reason for the change (e.g. `USER_CONSENT`, `MDM_POLICY`)
#### `XProtect` {#xprotect}
Emitted whenever XProtect detects or remediates malware.
The event will indicate:
- The XProtect signature version
- The identifier for the malware that was detected
- The path that it was detected at
- An `incident_identifier`, which can be used to link multiple malware
detected/remediated events together
- If the malware was remediated:
- The path that was remediated
- The action taken to remediate it (e.g. `path_delete`)
#### `LaunchItem`
This item is emitted whenever a LaunchAgent, LaunchDaemon, or LoginItem is
registered with the system.
The event data will indicate:
- Whether an item was added or removed
- The item type (e.g. `AGENT`, `DAEMON`, `LOGIN_ITEM`)
- Whether or not the item is _legacy_
- When this field is true, the item was registered by placing a
`launchd.plist` file in the `/Library/LaunchDaemons` or
`/Library/LaunchAgents` directories, instead of being registered using
[`SMAppService`](https://developer.apple.com/documentation/servicemanagement/smappservice?language=objc)
- The item path, if applicable
- The executable path, if applicable
## Configuration
### Event Selection
The `Telemetry` configuration key allows you to specify which events should be logged.
You can use `Everything` to log all events (this is the default):
```xml
TelemetryEverything
```
Or select specific events:
```xml
TelemetryExecutionAuthenticationFileAccess
```
Or disable logging events:
```xml
TelemetryNone
```
### Log Storage
The `EventLogType` key determines how event logs are stored:
- **file**: Writes events to a file on disk (default)
- **syslog**: Sends events to the macOS Unified Logging System
- **protobuf**: Uses a maildir-like format on disk
The format of protobuf messages is available in the [proto
schema](https://github.com/northpolesec/santa/blob/main/Source/common/santa.proto).
- **json**: Writes one JSON object per line to a file
The format of protobuf messages is available in the [proto
schema](https://github.com/northpolesec/santa/blob/main/Source/common/santa.proto).
JSON logs are created by first creating protobuf messages and then converting
to JSON. Because JSON output requires this conversion, it is a less
performant option.
- **null**: Disables event logging entirely. Consider setting the `Telemetry`
key to `none` instead, as this will save Santa from generating events only to
discard them.
### File Options
Applies when using the `file` log type.
- `EventLogPath`: Path for filelog/JSON output (default: `/var/db/santa/santa.log`)
### Protobuf-based Options
Applies when using the `protobuf` or `json` log types.
- `SpoolDirectory`: Base directory for protobuf format (default: `/var/db/santa/spool`)
- `SpoolDirectoryFileSizeThresholdKB`: Per-file size limit (default: 250KB)
- `SpoolDirectorySizeThresholdMB`: Total spool directory size limit (default: 250MB)
- `SpoolDirectoryEventMaxFlushTimeSec`: Maximum buffer time before flush (default: 15 sec)
### File Change Monitoring
- `FileChangesRegex`: Regex pattern for paths to monitor for file changes
- `FileChangesPrefixFilters`: Path prefixes to exclude from file change
monitoring. These paths will not be matched against the `FileChangesRegex`,
which can be a performance improvement for noisy paths.
### Additional Options
- `EnableMachineIDDecoration`: Adds machine ID to filelog entries
- `EntitlementsPrefixFilter`: Entitlement prefixes to exclude from execution telemetry.
Matching entitlements will be omitted from the logged event, but the execution event
itself is still logged. Entitlements are only logged when `EventLogType` is set to
`protobuf` or `json`.
- `EntitlementsTeamIDFilter`: Team IDs whose process entitlements should be excluded from
execution telemetry. Matching entitlements will be omitted from the logged event, but the
execution event itself is still logged. Entitlements are only logged when `EventLogType`
is set to `protobuf` or `json`.
## Example Configuration
Here's a complete example configuration for telemetry:
```xml
TelemetryExecutionAuthenticationFileAccessEventLogTypefilelogEventLogPath/var/log/santa/events.logFileChangesRegex^/Users/.*\.sh$FileChangesPrefixFilters/private/tmp/EnableMachineIDDecorationEntitlementsPrefixFiltercom.apple.privateEntitlementsTeamIDFilterplatform
````
This configuration:
- Logs execution, authentication, and file access events
- Writes logs to a custom file location
- Monitors shell script changes in user directories
- Excludes temporary directory changes
- Adds machine ID to log entries
- Omits private Apple entitlements and platform binary entitlements from execution events
---
## Intro
Santa is a high-performance open-source security agent for macOS that provides
binary & file-access authorization and rich system event logging.
---
## Known limitations
- Santa only blocks execution (execve and variants); it doesn’t protect against
dynamic libraries loaded with dlopen, libraries on disk that have been
replaced, or libraries loaded using `DYLD_INSERT_LIBRARIES`.
- **Scripts:** Santa is written to ignore any execution that isn’t a binary.
After weighing the administrative cost versus the benefit, we found it wasn’t
worthwhile to manage the execution of scripts. Additionally, several
applications make use of temporary scripts, and blocking these could cause
problems. We’re happy to revisit this (or at least make it an option) if it
would be useful to others.
- **Removable Media (e.g. USB Mass Storage) Blocking:** Santa’s removable media
blocking feature only stops incidental data exfiltration, it is not meant as
a hard control. It operates at the mount level. It cannot block:
- Directly writing to an unmounted, but attached device
- **Network Mount Blocking:** Santa's network mount blocking feature requires
macOS 15 or later. This feature is limited to Workshop customers.
- Metrics reported by Santa are not _currently_ in a format that is friendly to open-source solutions