Skip to main content
The endpoint agent is pure Bash - curl + openssl over POSIX sh, with no Python runtime or third-party packages on the endpoint. It plants the bait, then watches the bait paths for a read and fires a signed callback the moment one happens.

Sensors

fs_usage is the real sensor: it yields genuine open/read events and, via ps, the process and user that read the file - which enrich the alert. It requires root, which the agent has when run under MDM. The firehose is trimmed at the source by grep-ing to only the bait paths, and noise processes (Spotlight, mds, the agent itself, …) are filtered out. The atime fallback exists so non-macOS hosts get some coverage, but it’s strictly best-effort.

The agent protocol

The agent never parses JSON. The agent-facing API speaks a plain-text protocol so enroll, pull, and the signed callback are each a few lines of shell:
  • Enroll - POST /api/enroll with the shared enroll token; the response is key=value lines, including the endpoint’s agent_token.
  • Pull - GET /api/agent/deployments returns this endpoint’s own instances as tab-separated records (deployment id, path, HMAC secret, and URLs for the bait content and the callback). The bait content isn’t inlined - it can be multi-line - so the agent fetches it raw from the per-deployment content URL.
  • Trigger - on a read, the agent builds a key=value body (deployment_id, event_type, process, pid, os_user, accessed_path, triggered_by, timestamp) and POSTs it to POST /api/trigger.
Every callback is HMAC-signed: the agent computes openssl dgst -sha256 -hmac over the exact request body and sends it as X-Thumper-Signature: sha256=<hmac>. If the server stops recognizing the deployment (a DB reset or redeploy returns 401), the agent re-enrolls, re-pulls, and resends - so the read that triggered it still alerts under fresh credentials. See the security model for how the server verifies it.