Endpoint Security as a Detection Source
Endpoint Security (ES) gives an entitled client structured records about selected operations on a Mac. A detection built from ES must name the event, the fields it uses, and the client configuration that delivers it. A system supporting an event type, product subscription, and retained export are separate checks.
This module uses Apple's estrace to observe one harmless child process.
That successful capture establishes the shape of an ES record. Later
modules build a sensor, measure delivery, and test detection logic.
What the client receives
An ES client subscribes to specific event types. The operating system
delivers es_message_t records with the actor, event payload, timestamps,
and versioned fields. An authorization event asks a client for a decision
before the operation completes. A notification reports an operation
without asking the client to decide it.
A production client's useful data also depends on its entitlement, privileges, subscriptions, mute rules, processing capacity, retention, and export pipeline. A vendor's process feed may omit fields present in the underlying ES message. Inspect the product's actual schema before porting a rule from this course.
A custom client requires Apple's
Endpoint Security entitlement
and appropriate deployment. Apple's built-in estrace can follow a
child on the validation VM without root. That observation does not grant a
third-party application permission to subscribe system-wide.
Read the event catalog on the target build
106 exec iokit_open mmap mprotect open uipc_bind uipc_connect xpc_connect
The count is the number of lines printed by this tool on build 26A434,
not a promised count for every macOS version. The names are short names
accepted by eslogger; they are not the C enum constants. Read the
installed SDK header to determine which AUTH and NOTIFY forms exist.
For example, the macOS 27 SDK declares AUTH_MMAP,
NOTIFY_MMAP, AUTH_MPROTECT, NOTIFY_MPROTECT,
AUTH_IOKIT_OPEN, and NOTIFY_IOKIT_OPEN.
The presence of iokit_open is especially important for this course.
The SDK defines an IOKit-open event. Test the event, target, and client on
the build under discussion before claiming product visibility.
Capture an execution event
Run a program with no output through a child-scoped trace, then select only the fields needed for this lesson:
{"event_type":9,"path":"/usr/bin/true","signing_id":"com.apple.true","seq_num":0,"global_seq_num":1}event_type: 9 identifies the notification form of exec in the
installed header. The target path and signing identifier belong to
/usr/bin/true. The sequence values describe this trace's delivery
order; one record cannot demonstrate a drop or establish lossless
collection. The full JSON also contains process identities and
environment values, which should be minimized before sharing a capture.
The command deliberately follows its own child. It does not observe all execution on the host. Use a privileged, entitled sensor or a product feed for fleet-wide validation.
Inspect the record before choosing fields
Do not begin a rule by copying field names from another product. Ask the source what the macOS 27 record contains. The following query prints only key names, so audit-token values and environment data do not enter the course evidence:
{"top":["action","action_type","event","event_type","global_seq_num","mach_time","process","schema_version","seq_num","thread","time","version"],"process":["audit_token","cdhash","codesigning_flags","cs_validation_category","executable","group_id","is_es_client","is_platform_binary","original_ppid","parent_audit_token","ppid","responsible_audit_token","session_id","signing_id","start_time","team_id","tty"],"target":["audit_token","cdhash","codesigning_flags","cs_validation_category","executable","group_id","is_es_client","is_platform_binary","original_ppid","parent_audit_token","ppid","responsible_audit_token","session_id","signing_id","start_time","team_id","tty"]}The top-level process is the actor that caused the exec operation. The
event.exec.target object describes the new process image. Treating those
objects as interchangeable can reverse an investigation. For example, a
trusted launcher in process can execute an unfamiliar target, while an
untrusted actor can request execution of a platform binary.
Fields have different jobs:
| Field group | Detection use |
|---|---|
audit_token, start_time, session_id | Correlate identity while avoiding PID reuse |
executable.path, signing_id, team_id, cdhash | Describe the actor or target image |
parent_audit_token, responsible_audit_token, original_ppid | Reconstruct launch responsibility beyond one parent edge |
seq_num, global_seq_num | Detect possible delivery gaps within their documented scope |
version, schema_version | Select fields that exist in the received record |
Normalize the fields your own sensor exports and retain the original event for
forensic review. Do not hard-code numeric event_type values as the primary
rule interface when a stable normalized event name is available.
AUTH and NOTIFY have different contracts
An AUTH event arrives before the protected action is decided. The client must reply before the event's deadline. A NOTIFY event describes an action without a response from the client. The event name alone does not say whether the action succeeded; read the event payload and result fields relevant to that operation.
Slow clients, full queues, missed deadlines, and process restarts have different consequences. Do not reduce those conditions to "AUTH never drops" or "NOTIFY always drops silently." DE 01 measures sequence behavior and recovery with a test client, then defines what the result permits you to claim. A gap in a sequence number is evidence that records may be missing. It cannot reconstruct the missing actions.
Event families and limits
| Question | ES candidate | Additional source to consider |
|---|---|---|
| Which binary executed? | EXEC, FORK, EXIT | Shell history or application log for context |
| Which file operation occurred? | OPEN, CREATE, RENAME, UNLINK, CLOSE | Resulting file and filesystem metadata |
| Was memory mapped or reprotected? | MMAP, MPROTECT | Process memory analysis, when authorized |
| Was a Unix-domain socket used? | UIPC_BIND, UIPC_CONNECT | Daemon and XPC service inventory |
| Was a user client opened? | IOKIT_OPEN | IORegistry, driver logs, entitlement checks |
| Was an XPC connection attempted? | XPC_CONNECT | Service-side logs and request semantics |
| Was a TCP connection made? | No general ES TCP flow event | Network Extension, firewall, DNS, proxy, packet capture |
An ES event for a Unix-domain socket does not provide general TCP connection telemetry. Likewise, an XPC connection record does not reveal the meaning of every message sent over that connection. Correlate process identity, destination, time, and a second source before claiming a network or IPC technique was detected.
The event catalog changes across OS releases. The schema version in a message and the SDK's availability annotations matter when a rule moves between fleet populations. DE 01 turns those details into a version-aware sensor contract.
State the coverage claim precisely
For the command above, a defensible statement is:
On macOS 27.0.1 build 26A434, the child-scoped
estracerun delivered one exec notification for/usr/bin/true, including its path and signing identifier.
Fleet coverage, EDR subscription, queue health, and network visibility each need their own collection test.
An ES-based rule is supported by a subscribed event, an observed message, and a validated export path. The child trace demonstrates one exec notification. Later labs test delivery under load and correlate ES records with other sources.
What Comes Next
Module 0.4 uses Unified Logging as a separate source. It checks actual messages before treating a predicate as a detection signal.
Continue macOS Detection Engineering
These foundation modules are open as a preview. Full modules, lab downloads, progress tracking, and certificate workflow require active course access.
Get full access