WhisperDocs
Endpoint

The macOS sensor

The plane that protects a Mac does not run on macOS. The routable /128 identity, the graph verdict on every destination, per-device policy and the off-host kill-switch are network-side, so they cover a Mac today, sensor or no sensor, entitlement or no entitlement, and anyone can verify every one of those claims with stock tools. On the host, the detection engines themselves, the ransomware correlator, the process-injection correlator, the event chain and the fenced response tier, are now exercised on Apple-silicon over the bridge datapath (the exec, file and socket collectors are proven on real Apple hardware; the /dev/bpf qname tap needs root and is exercised through a scripted read seam rather than a live device; the engines are exercised in datapath tests rather than fired by a live Endpoint Security feed), fed through the real bridge datapath, reading the kernel's code-signing identity where the kernel will give it. What remains gated is one thing, and we show the proof of the gate itself: the live Endpoint Security feed needs Apple's ES entitlement plus Developer ID notarization, and macOS kills an unapproved client before it reads a single event. Approval flips it on; nothing else changes. Both halves, kept distinct, are the whole macOS story.

/128
routable identity, on a Mac today
7.53B
graph nodes scoring destinations
0
host cooperation needed to revoke
0
kernel extensions, ever
1
wire contract, byte-proven
4
engines exercised over the bridge datapath

What a Mac gets today

Start with the half that needs no entitlement, no installer and no trust in anyone's release calendar, because it is the half that decides protection. These four layers live on Whisper infrastructure, not on the endpoint, so a MacBook carries them the moment it holds an address:

i

Why we lead with this. On macOS, every endpoint vendor's on-host timeline is clocked by Apple: Endpoint Security is a restricted, Apple-approved capability, and there is no legitimate way around that queue. Our on-host bridge waits in it too, and the rest of this page states exactly where that stands. The protection plane above does not wait, because it is not an app.

Two homes for a Mac's protection. On the network, live today: the verifiable /128 identity, graph verdicts, per-device policy, and off-host response. On the Mac: the Endpoint Security bridge and DNS proxy feeding the same shared Go detection brain, the engines exercised on Apple-silicon over the bridge datapath (the exec, file and socket collectors are proven on real Apple hardware; the /dev/bpf qname tap needs root and is exercised through a scripted read seam rather than a live device; the engines are exercised in datapath tests rather than fired by a live Endpoint Security feed), the live ES feed entitlement-gated. ON THE NETWORK · LIVE FOR A MAC TODAY · KEYLESS-VERIFIABLE IDENTITY routable /128 DNSSEC · DANE · RDAP stock dig + curl check it THE GRAPH destination verdicts 7.53B nodes · 40.3B edges DoH/DoT or /128 resolver POLICY per-device · firewall metered egress + logs enforced off-host RESPONSE revoke the /128 worldwide, one call survives a lost Mac none of the four waits on an entitlement · they act on Whisper infrastructure, not on the endpoint ON THE MAC · ENTITLEMENT-GATED · DEVELOPER AND INTERNAL BUILDS TODAY ES + NETWORK EXTENSION BRIDGE Apple's own frameworks · no kernel extension exec + file + dns + memory · live feed entitlement-gated THE SAME GO BRAIN one wire contract, byte-proven against Linux engines exercised on Apple-silicon over the bridge datapath (the exec, file and socket collectors are proven on real Apple hardware; the /dev/bpf qname tap needs root and is exercised through a scripted read seam rather than a live device; the engines are exercised in datapath tests rather than fired by a live Endpoint Security feed)
The purple row is live for a Mac now and checkable keyless. The bottom row is the on-host half: real, built, contract-tested, its engines exercised on Apple-silicon over the bridge datapath (the exec, file and socket collectors are proven on real Apple hardware; the /dev/bpf qname tap needs root and is exercised through a scripted read seam rather than a live device; the engines are exercised in datapath tests rather than fired by a live Endpoint Security feed), and its live feed gated on Apple's Endpoint Security entitlement. We never round the second row up into the first.

The fleet console already reads Macs this way. The capture below is our live lab fleet, genuinely mixed, with a macOS demo box among the worst-ranked hosts:

The Whisper EDR console Overview reading 53 managed endpoints and 318 verifiable /128 identities on the wire. A worst-hosts list names edr-console-demo-01, edr-console-demo-win and edr-console-demo-mac. A Fleet coverage panel shows a connectivity-tier bar and an on-host sensor-depth bar.
Captured 2026-08-25 from the operator console. The macOS demo box sits in the same worst-first list as its Linux and Windows neighbours because identity, policy and containment are network-side: its /128 carries the same one-call revoke, sensor depth or not.

Identity on a Mac: verify it from the terminal you already have

The keyless half first. macOS ships dig and curl, and those two are enough to check a Whisper identity against the internet's own records, with our API nowhere in the trust path. The example is a live identity, the agent scout, so every line below is runnable from any Mac this second:

# reverse DNS names the address - the identity, in public
$ dig -x 2a04:2a01:b69a:6717:e3b0:51ff:3bf7:f478 +short
ae3b051ff3bf7f478.tdc38e7c55bad3306a92b830f9bb1e4f9.agents.whisper.online.

# the DANE-EE key pin (usage 3, selector 1, matching 1) - no public CA needed
$ dig +short TLSA _443._tcp.ae3b051ff3bf7f478.tdc38e7c55bad3306a92b830f9bb1e4f9.agents.whisper.online
3 1 1 9EC1EF18A1F15E5480A0FC3C8D6E9690B2CCF1A7FA7146201940F28C422BB47D

# one keyless call returns the whole evidence bundle
$ curl -s 'https://rdap.whisper.online/verify-identity?ip=2a04:2a01:b69a:6717:e3b0:51ff:3bf7:f478'
{
  "is_whisper_agent": true,
  "fqdn": "ae3b051ff3bf7f478.tdc38e7c55bad3306a92b830f9bb1e4f9.agents.whisper.online",
  "dane_ok": true,
  "jws_ok": true,
  "evidence": {
    "posture": "tier1.5",
    "dane": { "usage": 3, "selector": 1, "matching": 1,
              "profile": "DANE-EE 3 1 1 (DNSSEC-anchored TLSA; no public CA needed)",
              "strong_pin": true, "served_leaf_matches": true },
    "rdap": "https://rdap.whisper.online/ip/2a04:2a01:b69a:6717:e3b0:51ff:3bf7:f478"
  }
}

The full chain (the DNSSEC signatures validated to the IANA root, the forward-confirmed AAAA, the RDAP object) is in Verify an identity; delv, for validating on the Mac itself rather than trusting a resolver, is one brew install bind away.

The keyed half. The whisper CLI is a single static binary and macOS is a first-class build, and the install is genuinely easy: the same one command every other platform uses, no Gatekeeper argument required. It fetches a signed, checksum-verified binary and ad-hoc-signs it itself the moment it lands, so there is no quarantine flag to clear and no right-click-to-open:

# the CLI, same command on macOS and Linux
$ curl -fsSL https://get.whisper.online | sh

# with your API key: one call registers an agent and hands back a routable /128
$ curl -s -X POST https://graph.whisper.online/api/query \
    -H 'content-type: application/json' \
    -H 'X-API-Key: whisper_live_...redacted' \
    -d '{"query":"CALL whisper.agents({op:\"register\", name:\"scout\"})"}'

A signed, notarized, stapled installer package now builds end to end from this same tree, and Gatekeeper is clean on it: spctl --assess --type install reads accepted, source=Notarized Developer ID, a flip from rejected, source=no usable signature the week before. It has no download route open yet, so the curl one-liner above stays the way to actually get whisper onto a Mac today; a Homebrew tap also exists (brew install whisper-sec/tap/whisper) but is not kept in step with every release, so we point you at the one-liner rather than the tap.

How the Mac's traffic actually carries that identity is the same connectivity ladder as everywhere else, all of it network-side and none of it entitlement-gated: a routed /128 over WireGuard (a wg-quick config today, with one-line whisper connect ergonomics for the routed tier on the way), the source-bound egress proxy where you want packets leaving as the /128 without a tunnel, or simply keeping the Mac's own address and pointing its DNS at the graph-first resolution plane, which macOS can pin system-wide with an encrypted-DNS configuration profile. AI agents spawned on a Mac follow the agent path, not the host path: each gets its own governed /128 from the same one call, with policy composing down the tree. The deeper treatment is in The /128 identity.

The on-host bridge: new eyes, the same brain

macOS is a new pair of eyes, not a second brain. Two small Swift front-ends observe the Mac through Apple's own frameworks: an Endpoint Security daemon for process activity and a NetworkExtension DNS proxy for DNS. Each observation is encoded as one NDJSON line in the exact event vocabulary the Linux collectors emit and handed over a local Unix-domain socket to a bridge collector inside the same whisper sensor service that runs everywhere else. From that point on, a Mac event is indistinguishable from a Linux event: it rides the identical pipeline, the wide tap, the bounded on-host process graph, the local NDJSON spool the operator owns, and the curated uplink. No kernel extension exists anywhere in this design, because Endpoint Security and NetworkExtension are Apple's supported user-space surfaces and we refuse to ship anything lower.

PieceWhat it isEmits
Endpoint Security daemonA small Swift daemon under launchd, subscribed notify-only: process events always, file and memory events behind their own flagsexec lines, plus file and memory when enabled dev builds
DNS proxy system extensionA NetworkExtension DNS proxy plus the container app that activates it, a transparent relay that observes as a side-effectdns lines, UDP and TCP dev builds
The Go bridgeA darwin-only collector in the standard sensor service: binds the socket, validates every line, forwards into the shared pipelinethe same spool and uplink every Linux collector feeds
The macOS bridge. Two Swift observers, the Endpoint Security daemon and the DNS proxy system extension, encode NDJSON in the shared vocabulary and dial one local Unix socket. The Go bridge inside the standard sensor service owns the socket, gates every peer, validates every line, and forwards into the same tap, process graph, spool and uplink that Linux collectors feed; the shared detection engines consume copies. SWIFT · APPLE'S FRAMEWORKS · EYES ONLY ES DAEMON notify-only exec events can never block an exec DNS PROXY transparent relay, dns events never black-holes a query one Unix socket mode 0700 · peer-cred gate 64 KiB lines · ≤ 8 conns GO BRIDGE validate + forward drops counted, never guessed shared tap process graph NDJSON spool curated uplink identical to the Linux pipeline SHARED GO ENGINES OS-neutral, consume copies off the tap run on bridged events by construction the Swift side is eyes only: findings are made by the shared engines, never bridged in
The bridge owns and binds the socket; the Swift daemons dial it. When nobody is listening, the ES daemon writes its NDJSON to its own log instead, so a bridge that is down costs observations, never a wedged daemon. Direction of trust is deliberate: the Swift side stamps the host, timestamp and boot id, because on macOS it is the vantage point that knows the host.

The consequence is the one that matters: every OS-neutral Go engine, the event-chain correlator, the ransomware detector, the process graph, Sigma, YARA, runs on macOS telemetry with zero changes, by construction, because the wire contract is byte-identical and the tap is the same tap. The detection brain is shared; only the eyes are per-OS. And "by construction" is no longer the strongest form of that claim: the engines have now been exercised on Apple-silicon over the bridge datapath (the exec, file and socket collectors are proven on real Apple hardware; the /dev/bpf qname tap needs root and is exercised through a scripted read seam rather than a live device; the engines are exercised in datapath tests rather than fired by a live Endpoint Security feed), through the real bridge datapath, on real macOS. What we still do not claim: the live, entitlement-signed Endpoint Security feed driving them in production. The measured production engine runs published on this site are Linux and Windows runs, and Platform support owns that matrix.

What it streams today, exactly

One JSON object per line, a kind field discriminates, timestamps are epoch microseconds everywhere. This is the same envelope the Linux pages document, which is the point. Per kind:

KindCarriesmacOS producer
execpid, ppid, uid, comm, executable path, a vnode-pinned size-capped sha256, known-good mark, a bounded command line, boot id, host, plus the kernel's code-signing verdict: team id, signing id, cdhash, the platform-binary fact and the raw cs flagsEndpoint Security exec notifications streaming, dev builds
dnsqname, qtype, querying pid, source port, the resolver the OS chose, hostThe DNS proxy, UDP and TCP DNS both streaming, dev builds
filecreate / modify / move / delete / hash, with path and digestEndpoint Security file subscriptions (create, settled close-after-modify, truncate, rename, unlink, clone), behind their own flag and scoped to the watch dirs the bridge announces dev builds
memoryremote-thread-create, executable mprotect, executable mmap, each with the acting process's kernel signing identityEndpoint Security memory notifications, behind their own flag; dispatched straight to the injection correlator, never to the spool dev builds
connpid, destination, port, directionVocabulary reserved; macOS covered by the entitlement-free libproc socket sampler

Two details worth trusting. The image hash is honest by construction: the size-capped sha256 is pinned to the exec-time file identity, so a binary swapped between exec and hash yields no digest rather than a wrong one, and any field a message cannot supply stays at its zero value instead of being guessed. And DNS attribution is honest the same way: the querying pid comes from the flow's own audit token and reads zero when absent, an admitted absence, never a claim.

Bounded and safe by construction

The macOS path inherits the same two laws every Linux collector obeys: observe never blocks, and the sensor never takes the service down. The numbers below are resource bounds and trust properties, compiled in rather than configured, published because they build confidence without handing anyone an evasion map. The missing knobs are the design here too.

The Go bridge

The Endpoint Security daemon

The DNS proxy

One wire contract, byte-proven

"Same brain" would be marketing if it rested on a shared intention. It rests on a corpus. The Swift encoders are proven byte-identical to the Go golden corpus for the exec and dns kinds: a corpus-driven contract suite reads the staged Go corpus and holds the live Swift encoder to it, and the suite is mutation-verified, meaning a one-token edit to the corpus flips the tests red at the exact byte offset. It runs in CI on Linux Swift, no Mac in the loop, so drift cannot land. The corpus spans exec, dns and file, including a darwin-spelled file set, and the memory goldens are carried verbatim by their Go twin, so the two encoders cannot move apart silently. Only conn remains Go-canonical, because there is no macOS producer for it yet; we state that rather than blur it.

i

What the proof buys you. When the entitlement lands and the bridge ships broadly, macOS does not get a young detection stack: it gets the Linux one, unchanged, because a macOS event has been provably indistinguishable on the wire the whole time. The contract is the moat against per-OS drift, and it is enforced by CI, not by discipline.

What has run on a real Mac

Contract tests on Linux CI say the engines would run on macOS. In August 2026 we closed the remaining distance and ran them on macOS: the compiled darwin sensor's own engine and datapath suites, executed on a real Apple-silicon Mac, pushing ES-shaped events through the real bridge ingest into the real engines, the exact code path the live feed uses. Every engine fired. The captures below are from that run, 2026-08-26, unedited apart from trimming:

# the compiled darwin sensor test binary, run on the Mac itself:
# the ransomware datapath (T1486 mass-encrypt, the ES-spelled canary trip, T1490
# recovery-tool execs), the event chain, the injection correlator, the response fence
--- PASS: TestEventChain_OrderedChainFires (0.00s)
--- PASS: TestEventChain_SelfExecutingDropperFires (0.00s)
--- PASS: TestEventChain_DescendantConnectFires (0.00s)
--- PASS: TestRansomware_MacBridgeFileDatapathMassEncryptFiresT1486 (0.00s)
--- PASS: TestRansomware_MacBridgeCanaryHitESSpellingFiresT1486 (0.00s)
--- PASS: TestRansomware_MacBridgeDatapathExecsReachTheDetectorAndFireT1490 (0.00s)
--- PASS: TestESInjectionCorrelatorFiresAndDedups (0.00s)
    --- PASS: TestESInjectionCorrelatorMemoryShapes/remote_thread_fires_hollow (0.00s)
    --- PASS: TestESInjectionCorrelatorMemoryShapes/remote_thread_from_platform_binary_is_screened (0.00s)
    --- PASS: TestESInjectionCorrelatorMemoryShapes/W^X_mprotect_fires_rwx (0.00s)
--- PASS: TestDarrtProcessStopFencesThroughHandle (0.00s)
--- PASS: TestDarrtProcessStopPlatformBinaryRefusedBySigningAlone (0.00s)
--- PASS: TestDarCoreStartTicksFromTimeval (0.00s)
PASS

Three of those lines deserve a sentence each. The ransomware trio is the datapath claim made real: mass-encryption pressure fed as bridged file events fires T1486, a canary tripped under the exact resolved-path spelling Endpoint Security reports fires the strongest signal, and recovery-tool execs riding the bridged exec stream fire T1490. The injection lines are the correlator convicting on the memory shapes ES reports in real time, remote-thread-create into a foreign task and a writable-then-executable flip, while screening the same act when the actor is an Apple platform binary. And the response lines are the process-stop identity fence doing its one job: the (pid, start-ticks) identity is re-proven before every signal, so a recycled pid, which always carries a different start time, is refused rather than killed.

The full sensor service, the same binary an operator installs, also boots on the machine and binds the root-only bridge socket the Swift daemons dial:

# the standard sensor service, started on the Mac
whisper: sensor: observing with 1 collector(s) -> /tmp/whisper-e2e/spool.ndjson
# the bridge socket, up, root-only
srwx------  1 root  daemon  0 Aug 26 06:42 /var/run/whisper-esclient.sock

And the Swift Endpoint Security client builds for release on the same machine, in seconds:

$ swift build -c release
Building for production...
[11/12] Linking whisper-esclient
Build complete! (4.16s)

The code-signing force-multiplier

One thing macOS gives the engines that Linux structurally cannot: on every event, Endpoint Security attaches the kernel's own code-signing verdict for the acting process, the team id, the signing id, the cdhash, the platform-binary fact and the raw cs flags. A Linux exec event has no kernel-attested signing identity; here it arrives free, on every message, and the engines already judge with it. The injection correlator screens remote-thread creation from Apple platform binaries and treats an ad-hoc image staging executable memory as the reflective-loader tell; the response executor refuses to stop a platform binary on signing grounds alone; and absence is treated as absence, a missing cs-flags fact is a non-signal, never a claim of unsigned. Both of the platform-binary judgments are in the passing lines above. The identity itself is real and readable on the same machine, here via codesign on one of the run's own detonation binaries:

# codesign(1) reading the identity of a detonation binary from the run
Identifier=payload
CodeDirectory v=20400 size=384 flags=0x20002(adhoc,linker-signed) hashes=9+0 location=embedded
CDHash=50a8e531f800f37e224934a9b18885a10c3909bc
Signature=adhoc
TeamIdentifier=not set

The gate, proven, not asserted

The same machine also proves the one thing this page refuses to blur. The live Endpoint Security feed requires Apple's ES entitlement plus a Developer ID signature and notarization, and macOS enforces that in the kernel's integrity daemon, not in a license agreement. We ran our real ES client, ad-hoc signed, on the SIP-enabled Mac and let the OS answer:

# the real ES client, ad-hoc signed, on a SIP-enabled Mac: killed before main()
EXITED code=137
# the system log names the killer and the reason
amfid: .../whisper-esclient not valid: Error Domain=AppleMobileFileIntegrityError Code=-423
       "The file is adhoc signed or signed by an unknown certificate chain"
# control: the SAME binary, signed WITHOUT the ES entitlement, runs fine -
# the gate is the entitlement, not the code
usage: whisper-esclient [--socket PATH] [--stdout] [--file-events] [--memory-events] [--watch-dir DIR ...]
# and running it as root changes nothing, with the reason spelled out
amfid: Adhoc signed app with restricted entitlements detected
amfid: .../whisper-esclient not valid: Code=-424 "The file is adhoc signed but contains restricted entitlements"

That is the flip-on-approval shape, stated exactly. The wire contract and the service model are proven on real macOS today, and the exec collector's code-signing identity is proven on real hardware; the engines themselves are exercised in compiled arm64 datapath tests rather than fired on a live host; the one missing piece is Apple's signature on the ES client, and the capture above is the OS itself saying so. When the entitlement lands, the same client is signed, notarized and loaded, and the proven pipeline behind the socket starts receiving live events. No new code path is waiting to be written on approval day.

Beyond parity, built dark: the inline-block plane

Everything above is the observe plane, and observe-only is the sensor's posture everywhere. On Linux the one blocking primitive is the opt-in exec guard, an inode-scoped deny. macOS offers strictly more: an Endpoint Security AUTH client can make the kernel suspend an exec, a signal or a file open until a verdict comes back, a true inline block at the syscall boundary, with the kernel's code-signing identity attached to the thing being judged, so a deny can name a cdhash and a contained pid can be protected from tampering. We have built that plane, and it ships dark:

This is the beyond-parity tier: when armed, macOS gets a prevention surface deeper than the Linux exec guard, and it inherits every safety rail that guard taught us. The memory path stays dark until the entitlement lands; the file collector is proven on real Apple hardware, and on customer machines SIP stays on, always.

Install and service model

The service shape is boring on purpose, and identical in kind to every other platform. Three pieces land on a Mac:

And the caveats, stated as two gates rather than a footnote:

PostureWhat worksThe gate
Developer and internal, today currentBuilding, testing, running the sensor service and exercising the engines over the bridge datapath on a stock Mac with SIP fully enabled, and the August 2026 run above did exactly that, in compiled arm64 datapath tests rather than a live host firing. Running the live ES client does not: macOS kills an ad-hoc-signed ES client before it starts, and the capture above is that kill, verbatim. A dev Mac that needs the live feed takes a one-time SIP relaxation plus system-extension developer mode; that is our internal harness, and nothing from it ships to customers.Apple's platform policy on unsigned ES clients, by design. We work inside it, not around it.
Customer ship gatedSIP stays fully on. Delivered as a signed, notarized, stapled package under a Developer ID.The Apple Endpoint Security entitlement, a restricted, Apple-approved capability, application in progress. Externally clocked, not an engineering gap: the engines are exercised in compiled arm64 datapath tests, the contract suite and the install model already exist, and approval flips the live feed on.

Where macOS stands

The status vocabulary here is the same one Platform support defines, and it is exact. Live means shipped, and for Linux and Windows, measured on a real box. In development means built, contract-tested and, for macOS, exercised over the bridge datapath in compiled arm64 tests, but not yet customer-installable. macOS is in development: the engines are exercised over the bridge datapath in compiled arm64 tests, not fired by a live feed, the wire contract is byte-proven, and the live Endpoint Security feed waits on Apple's ES entitlement, killed by the OS itself until then. We never round that up, on this page or anywhere else.

What should convince you is the shape, not a promise. This is an EDR whose containment does not live on the endpoint, so the platform Apple gates most tightly is also the platform where our core protection loses nothing by waiting. And when the on-host half does ship, it is not a fork and not a kext: it is the same Go brain already exercised on Apple-silicon over the bridge datapath (the exec, file and socket collectors are proven on real Apple hardware; the /dev/bpf qname tap needs root and is exercised through a scripted read seam rather than a live device; the engines are exercised in datapath tests rather than fired by a live Endpoint Security feed), behind Apple's own frameworks, with a CI-enforced proof that the Mac's telemetry was never a dialect, waiting only for Apple's signature to start listening live.