Skip to main content
Beta — OS-level Sandbox is opt-in and under active development. Behavior, settings, and platform support may change between releases.
OS-level sandboxing lets users set filesystem and network boundaries for Droid. In the Beta version, all shell commands initiated by Droid run in a separate process that is limited to the filesystem and network boundaries configured by users and enforced at the OS kernel level.

How OS-level isolation works

Sandbox enforces its filesystem and network boundaries with the same operating-system primitives the OS uses to confine untrusted software, so a blocked read, write, or connection is denied by the kernel rather than relying on Droid to police itself:
  • macOS — Seatbelt (the built-in macOS sandbox) profiles restrict filesystem and process access.
  • Linux and WSL2bubblewrap with a seccomp filter provides the same confinement.
  • Network (all platforms) — outbound traffic is routed through an HTTP/SOCKS filtering proxy that permits only the allowed domains (Factory’s own domains are always allowed).
Because Sandbox relies on these host primitives, it blocks rather than running without isolation when they are unavailable.

Isolation modes

The sandbox.mode setting selects what is placed inside the OS boundary. Both modes enforce the same default policies and configuration; they differ only in scope.
per-command (default)whole-process
Runs inside the OS sandboxEach shell command and its child processesThe entire Droid process
MCP servers, hooks, subagentsWrapped or checked against your policy per callIsolated inside the process boundary
Main Droid processNot isolatedIsolated
If isolation is unavailableThe affected command or hook is blockedDroid refuses to start
  • per-command runs each Droid-initiated action through the sandbox individually. Shell commands (and their child processes) are confined at the OS level; other tools are mediated by policy checks before each call. The main Droid process itself is not isolated.
  • whole-process launches the entire Droid process inside the OS sandbox, so the main process and everything it spawns (MCP transports, subagents) is isolated too. Its own network requests — not just those from the Execute tool — are filtered against allowedDomains, with interactive domain prompts in TUI mode. If the sandbox cannot be established at startup (unsupported platform or a failed isolation check), Droid refuses to start rather than running unsandboxed.

Enable and configure the sandbox

Set sandbox.enabled to true in your settings to turn on the sandbox:
{
  "sandbox": {
    "enabled": true
  }
}
Once enabled, the default policies below apply immediately — no other configuration is required to start. Settings resolve across the hierarchy (org > project > user), so you can enable the sandbox for yourself (user settings), a repository (project settings), or everyone (organization settings).

Default access policies

ResourceDefault policyConfigurable via
File readsAllow all. Only explicit denyRead entries are blocked.sandbox.filesystem.denyRead
File writesDeny all except CWD (current working directory). Additional paths can be allowed. denyWrite overrides allowWrite.sandbox.filesystem.allowWrite, sandbox.filesystem.denyWrite
NetworkDeny all except Factory’s own domains (always allowed by default). Additional domains must be explicitly allowed.sandbox.network.allowedDomains

Full settings reference

{
  "sandbox": {
    "enabled": true,
    // Isolation scope: "per-command" (default) or "whole-process"
    "mode": "per-command",
    "filesystem": {
      // Additional writable paths beyond CWD (which is always writable)
      "allowWrite": ["/tmp/build-output", "~/.config"],
      // Deny writes to specific subpaths even if parent is in allowWrite
      "denyWrite": ["/tmp/build-output/cache/locks", "~/.config/secrets"],
      // Block reads to specific paths (everything else is readable)
      "denyRead": ["~/.aws/credentials", "~/.ssh/id_rsa"]
    },
    "network": {
      // Only these domains are reachable (Factory's own domains always included)
      "allowedDomains": ["github.com", "*.npmjs.org"]
    }
  }
}
Settings merge across the hierarchy (org > project > user). denyWrite/denyRead use union merge — org denies cannot be removed downstream.

Organization controls

  • Org-level denyWrite/denyRead settings cannot be overridden by user “Allow always”
  • Violation prompt shows “(organization policy)” when the deny comes from org settings
  • Admins can set the sandbox isolation mode (per-command or whole-process) org-wide from Enterprise Controls

Coverage and enforcement

With the sandbox enabled, a tool runs only if the sandbox can check everything it might do against your filesystem and network rules. Tools whose actions can’t be checked are blocked.
  • File tools (Read, Edit, Create, LS, Grep, Glob, ApplyPatch) — checked before every operation, enforcing denyRead for reads and allowWrite/denyWrite for writes
  • Execute tool — shell commands run inside the OS sandbox, with network routed through a filtering proxy for domain-level control
  • FetchUrl — network requests are checked against allowedDomains
  • WebSearch — network requests are checked against allowedDomains
  • MCP tools — filesystem and network requests are checked; locally launched servers receive a minimal environment (ambient host environment variables are dropped, keeping only a safe operational allowlist plus keys set in mcp.json)
  • Subagents (Task tool) — delegated subagents inherit the parent sandbox policy
  • Hooks — hook commands (PreToolUse, PostToolUse, etc.) are wrapped by the sandbox and run with the same proxy/runtime env as the Execute tool; if the sandbox cannot be established the hook is blocked instead of running on the host

When something is blocked

Interactive permission prompts (TUI mode):
  • Sandbox violations interrupt the agent loop with a TUI prompt, even at Auto (High) autonomy
  • Options: Allow once, Allow always (persists to settings), Deny — for denyRead/denyWrite violations, “Remove from deny list” replaces “Allow always”
  • Execute network violations show a real-time domain prompt with a 60s auto-deny timeout
Non-interactive mode (droid exec):
  • Sandbox violations are auto-denied without prompting — no hang, no user interaction required
  • The agent receives a denial message and reports it in the output
Allow-always persistence:
  • Choosing Allow always saves the exception to your user settings (for example, adding a domain to allowedDomains or a path to allowWrite) so it won’t prompt again
  • Changes take effect immediately in the current session
TUI indicators:
  • SANDBOX status indicator in footer when sandbox is enabled
  • “Sandbox Violation” prompt with violation details (path, domain, reason)

Security limitations

Sandboxing reduces the impact of a mistake or a prompt-injection attack, but it does not eliminate risk:
  • Allowed network egress can still leak data. Every domain in allowedDomains is a channel through which data the agent can read might leave. Keep the allowlist as narrow as your workflow permits.
  • A writable path can still be modified. The sandbox limits where writes land, not what is written within the allowed paths — including your own project code under the working directory.
  • Your settings files are protected. Sandboxed tool processes cannot write to Droid’s own configuration files (e.g. settings.json), so they cannot silently change sandbox policy.
Treat Sandbox as defense in depth alongside Autonomy Level approvals and human review, not as a hard boundary around untrusted code. To evaluate code you do not trust, run Droid inside a container or a dedicated virtual machine.