> ## Documentation Index
> Fetch the complete documentation index at: https://quintsecurity.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# EndpointSecurity Extension

> macOS system extension — code signing detection, 9 event types, Unix socket transport to daemon

# EndpointSecurity Extension

The EndpointSecurity (ES) system extension is the **ground truth** tier of Quint's architecture. It runs as a macOS system extension inside `QuintAgent.app`, using Apple's EndpointSecurity framework to monitor file operations, process events, and agent lifecycle at the OS level. The extension communicates with the Go daemon over a Unix socket with auth handshake.

While the forward proxy captures **intent** (what agents ask models to do), the ES extension captures **truth** (what actually happens on disk). Divergence between the two is the highest-signal threat Quint can detect.

## Architecture

```mermaid theme={null}
flowchart TD
    subgraph ESExtension["QuintEndpointExtension (Swift)"]
        SC["Scout\n(ES Client 1)\nNOTIFY_EXEC only"]
        REC["Recorder\n(ES Client 2)\n9 event types\ninverted muting"]
        PT["ProcessTracker\nPID → platform map"]
        AS["AgentSignatures\n4-layer detection cascade"]
        BUF["Buffer\n(10,000 event capacity)"]
        SOCK["SocketClient\nUnix socket + auth"]
    end

    subgraph Daemon["Go Daemon"]
        ESL["eslistener\n(Unix socket server)"]
        UNI["unisession\n(Unified Session Tracker)"]
        FWD["cloud/forwarder\n(batch push to API)"]
    end

    SC -->|"exec detected"| AS
    AS -->|"agent? yes"| PT
    PT -->|"watch(auditToken)"| REC
    REC -->|"9 event types"| BUF
    SC -->|"exec events"| BUF
    BUF --> SOCK
    SOCK -->|"Unix socket\nlen-prefixed JSON\nauth handshake"| ESL
    ESL --> UNI
    UNI --> FWD

    style ESExtension fill:#1a1a2e,stroke:#FF3C22,stroke-width:2px
    style Daemon fill:#1a1a2e,stroke:#FF6B57,stroke-width:2px
```

## Two ES Clients

The extension uses two separate EndpointSecurity clients with different roles:

### Scout (Client 1)

Subscribes to `ES_EVENT_TYPE_NOTIFY_EXEC` only -- every process launch on the machine. For each exec, it runs the 4-layer agent detection cascade. When an agent is found, it tells the Recorder to start watching that process and all its children.

Scout sees everything but does minimal work per event (just the detection check).

### Recorder (Client 2)

Uses **inverted muting** (`es_invert_muting`): by default it receives zero events. When Scout activates a process via `es_mute_process` (which, under inverted muting, means "start watching"), the Recorder subscribes to all 9 event types for that process.

This design means the Recorder only receives events from confirmed AI agent processes -- no noise from the rest of the system.

## 9 Event Types

| Event    | ES Constant                   | What It Captures                                                    |
| -------- | ----------------------------- | ------------------------------------------------------------------- |
| `exec`   | `ES_EVENT_TYPE_NOTIFY_EXEC`   | Process execution with binary path, signing info, command-line args |
| `fork`   | `ES_EVENT_TYPE_NOTIFY_FORK`   | Child process creation (child is auto-watched via parent cascade)   |
| `exit`   | `ES_EVENT_TYPE_NOTIFY_EXIT`   | Process termination                                                 |
| `open`   | `ES_EVENT_TYPE_NOTIFY_OPEN`   | File open with full path                                            |
| `write`  | `ES_EVENT_TYPE_NOTIFY_WRITE`  | File write (fd-level, no path)                                      |
| `close`  | `ES_EVENT_TYPE_NOTIFY_CLOSE`  | File close with full path and modified flag                         |
| `rename` | `ES_EVENT_TYPE_NOTIFY_RENAME` | File rename with source path                                        |
| `unlink` | `ES_EVENT_TYPE_NOTIFY_UNLINK` | File deletion with target path                                      |
| `create` | `ES_EVENT_TYPE_NOTIFY_CREATE` | File/directory creation with destination path                       |

<Note>
  Network events (`connect`, `sendto`) are not available in the ES framework's notify API. Network monitoring for agent traffic is handled by the forward proxy tier.
</Note>

## Agent Detection Cascade

The extension detects AI agent processes through a 4-layer cascade, evaluated in priority order:

```mermaid theme={null}
flowchart TD
    EXEC["Process EXEC event"] --> L1{"Layer 1: Code Signing\n(TeamID + SigningID)"}
    L1 -->|"match"| AGENT["Agent Detected ✓"]
    L1 -->|"no match"| L2{"Layer 2: Path/Name\n(binary name + path substring)"}
    L2 -->|"match"| AGENT
    L2 -->|"no match"| L3{"Layer 3: Args\n(interpreter + agent script)"}
    L3 -->|"match"| AGENT
    L3 -->|"no match"| L4{"Layer 4: Parent Cascade\n(parent is watched agent?)"}
    L4 -->|"yes"| AGENT
    L4 -->|"no"| SKIP["Not an agent — ignore"]
```

### Layer 1: Code Signing (Highest Confidence)

Uses the macOS code signing identity (`signingID` + `teamID`) that the kernel verifies cryptographically. This is unforgeable without the vendor's signing key.

| Platform         | Team ID      | Signing IDs                                 | Team-Only Trust                                              |
| ---------------- | ------------ | ------------------------------------------- | ------------------------------------------------------------ |
| `claude-code`    | `Q6L2SF6YDW` | `com.anthropic.claude-code`                 | Yes (Anthropic has few products)                             |
| `claude-desktop` | `Q6L2SF6YDW` | `com.anthropic.claudefordesktop`, `.helper` | Yes                                                          |
| `cursor`         | `VDXQ22DGB9` | `com.todesktop.230313mzl4w4u92`, `.helper`  | Yes                                                          |
| `copilot`        | `UBF8T346G9` | `com.microsoft.VSCode`                      | No (Microsoft has many products -- requires SigningID match) |

For vendors with few products (3 or fewer signing IDs), a TeamID-only match is accepted. This covers new products from a known AI vendor (e.g., if Anthropic ships a new tool signed with the same TeamID, it's auto-detected). For vendors with many products (Microsoft), both TeamID and SigningID must match.

### Layer 2: Path/Name (Fallback)

For unsigned or unknown-vendor tools, matches on process binary name (case-insensitive exact) and binary path (substring). Covers 21 platforms including Claude Code, Cursor, Copilot, Windsurf, Kiro, Codex, Aider, Cline, Continue, Augment, Goose, Gemini CLI, Amp, Zed, OpenCode, PearAI, Trae, Void, and Devin.

### Layer 3: Arg Match (Interpreters)

For interpreter processes (`node`, `python`, `python3`, `bun`, `deno`), checks command-line arguments for known agent script patterns. Catches cases like `node /path/to/claude-code/main.js`.

### Layer 4: Parent Cascade (Lowest Confidence)

If the parent process is already tracked as an agent, the child inherits agent status. This captures the full process tree -- when Claude Code forks a child process, that child is automatically watched.

## Unix Socket Transport

The extension communicates with the Go daemon over a Unix stream socket (`AF_UNIX`, `SOCK_STREAM`):

| Setting            | Value                                                 |
| ------------------ | ----------------------------------------------------- |
| Socket path        | Read from `/etc/quint/es-socket-path`                 |
| Auth secret        | Read from `/etc/quint/es-auth-secret`                 |
| Frame format       | 4-byte big-endian length prefix + JSON payload        |
| Buffer capacity    | 10,000 events                                         |
| Reconnect interval | 2 seconds                                             |
| Drain interval     | 100ms                                                 |
| Socket mode        | Non-blocking (`O_NONBLOCK`)                           |
| Write safety       | `SO_NOSIGPIPE` (returns `EPIPE` instead of `SIGPIPE`) |

### Auth Handshake

On connection, the extension sends an auth frame before any events:

```json theme={null}
{"type": "auth", "secret": "<shared-secret>"}
```

The shared secret is stored at `/etc/quint/es-auth-secret` (readable by both the extension and daemon). The daemon validates the secret before accepting events.

### Non-Blocking Writes

The socket is set to `O_NONBLOCK` so ES callback threads are never blocked by a slow or dead connection. If a write fails:

1. The failed event is pushed back to the buffer
2. The connection is marked dead
3. The run loop reconnects after 2 seconds
4. Buffered events drain on reconnection

Dead connections are detected via `recv(MSG_PEEK)` returning EOF.

## Event Payload

Each event sent over the socket includes:

```json theme={null}
{
  "type": "exec",
  "timestamp": "2026-04-12T10:30:00Z",
  "pid": 12345,
  "ppid": 12340,
  "uid": 501,
  "process": {
    "path": "/usr/local/bin/claude",
    "signingID": "com.anthropic.claude-code",
    "teamID": "Q6L2SF6YDW",
    "isPlatformBinary": false,
    "args": ["claude", "--model", "claude-sonnet-4-20250514"],
    "cwd": ""
  },
  "event": {
    "file": {"path": "/Users/dev/project/src/main.go"}
  },
  "agentMatch": {
    "matched": true,
    "platform": "claude-code",
    "matchReason": "code_signing"
  }
}
```

## Installation & Entitlement

The ES extension ships inside `QuintAgent.app`, distributed via the `.pkg` installer:

* **QuintAgent.app** — host app that activates the system extension, shows status bar icon
* **QuintEndpointExtension** — the actual system extension binary

<Warning>
  The EndpointSecurity framework requires an Apple-issued System Extension entitlement. Quint's entitlement application is pending (typically 1-4 months). During development, the extension runs with SIP disabled or in a reduced-security VM.
</Warning>

### Requirements

* macOS 11+ (EndpointSecurity framework)
* System Extension approval (user consent dialog)
* Full Disk Access (for file event monitoring)
* Root/admin for installation

## Relationship to NE

Quint ships a second system extension alongside ES: the [Network Extension](/edge/network-extension), which transparently redirects LLM API flows into the MITM pipeline. The two extensions are independent — separate bundles, entitlements, and approval flows — and a failure in one doesn't affect the other. Both feed the same daemon and converge in the `unisession.Tracker`.

## Tier Comparison

|                        | Tier 1: Proxy                                                   | Tier 2: ES Extension                                                  |
| ---------------------- | --------------------------------------------------------------- | --------------------------------------------------------------------- |
| **Status**             | Shipped                                                         | Built (entitlement pending)                                           |
| **Language**           | Go                                                              | Swift                                                                 |
| **What it sees**       | Intent (tool calls, HTTP requests, LLM conversations)           | Truth (file I/O, process lifecycle, OS events)                        |
| **Agent detection**    | User-Agent headers, domain patterns, system prompt fingerprints | Code signing (cryptographic), process name/path, args, parent cascade |
| **Deployment**         | User-space, proxy env vars                                      | System extension, requires Apple entitlement                          |
| **Coverage**           | Traffic routed through proxy                                    | All OS-level activity from agent processes                            |
| **Evasion resistance** | Agent can skip proxy                                            | Cannot bypass without kernel exploit                                  |
| **Key signal**         | LLM conversation content, tool call arguments                   | File operations, process tree, execution patterns                     |

<Info>
  When both tiers run together, Quint detects **intent vs. truth divergence** -- an agent that claims to read a file (Tier 1) but actually exfiltrates credentials (Tier 2) triggers a high-confidence alert. This is the foundation of Quint's defense-in-depth architecture.
</Info>
