Security & Privacy
How Daintree sandboxes processes, hardens IPC, enforces Trusted Types, scrubs secrets, contains the daintree-file protocol, hardens git, filters environments, handles skip-permissions, and stores your data.
Daintree runs coding agents with real filesystem and network reach, on your machine, inside your repositories. That is the whole point of the habitat, and it is also the reason this page exists. Everything below describes a boundary that is enforced in code, plus the handful of places where the honest answer is that no boundary exists and you are trusting something.
The boundaries
Four areas carry enough detail to have their own page. They fail in unrelated ways, so they are documented apart rather than as one long list:
- Desktop and IPC. Renderer sandboxing, the separation between the UI and the processes with real system access, IPC validation and rate limiting.
- Browser and content. Content
Security Policy, Trusted Types, the embedded browser, permission lockdown, the
daintree-file://protocol, and what happens to an external link. - Git, process and environment. Git command and pathspec hardening, lifecycle script injection, secret scrubbing, environment filtering, and what skip-permissions actually turns off.
- Privacy and data. What is stored and where, what telemetry does and does not send, and macOS folder access.
Plugin trust
Plugins are the one surface where third-party code runs inside Daintree, and the trust model is deliberately explicit about what it does and does not promise.
A plugin's main entry runs in a utility worker, while a contributed React view runs in the app renderer. The host API applies capability, scope, and consent checks to its own methods. That provides specific controls and worker crash recovery, but the normal plugin worker is not a Node sandbox: direct Node filesystem, process, and network calls are not contained by the manifest's host API scopes.
Project-level plugins add executable code to a repository under .daintree/plugins/. Discovery stages them for review; folder trust and project activation are separate from merely opening the repository. Review plugin source and the built entry points before trusting a folder. Trust is local to the user, not something a collaborator grants by committing a file.
Install or trust plugins as code that can run with your account's permissions. An archive hash identifies bytes; without an independently trusted expected hash or signature, it does not authenticate a publisher. Worker isolation also does not isolate a plugin's React view from the app renderer.
The full capability list, the compound-capability lattice, the scope semantics and the install pipeline are documented in Plugin trust and capabilities.
MCP server
Daintree exposes an opt-in local MCP server for external tools, and it also provisions per-session MCP wiring for the agents it launches itself. The two have separate trust boundaries.
Network and auth
The local server is disabled by default and binds to 127.0.0.1 only, so Daintree does not expose a network listener on external interfaces. On first start it generates a bearer key in the format daintree_<32-hex>, compared timing-safely on every request, and the transport additionally requires a matching loopback Host and validates an optional Origin as a matching HTTP loopback origin. Rotating the key from Settings > MCP server invalidates every external client holding the old one.
Four properties are worth repeating here because they are access-control boundaries rather than conveniences: destructive calls confirm in Daintree, never through client-declared elicitation; project.getSettings does not return decrypted secrets over MCP; introspection is scoped to the calling session's own tier; and the external fullToolSurface opt-in was removed outright: it used to expose 335 of 426 actions to any API-key caller, and nothing replaces it. The full model is on the MCP server page.
Cross-agent token isolation
When Daintree launches an agent that needs MCP wiring, it mints a per-session token scoped to a single agent type. A token issued for a Claude session is not valid for a Codex, Gemini or Copilot spawn, and the reverse holds. Token reuse across agent types is the pattern this guards against.
Enforcement is at the spawn-argument builder: each agent's builder returns nothing when handed a token from a different agent type, and the caller throws rather than falling back. This is a hard spawn failure (the process never starts), not a silent downgrade.
The literal bearer is kept out of command-line arguments. Codex reads it from the PTY environment; Copilot receives an environment-variable placeholder in its session configuration and the value through its PTY environment. Other adapters use their supported session-config transport. This reduces argument-list exposure; it does not make environment variables, temporary files or arbitrary logs secret-proof.
App-level guards
Two smaller behaviors that exist to prevent accidental loss rather than to stop an attacker:
- Single instance. Only one copy of Daintree runs at a time; opening a second focuses the existing window. This avoids conflicts over file locks and terminal processes.
- Window close protection. Command-W Control-W, or Control-F4 Control-W closes the focused panel, not the application window, so a reflexive keystroke does not take a set of running agent sessions with it.