EDRApp.app, Team ID MVMB6LCP2A), which embeds the ESensor Endpoint Security system extension as the telemetry source. ESensor emits JSON, a local forwarder LaunchDaemon batches and ships it over outbound HTTPS, and the same Hilt control plane that serves the Linux collector enriches and stores it — the only platform-specific divergence is the enrichment profile and the destination table.
This page traces a single event end to end. For the on-host architecture see the collector overview; for what is captured and the column schema see the event data model.
Pipeline at a glance
1
ESensor (Endpoint Security extension)
The ESensor system extension subscribes to Apple Endpoint Security
NOTIFY events and emits each one as a single JSON line, stamped with code-signing trust and application attribution. No kernel extension is involved — ESensor is a pure user-space System Extension running on Apple’s modern frameworks.2
Local forwarder (LaunchDaemon)
A small forwarder LaunchDaemon tails the ESensor JSON stream, batches events, and HTTP-POSTs them over outbound HTTPS to the configured Hilt ingest endpoint. If the endpoint is unreachable it spools events to disk and drains them when connectivity returns.
3
edr-collector /ingest (edge VPC)
The collector terminates the HTTPS POST at its
/ingest endpoint, validates the batch, and routes each event to a Kafka topic by event class. It lives alone in a public edge VPC so roaming Macs can reach it directly over the internet — no VPN.4
MSK Kafka (dag.endpoint.*)
The collector produces events to the core Amazon MSK cluster on the
dag.endpoint.exec, dag.endpoint.file, and dag.endpoint.net topics, which buffer the stream and decouple ingest from enrichment.5
Enrichment (ENRICH_PLATFORM=macos)
The enrichment service consumes the
dag.endpoint.* topics with the macOS profile. It resolves each event’s responsible_pid into an owning application and a per-instance session, normalizes the code-signing identity, and writes typed rows.6
ClickHouse (endpoint_events)
Enriched rows land in the purpose-built, macOS-native ClickHouse table
endpoint_events, typed by event_class / event_type, carrying the code-signing and application-attribution columns plus an attrs map for the security long tail.7
Dashboard
macOS hosts surface in the Collectors fleet with a macOS host-type badge, and their events appear across the Investigate, Networks, Files, and Users views — queryable by signing trust and owning application.
Stage 1 — ESensor emits JSON
ESensor is an Endpoint Security (ES) system extension (bundle idHilt.EDRApp.ESensor) embedded in the Hilt EDR app. It opens an ES client, subscribes to a fixed set of NOTIFY events, applies aggressive userspace filtering, and writes each surviving event as a single JSON line.
What it subscribes to. ESensor captures process, file, persistence, device, and network telemetry:
Volume reality.
file_open dominates the stream at roughly 95%+ of all events, so ESensor filters aggressively in userspace before anything is emitted. Only the security-relevant remainder is written to the JSON stream and handed to the forwarder.
The network source is the per-flow Network Extension content filter (
Hilt.EDRApp.NetFilter, with an lsof fallback), not Endpoint Security. ES has no network events; this is why network attribution arrives as net_flow rather than an ES NOTIFY type. See event data model.Trust and attribution stamped at the source
The defining property of the macOS collector is that every event carries first-class code-signing trust and application attribution — fields the Linux collector cannot express. These are resolved from the Endpoint Security process record at emit time, not bolted on later:
Because trust and application identity travel with the event, a query like “which unsigned app read
~/.ssh” is a single WHERE clause downstream.
Stage 2 — Local forwarder batches and ships over HTTPS
The forwarder is a lightweight LaunchDaemon installed alongside the Hilt EDR app. It owns the network path; ESensor itself opens no sockets.- Tails and batches. It reads ESensor’s JSON line stream, accumulates events into batches, and POSTs them to the collector’s
/ingestendpoint. - Outbound HTTPS only. The single destination is the configured Hilt ingest endpoint, reached over outbound HTTPS. There are no inbound sockets and no phone-home — the host initiates every connection.
- Roaming-friendly. Because the collector lives in a public edge VPC, the forwarder reaches it directly over the internet from wherever the Mac is. No VPN or corporate network is required.
Spool on disconnect
When the ingest endpoint is unreachable — a closed laptop, a flaky network, a captive portal — the forwarder does not drop events. It spools them to disk locally and continues accepting new events from ESensor. When connectivity returns, the spool is drained to the collector in order, so a Mac that was offline backfills its timeline rather than leaving a gap.Spooling makes the macOS collector resilient to the intermittent connectivity that is normal for laptops. The trade-off is that an event’s appearance in the dashboard reflects when the host reconnected, not necessarily when the activity occurred — the event’s own kernel timestamp remains the source of truth for ordering.
Stage 3 — edr-collector /ingest
The edr-collector is the edge ingest service. It runs alone in a public edge VPC so roaming Macs can reach it over the internet, and it is the only component the host ever talks to.- Receives the batched HTTPS POST at
/ingest, validates the payload, and acknowledges the batch so the forwarder can release it from the spool. - Routes by class. It maps each event to a Kafka topic — process events to
dag.endpoint.exec, file events todag.endpoint.file, and network flows todag.endpoint.net. - Produces to the core MSK cluster through a write-only path: the collector can publish to the
dag.endpoint.*topics but cannot read back or reach anything else in the core network.
Stage 4 — MSK Kafka (dag.endpoint.*)
Events are buffered on Amazon MSK across three topics, partitioned by event class:
Kafka decouples ingest from enrichment: the collector can keep accepting events even if enrichment is briefly behind, and enrichment can be restarted or scaled without losing the stream. The same
dag.endpoint.* topics carry the Linux collector’s endpoint stream — the platform is distinguished downstream, not by topic.
Stage 5 — Enrichment (ENRICH_PLATFORM=macos)
A dedicated, fault-isolated enrichment deployment consumes thedag.endpoint.* topics with ENRICH_PLATFORM=macos. This profile is what makes the rows macOS-native rather than Linux-shaped:
- Resolves
responsible_pid→ application + session. Apple’s ES “responsible process” is turned into the owningapplication_id/application_display_nameand a per-instancesession_id, folding helper processes back to their parent app. This is the step that lets the dashboard group activity by application instead of by raw process. - Normalizes code-signing identity. The
code_signatureverdict,signing_id,team_id, andcdhashare validated and written as first-class, typed columns. - Types the event. Each event is keyed by
event_class/event_typeso file, process, persistence, device, and network events share one table without Linux cgroup/k8s/container clutter. - Preserves the long tail. Security-relevant attributes that don’t warrant their own column (e.g.
xattrname on a quarantine strip, removable-media flags on amount) are written into anattrsmap.
Stage 6 — ClickHouse (endpoint_events)
Enriched rows are written to the purpose-built ClickHouse tableendpoint_events — the live macOS telemetry table. It is macOS-native by design:
- typed by
event_class/event_typerather than cloned from the Linux schema; - carries the code-signing identity columns (
code_signature,signing_id,team_id,cdhash) and application-attribution columns (application_id,application_display_name,responsible_pid,session_id,device_name) as first-class fields; - includes an
attrsmap for the security long tail; - omits Linux-only concepts (cgroup, container, pod, node, k8s) entirely.
device_name means no host-inventory join is needed to render a host.
Earlier macOS rows were written to a clone of the Linux schema (
dag_events_endpoint); that table is retired and is no longer written. endpoint_events is the authoritative destination. See the event data model for the full column list.Stage 7 — Dashboard views
macOS hosts and their events surface across the dashboard:- Collectors fleet — each enrolled Mac appears with a macOS host-type badge, identified by its
device_name, alongside Linux collectors in the same fleet view. - Investigate — process, file, and persistence activity, filterable by signing trust (
code_signature) and owning application (application_display_name). - Networks — outbound
net_flowactivity attributed to the responsible application and bundle id. - Files — file opens, deletes, renames, chmods, and quarantine-tamper events.
- Users — activity grouped by the acting user and session.
developer_id-but-not-platform binary that touched a sensitive path, or every app whose code_signature is unsigned_or_invalid.
What this data flow does not do
The macOS collector observes system activity at the metadata level only. The data flow explicitly does not include:- Inbound connections or a phone-home. The forwarder makes only outbound HTTPS to the configured ingest endpoint; nothing listens for inbound sockets.
- File contents, packet payloads, memory, or environment variables. Events carry metadata only — paths, identifiers, signing identity, and flow tuples — never the data a process reads or writes.
- A kernel extension. ESensor and NetFilter are user-space System Extensions; there is no kext and no
csrutil disable. The collector runs with System Integrity Protection enabled. See system requirements. - On-device response or auto-update. During early access the pipeline is telemetry-only; auto-update and on-device quarantine response are not yet available on macOS.
Status: early access. The notarized
.pkg with SIP-on install and the data flow described here are the shipping model. On-device response and agent auto-update are planned but not yet available on macOS.