Docs · Accounts

Security and isolation

What separates sandboxes

  • A VM each. Every sandbox is a QEMU/KVM virtual machine with its own kernel (the distribution's own), memory and disk. Sandboxes share a physical machine with other sandboxes, but no kernel.
  • A confined VM process. Each VM's QEMU process runs as an unprivileged user with no capabilities, under QEMU's seccomp sandbox (it can't start programs or gain privileges), in a systemd unit that makes the system read-only, lets it write only its own VM's directory and gives it only /dev/kvm, /dev/net/tun and /dev/vhost-net.
  • A separate network port. Each VM has its own port on the machine's network bridge. It can't reach other sandboxes, the machine itself or private ranges, can only send traffic from its own addresses (no spoofing), and can't send router advertisements. Inbound connections to its public IPv6 address are refused except SSH and the ports you open. See Network.
  • Its own disk. A new sandbox's disk is a copy of froog's base image, which is cleaned of keys, machine ids and logs before it's saved. Snapshots, forks and saved snapshots are copies of one sandbox's disk.
  • Shared CPU and memory. vCPUs are shared with other sandboxes on the machine. To fit more VMs, memory pages that are identical across VMs are stored once (KSM), and memory a guest frees goes back to the machine.

Inside a sandbox

You log in as user, which has passwordless sudo: you and your agents are root in your own VM. froog prompt runs each harness with its permission prompts off (for example Claude Code with --dangerously-skip-permissions, Codex with --dangerously-bypass-approvals-and-sandbox), because the VM is the boundary. Anything that runs in a sandbox, including code an agent downloads, can read everything in it: your variables (in ~/.froog/env), secret files, logins made inside it and its froog key. Give a sandbox only the credentials its work needs, and use --no-environment for code or people you don't trust.

--no-environment decides what froog writes into a sandbox at start. It doesn't clean a disk you start from: a fork, or a sandbox from a saved snapshot, has everything that was on the source's disk, secret files and logins included. Make templates for untrusted code from a sandbox that never held credentials.

Who can get in

  • SSH: keys only. Password and root logins are off. Your account's SSH keys (froog keys) are written to ~/.ssh/authorized_keys at every start, and froog rewrites the file on running sandboxes when you add or remove a key, so a removed key stops working at once (a stopped sandbox gets the new list when it starts). froog owns the file: it replaces it whole, so keys you add to it by hand are dropped at the next rewrite. Register them with froog keys add. Each sandbox has its own SSH host key, made by froog and pinned by the CLI, so froog ssh refuses a machine that isn't yours.
  • API keys: each has scopes and an expiry. froog stores only a SHA-256 hash of each key.
  • The in-sandbox key reaches only its own sandbox and can't create, start, fork or delete sandboxes. It's replaced at every start and revoked when the sandbox stops.
  • froog's control plane holds a key of its own for each sandbox (also in authorized_keys) and uses it for exec, files, background commands, setup, public URLs and the desktop. Each command, with its env values and any tokens, goes over the SSH session's input, never on a command line other processes could read. froog's operators run the machines and can reach any sandbox.
  • Public URLs are private by default (a token, then a cookie for that host) and live on a separate domain, froogusercontent.com, so a page in a sandbox never shares cookies with froogcorp.com. Desktop links carry their token after the # and must be opened within 10 minutes.

Secrets and data

Account and per-sandbox variables, secret files, the setup script, telemetry headers and each sandbox's SSH keys are encrypted at rest on the control plane (XChaCha20-Poly1305). Inside a sandbox, variables and secret files are plain files on its disk, and so in its snapshots.

DataKept
A running sandbox's diskUntil you stop or delete it. Automatic snapshots every hour and at each stop, the 3 newest kept.
A stopped sandbox's disk14 days, then deleted (snapshot_data_expired).
Saved snapshotsUntil you delete them, also after their sandbox is deleted.
Command history and output90 days, up to 512 MiB per account. Deleted with the sandbox. Not kept at all with monitoring off.
Process samples and metrics history7 days. Deleted with the sandbox.
Process records72 hours after the process ends. Deleted with the sandbox.
A deleted sandboxIts VM, disk and automatic snapshots are deleted.

Snapshots live on the machine that runs the sandbox, and are also copied off that machine to separate storage, encrypted, usually within minutes of being taken: saved snapshots, the snapshot taken when a sandbox stops, and the newest automatic snapshot of a running one. If the machine fails, a sandbox comes back from that copy. Changes made since the last snapshot are only on the machine, so keep work you can't lose in git or download it. With zero data retention nothing is copied. The control plane's database (accounts, encrypted secrets, command history) is backed up every hour, encrypted, to storage in another location, and backups are kept up to 12 months. Data controls turn off history, snapshots, or everything after a stop.

Report a security problem to hello@froog.tech, and abuse coming from a sandbox to the same address with "Abuse" in the subject.