From b9eabc4f092acb54631f5765850c193092dc7c0d Mon Sep 17 00:00:00 2001 From: Brett Kinny Date: Thu, 29 Oct 2026 14:37:18 +1000 Subject: [PATCH] docs: propose egress allowlist, tabulate runtime controls, compare sandboxes - ADR 0011 (Proposed): opt-in egress allowlist enforced by a proxy outside the Box, with the operator list never mounted into the Box. - SECURITY.md: per-control table (default, knobs, risk, recommendation). - docs/comparison.md: draft comparison with dev containers and AI-agent sandboxes. Refs #183 Co-Authored-By: Claude Opus 5.5 --- SECURITY.md | 19 +++++ docs/adr/0011-opt-in-egress-allowlist.md | 97 ++++++++++++++++++++++++ docs/comparison.md | 70 +++++++++++++++++ 3 files changed, 186 insertions(+) create mode 100644 docs/adr/0011-opt-in-egress-allowlist.md create mode 100644 docs/comparison.md diff --git a/SECURITY.md b/SECURITY.md index 026b6b4..2a2962d 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -270,6 +270,25 @@ The `dev` user can invoke passwordless package-management/install commands. inside the Box, so the sudo allowlist is an operational control, not a security barrier against a malicious Box user. +### Runtime controls at a glance + +Each row is a control that shapes what code running in the Box can reach. The +sections below give the details. + +| Control | Default | What you can change | Risk if relaxed or misused | Recommendation | +| --- | --- | --- | --- | --- | +| Linux capabilities | All dropped, then `CHOWN`, `DAC_OVERRIDE`, `FOWNER`, `SETUID`, `SETGID`, `KILL` re-added (Dev Container also adds `SYS_CHROOT`). | Only by editing Compose, `devcontainer.json`, or the runtime command yourself. The adapters expose no setting for this. | Extra capabilities such as `SYS_ADMIN` or `NET_ADMIN` widen the host kernel surface that container root can reach. | Keep the default set. | +| PID limit | `4096`. | Same as capabilities. | Without a limit, a fork bomb in the Box can exhaust the host's process table. | Keep the limit. | +| Package-management sudo | Passwordless `apt-get`, `apt-mark`, `dpkg`, `chown`, and `install` for `dev`, plus narrow `mv`/`rm` forms for staged `/usr/local/bin` promotion. | Not configurable. | This is effectively root inside the Box. It is not a barrier. | Treat every Box process as able to become root inside the Box. | +| Workspace mount | Read-write at `/workspace`. | Choose the host directory at install time. | Box processes can modify or delete project files, including `.git/hooks` and other config that host tools later run. | Push work regularly, and check `.git/hooks` and build scripts before running them on the host after an unattended session. | +| Managed home | Persistent volume holding history, `gh` auth, assistant logins, and SDKs. | Not configurable. | Any Box process can read every persisted token. | Use fine-grained, narrowly scoped tokens. Revoke them if the Box may be compromised. | +| Git identity | Private name/email config only. The host's Git config and credential helpers are never mounted. | Not configurable. | — | — | +| SSH access | Agent socket plus read-only `config`/`known_hosts` when an agent is available (Bash adapters). Otherwise none. | `SQUAREBOX_MOUNT_SSH=1` / `-MountSsh` mounts `~/.ssh` read-only when no agent is forwarded. | The opt-in exposes private keys to every Box process. A forwarded agent signs for any Box process while it is available. | Use an agent with per-use confirmation, or a dedicated narrow-scope key. Leave the directory mount off. | +| Network egress | Unrestricted outbound. The Box publishes no ports. | Not yet. An opt-in allowlist is proposed in [ADR 0011](docs/adr/0011-opt-in-egress-allowlist.md). | Any reachable host can receive Workspace content or tokens. On cloud VMs, `169.254.169.254` can hand out instance credentials. | Don't give unattended assistants credentials or Workspace content you couldn't afford to have exfiltrated. | +| Unattended assistants | Off. The `*-yolo` aliases skip approval prompts only when you invoke them. | Use them or not, per invocation. | They combine every exposure in this table with no human in the loop. | Prefer approval modes. Use `*-yolo` only in a Box whose Workspace, tokens, and SSH access are scoped for it. | +| Rootless Podman SELinux | `--security-opt label=disable` for the Box. | Not configurable. | SELinux container separation is off. Host file permissions and the declared mounts are the only boundary. | Validate on the target host before using sensitive credentials. | +| Additional mounts | None beyond those listed above. | Add your own through Compose, Dev Container config, or the runtime command. | Every added mount is fully exposed to Box processes. | Mount the narrowest path you can, and read-only where possible. | + Dev Container and Codespaces builds add the digest-locked official SSH server Feature to the derived development image; the published Squarebox Candidate does not contain that server. The upstream Feature enables root login in its diff --git a/docs/adr/0011-opt-in-egress-allowlist.md b/docs/adr/0011-opt-in-egress-allowlist.md new file mode 100644 index 0000000..d420083 --- /dev/null +++ b/docs/adr/0011-opt-in-egress-allowlist.md @@ -0,0 +1,97 @@ +# ADR 0011: Offer an opt-in egress allowlist enforced outside the Box + +Status: Proposed + +## Context + +The Box has unrestricted outbound network access. AI assistants can run +unattended inside it (the `*-yolo` aliases), and they can read the Workspace +and the credentials persisted in the Managed home. Any reachable host is +therefore a path for exfiltrating source, tokens, or conversation history, and +on cloud hosts `169.254.169.254` can hand out instance credentials. + +Setting `HTTP_PROXY`/`HTTPS_PROXY` inside the Box is not a control: any process +can ignore those variables. Enforcement only holds if the proxy is the sole +network path out of the Box, and the allowlist lives where Box processes +cannot edit it. NVIDIA OpenShell uses this shape (a per-sandbox network +namespace whose only route is a policy-checking CONNECT proxy). + +The Box still has to install and update tools at runtime: `setup.sh`, +`sqrbx-update`, mise SDK backends, npm assistants, the Claude installer, and +Box-tier APT reconciliation all need the network. A mode that breaks them is +not usable. + +## Decision + +Add an opt-in egress mode selected at install or rebuild time and recorded in +the Install identity: + +- `SQUAREBOX_EGRESS=open` (default): current behavior. +- `SQUAREBOX_EGRESS=audit`: all traffic goes through the proxy and is allowed, + but requests not on the allowlist are logged as would-be denials. +- `SQUAREBOX_EGRESS=allowlist`: requests not on the allowlist are refused. + +Native PowerShell takes the same values through `-Egress`. Any other value +fails before lifecycle mutation. + +In `audit` and `allowlist` modes the adapter creates, as Managed resources +labeled with the Install identity: + +- an `internal` network with no route off the host, which is the Box's only + network; +- a proxy container attached to both that network and an egress network, + whose image is pinned by digest in the Candidate like other image inputs. + +The Box gets `HTTP_PROXY`/`HTTPS_PROXY`/`NO_PROXY` pointing at the proxy for +convenience, but enforcement does not depend on them. The proxy filters +CONNECT and plain HTTP by destination hostname and port. It does not terminate +TLS and never sees request bodies or credentials. + +The proxy always refuses loopback, link-local (including `169.254.169.254`), +and unspecified addresses after DNS resolution, whatever the allowlist says. +Private RFC 1918 destinations are refused unless an exact hostname is listed. + +The effective allowlist is the union of: + +1. a Squarebox-owned default list shipped with the Candidate, covering the + hosts that Squarebox's own setup, update, and reconcile flows contact + (derived from `scripts/lib/tools.yaml`, the APT sources, mise backends, the + npm registry, and supported assistant API hosts); +2. an operator list at `/.squarebox/egress-allowlist`, one + hostname or `*.suffix` pattern per line. + +The operator list is mounted read-only into the proxy only. It is never +mounted into the Box and never stored in the Workspace or Managed home, so an +assistant cannot widen its own access. Proxy logs are readable from the host +with a lifecycle command (for example `sqrbx-egress log`). + +The Box must not resolve external names directly; the proxy resolves them. +Acceptance tests must show that DNS lookups, direct IP connections, and +non-proxied TCP from inside the Box all fail in `allowlist` mode. + +Recording the mode requires a new Install identity format under ADR 0007: +`FORMAT=3` appends `EGRESS=open|audit|allowlist`. `FORMAT=2` and `FORMAT=1` +records read as `EGRESS=open`. The verifier and shared fixtures cover every +accepted format in all four adapters. + +## Consequences + +This makes egress a security control for operators who choose it, but the +SECURITY.md posture is unchanged: the Box remains a development environment, +not a hostile-code sandbox. Allowed hosts are still exfiltration paths. Most +code-hosting and package registries accept arbitrary uploads, and an agent with +a GitHub token can push data to any repository that token can write. + +Host-level filtering cannot restrict HTTP methods or paths, and cannot keep +credentials out of the Box. Both would need TLS termination with a per-Box CA, +which this ADR rejects as too invasive for a development environment. + +Every new tool, SDK backend, or assistant can need a default-list update. +`audit` mode is the migration path: operators run in `audit`, review the +would-be denials, and then switch to `allowlist`. + +Compose and the Dev Container need equivalent definitions. GitHub Codespaces +controls its own networking, so this mode is not offered there. + +Rootless Podman needs internal-network and proxy coverage on Ubuntu CI and +manual UAT on Fedora with SELinux enforcing, as for other Podman changes. diff --git a/docs/comparison.md b/docs/comparison.md new file mode 100644 index 0000000..4534224 --- /dev/null +++ b/docs/comparison.md @@ -0,0 +1,70 @@ +# Squarebox compared with other environments and sandboxes + +> **Draft.** Last reviewed 2026-10-29. Several of these tools are pre-1.0 and +> change quickly. Check each project's own docs before relying on a cell. + +People reach for Squarebox, dev containers, and AI-agent sandboxes for +different jobs. Some give you a consistent, tool-rich environment. Others limit +what an agent can touch. A few do both. This page compares them on the +properties that matter when you let AI assistants run code. + +Squarebox is a portable development Box. It is not a hostile-code sandbox (see +[SECURITY.md](../SECURITY.md#container-authority-and-isolation)). + +## At a glance + +| Tool | Primary job | Isolation boundary | Outbound network | Credentials the agent can see | Workspace access | Runs on | +| --- | --- | --- | --- | --- | --- | --- | +| **Squarebox** | Portable dev environment with curated CLI/TUI tools and assistants | Container, with reduced capabilities and a PID limit | Unrestricted ([opt-in allowlist proposed](adr/0011-opt-in-egress-allowlist.md)) | Everything persisted in the Managed home; SSH agent socket if forwarded | Read-write bind mount | Docker or Podman on Linux, macOS, Windows; Compose; Dev Containers; Codespaces | +| **Dev Containers** (spec, VS Code) | Reproducible per-project dev environment | Container, configured per project | Unrestricted unless you configure it | Whatever the config and editor forward (Git credentials, SSH agent, env vars) | Read-write bind mount | Any Docker-compatible runtime | +| **GitHub Codespaces** | Hosted Dev Containers | Container on a dedicated cloud VM | No built-in allowlist | Codespaces secrets, exposed as environment variables; GitHub token | Repo clone on the VM | GitHub-hosted | +| **Docker Sandboxes** (`sbx`) | Run coding agents unattended | microVM with its own kernel | HTTP/HTTPS allowlist (`sbx policy allow`); raw TCP, UDP, and ICMP blocked | A host-side proxy injects credentials into requests, so the agent doesn't hold the raw values | Read-write mount by default; `--clone` gives a private copy | macOS (Apple silicon), Windows 11, Ubuntu 24.04+ with KVM | +| **Anthropic sandbox-runtime** (`srt`, used by Claude Code's sandbox) | Confine one process, with no container | OS sandbox: bubblewrap on Linux, Seatbelt on macOS | Domain allowlist through host-side HTTP/SOCKS proxies | Whatever the filesystem rules allow it to read | Filesystem allow/deny rules | Linux, macOS | +| **Container Use** (Dagger) | Parallel agents, each in its own branch | Container per agent, via Dagger | Not a focus | Whatever the container gets | Its own Git branch or worktree, reviewed through Git | Anywhere Dagger runs; MCP server for agents | +| **NVIDIA OpenShell** | Policy-governed runtime for fleets of agents | Container or VM, plus Landlock, seccomp, and a network namespace | Default deny; per-binary host rules with optional HTTP method/path rules | Provider credentials injected by a TLS-terminating proxy | Policy-defined filesystem access | Linux, macOS (Apple silicon), WSL 2; Kubernetes gateway | +| **Hosted agent sandboxes** (E2B, Daytona, and others) | Code-execution API for agent products | Firecracker microVM (E2B); varies by provider | Provider-specific | What your application passes in | Files uploaded through the API | Vendor cloud; Daytona can self-host | +| **Distrobox / Toolbx** | Run another distro's userland on the host | Container, deliberately well integrated with the host | Host network | Your host home directory, by default | Your whole host home directory | Linux | +| **Nix devshells / mise alone** | Pin toolchains per project | None | Host network | Everything your user can read | The host filesystem | Host OS | + +## Choosing + +- **You want the same terminal tools and assistants everywhere, and you trust + what runs in them:** use Squarebox, or Dev Containers if you prefer to build + your own image per project. +- **You want an agent to run unattended with a hard network and credential + boundary:** use Docker Sandboxes or OpenShell, or confine individual commands + with `srt`. Squarebox's `*-yolo` aliases don't give you this today. +- **You want several agents working in parallel without conflicts:** use + Container Use, or Git worktrees inside one Box. +- **You are building a product that runs model-generated code:** use a hosted + sandbox API. +- **You just want host-integrated tools from another distro:** use Distrobox or + Toolbx. They are not isolation. + +## What Squarebox borrows, and where it differs + +- Like Dev Containers, Squarebox is a container you reuse. It adds a + persistent Managed home and runs on Docker, Podman, Compose, Dev Containers, + and Codespaces. +- Unlike Docker Sandboxes and OpenShell, it doesn't yet enforce network egress + or keep credentials out of the Box. [ADR 0011](adr/0011-opt-in-egress-allowlist.md) + proposes host-level egress filtering. It deliberately does not include TLS + interception or credential injection. +- Unlike `srt`, it doesn't confine individual processes. Everything in the Box + shares the same access. +- Unlike hosted sandboxes, it runs on your own machine or server, and your + state stays in your own volume. + +## Sources + +- [Docker Sandboxes docs](https://docs.docker.com/ai/sandboxes/), + [security defaults](https://docs.docker.com/ai/sandboxes/security/defaults/), + [get started](https://docs.docker.com/ai/sandboxes/get-started/) +- [anthropic-experimental/sandbox-runtime](https://github.com/anthropic-experimental/sandbox-runtime) +- [dagger/container-use](https://github.com/dagger/container-use) +- [NVIDIA/OpenShell](https://github.com/NVIDIA/OpenShell) and its + [security best practices](https://docs.nvidia.com/openshell/latest/security/best-practices) +- [E2B vs Daytona comparison (third party)](https://www.morphllm.com/comparisons/e2b-vs-daytona) +- [Dev Containers specification](https://containers.dev/) +- [GitHub Codespaces docs](https://docs.github.com/en/codespaces) +- [Distrobox](https://distrobox.it/) and [Toolbx](https://containertoolbx.org/)