From 949e975b0f3462ff6fc32c87266bb0b1896fda61 Mon Sep 17 00:00:00 2001 From: Nicky Leach Date: Thu, 27 Aug 2026 09:25:06 -0700 Subject: [PATCH] docs(sandbox-providers): state the sandbox security boundary (#12286) ## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - Sandbox providers run agent work in isolated environments > - The Daytona documents described a command wrapper that the provider no longer uses > - Those documents therefore described a control that the code does not have > - This pull request states the real sandbox boundary and the controls for paths that cross it > - The benefit is accurate security guidance for sandbox provider authors and operators ## Linked Issues or Issue Description **Issue type** Outdated (no longer matches behavior). **Where is the issue?** `packages/plugins/sandbox-providers/SANDBOX-REQUIREMENTS.md` and `packages/plugins/sandbox-providers/daytona/README.md`. **What's wrong?** The Daytona provider no longer uses the documented command wrapper, package installation commands, or sudoers rule. The requirements document also lacked a clear statement of the sandbox security boundary. **Suggested fix** State that the sandbox provides the boundary. Name outbound workspace synchronization and the application programming interface bridge as the paths that cross the boundary. State that a provider must not map a host path into a sandbox synchronization path. ## What Changed - Replace stale wrapper requirements with the actual sandbox security boundary. - State the controls that apply to outbound workspace synchronization and the application programming interface bridge. - State that this repository does not enforce the provider path-mapping duty today. - Remove obsolete Daytona package-install commands and the sudoers rule. ## Verification - Confirm the difference contains the two documentation files and the test file changed by the follow-up fix. - Confirm that no unrelated source, configuration, or fixture file appears in the difference. - Run the repository continuous integration checks and confirm that every required check passes. - Run the repository review bot and confirm its final verdict. ## Risks Low risk. This pull request changes two documents and closes a database client in one integration test. It does not change product runtime behavior or configuration. ## Model Used OpenAI Codex, GPT-5, with tool use and code execution. The model produced the documentation change and the pull request text. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes: #` / `Refs: #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run the affected test locally; continuous integration provides complete test verification. - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip --- .../sandbox-providers/SANDBOX-REQUIREMENTS.md | 194 ++++++++++++++++-- .../sandbox-providers/daytona/README.md | 79 ------- 2 files changed, 173 insertions(+), 100 deletions(-) diff --git a/packages/plugins/sandbox-providers/SANDBOX-REQUIREMENTS.md b/packages/plugins/sandbox-providers/SANDBOX-REQUIREMENTS.md index 07eeb9acee..e314c1ab1b 100644 --- a/packages/plugins/sandbox-providers/SANDBOX-REQUIREMENTS.md +++ b/packages/plugins/sandbox-providers/SANDBOX-REQUIREMENTS.md @@ -6,31 +6,183 @@ exec time. The environment is a requirement, not a build step. This document states requirements. It does not state build steps. -## bwrap prerequisites (advisory, optional) +## Security boundary -A sandbox provider can wrap a command with an advisory bubblewrap (`bwrap`) -wrapper. The wrapper is advisory, best-effort, and automatic. It adds no -security. The ephemeral sandbox model stays the only security posture. A missing -prerequisite degrades to the plain command. It never fails the lease. Daytona is -the current provider with bwrap support. +Paperclip runs agent work inside a sandbox. Paperclip protects the host from +the code in that sandbox. This section states the rule for that protection. It +does not state the implementation. -The wrapper needs three run-time prerequisites. Each prerequisite is a fact of -the image or snapshot, not a fact of the runtime code. The runtime does not -build the image or snapshot. The runtime only probes for the capability and -degrades when the capability is absent. So each prerequisite is an owner -responsibility under the requirement-not-build contract above: +A sandbox is an untrusted execution environment. Paperclip assumes that a +sandbox process can read or change all accessible data. -- The `bubblewrap` package is installed, and the `bwrap` binary is on the PATH - (normally `/usr/bin/bwrap`). -- A passwordless `sudo` rule lets the sandbox user run `bwrap` as root. -- The host and kernel allow an unprivileged user namespace. +Paperclip does not protect sandbox files, processes, credentials, or code from +other code in the same sandbox. -The owner supplies these prerequisites through the image or snapshot. The -provider README states the distro-specific install commands, the exact sudoers -rule, the user-namespace setting, and the verification command. The install and -the sudoers change are environment provisioning at the image or snapshot layer. -Route them to DevOps through the board. Do not add a provisioning script to the -repository. +This section covers sandbox providers. It does not cover a local run on the +host. A local run has a different boundary. + +### What the boundary protects + +Paperclip protects two authorities across the boundary: + +- The authority to write host files +- The authority to call the Paperclip API + +Sandbox code holds each authority through one surface only: + +1. **Outbound workspace synchronization.** Paperclip copies sandbox files to + host paths that the Paperclip orchestrator selects. +2. **The Paperclip HTTP bridge.** Sandbox code calls the Paperclip API through + the bridge. + +A boundary control limits one of these two authorities. A control that only +protects data inside the sandbox is not a boundary control. A control that only +manages resource use is not a boundary control. + +### Provider isolation assumption + +The rule below depends on this assumption. + +The sandbox provider must isolate the sandbox from the host and the provider +control plane. The provider must isolate these items from direct sandbox access: + +- Host files +- Host credentials +- Cluster credentials +- Management sockets +- Provider management interfaces + +The provider must use isolated sandbox storage for each sandbox path that +synchronization uses. This includes workspace paths and staging paths. + +The provider must keep every host path outside a sandbox synchronization path. +A host path inside a synchronization path makes host files available to sandbox +code. Sandbox code can then change host files, and no synchronization control +applies to the change. This removes the boundary. + +A transfer and sandbox code must have the same read authority over sandbox +files. More transfer authority can turn a sandbox symbolic link into a way to +read a protected file. + +This repository does not enforce these provider rules today, and Paperclip +cannot verify them for an externally supplied sandbox. + +The provider and the operator set the policy for general internet access. +Paperclip does not enforce this policy inside the sandbox. + +### How to apply this rule + +The test is authority, not location. A change is a boundary change only in one +of these two conditions: + +- The change modifies one of the two authorities above. +- The change makes the provider isolation assumption false. A change that + exposes a management socket to the sandbox is an example. + +A boundary change needs a boundary review. A reviewer must examine the change +against this contract. This section does not remove any other review of a +change. + +The test gives these results: + +- Code inside the sandbox can modify these authorities. The in-sandbox part of + synchronization and the in-sandbox part of the bridge are examples. +- A change that meets neither condition above is not a boundary change. This is + true when the change removes a control inside the sandbox. +- A developer can remove a control that only protects data inside the sandbox. + A developer can also change the mechanism of a boundary control. The authority + of sandbox code must stay the same or decrease. +- A requested control is a boundary security requirement only if the control + limits one of the two authorities above. + +A change creates a new boundary surface in either of these conditions: + +- The change lets sandbox code write host files outside workspace + synchronization. +- The change lets sandbox code call the Paperclip API outside the HTTP bridge. + +The developer must update this contract before the change is released. A +reviewer must examine the change against this contract. + +### Where a boundary control must run + +Paperclip or the provider must enforce each boundary control outside the +sandbox. Sandbox code can change a control that runs inside the sandbox. A +control inside the sandbox can give an early error message, but it gives no +protection at the boundary. + +This rule applies to enforcement. It does not apply to the tools that create or +move data. A tool inside the sandbox can create data, and a control outside the +sandbox validates that data. The outbound archive is an example. The sandbox +creates the archive. The host validates each member before extraction. + +Each boundary control below must run outside the sandbox. + +### Surface 1: outbound workspace synchronization + +These boundary controls limit the authority of sandbox code over host files. The +synchronization implementation must: + +- Accept only source and destination mappings that the orchestrator supplies. +- Keep host destinations in the specified host workspace or asset roots. +- Reject path traversal and symbolic links that escape a host destination root. +- Validate archive member paths and link targets before extraction on the host. +- Handle sandbox file contents only as data during synchronization. + +Native synchronization hooks and the command fallback must meet the same +requirements. + +Synchronization also confines each sandbox source path to a synchronization +root. A path check outside the sandbox is lexical, and only a check inside the +sandbox resolves the symbolic links on the path. The check inside the sandbox is +not a boundary control. It gives an early error. + +Sandbox source confinement is safe as an early check, because a transfer reads a +sandbox source with the authority of sandbox code. The bytes that cross the +boundary are bytes that sandbox code can already read. The provider isolation +assumption above states this rule for the provider. + +These requirements protect host reliability and host resources. They are not +boundary controls: + +- Use atomic replacement for each single-file mapping. +- Move file data with bounded memory. + +### Surface 2: Paperclip HTTP bridge + +Sandbox code must call the Paperclip API only through the HTTP bridge. + +These boundary controls limit the API authority of sandbox code. The bridge +must: + +- Accept only requests that have valid bridge authentication. +- Limit bridge authentication to bridge access. +- Use only the run agent's API authority for each request. +- Permit only approved HTTP methods and routes. +- Forward only approved request headers. +- Add the correct run identity to each request. + +These requirements protect host reliability and host resources. They are not +boundary controls: + +- Limit request size, response size, and request time. +- Limit the queue length of the file-queue transport. +- Limit the number of concurrent requests on the bidirectional channel. + +All other HTTP bridge requirements apply to both transports. + +### What is not a boundary surface + +Paperclip sends commands from the host to the sandbox. Command execution can +return output to the host. This output does not give sandbox code authority to +write host files or call the Paperclip API. + +The host records this output as run logs and reads it as agent protocol +messages. Neither use gives sandbox code one of the two authorities above. + +A persistent process session stays in the sandbox. A bidirectional channel is a +transport. Sandbox authority stays limited to outbound workspace synchronization +and the HTTP bridge. ## Required on PATH diff --git a/packages/plugins/sandbox-providers/daytona/README.md b/packages/plugins/sandbox-providers/daytona/README.md index aee264d183..facdc7526c 100644 --- a/packages/plugins/sandbox-providers/daytona/README.md +++ b/packages/plugins/sandbox-providers/daytona/README.md @@ -29,85 +29,6 @@ Notes: - The driver supports both `snapshot`-based and `image`-based sandbox creation. If both are set, validation rejects the config as ambiguous. - Reusable leases map to Daytona stop/start semantics. Non-reusable leases are deleted on release. -## Advisory bwrap wrapper - -The driver wraps a sandbox command with an advisory bubblewrap (`bwrap`) wrapper. The wrapper is advisory, best-effort, and automatic. At lease time the driver probes the sandbox for the wrapper capability and records the result on the lease metadata. At execute time the driver wraps the command when the capability is present. The command builder is a pure function. - -- **The wrapper adds no security.** The ephemeral sandbox stays the only security posture. The wrapper only gives an agent real-time feedback when the agent tries to change a file that the ephemeral sandbox will not keep. -- **The read-only root is a feedback signal.** The wrapper binds the root as read-only (`--ro-bind / /`) and re-binds only the writable directories. A write to a path outside the writable set fails at once, so the agent learns the change is not durable. -- **A capability probe records the wrapper capability.** No configuration field turns it on. At lease time the driver reads the sandbox username with `id -un`, then probes the end-to-end `bwrap` capability by running `sudo -n bwrap` with a workspace bind and an `su` user switch. It stores `bwrapAvailable` and `sandboxUsername` on the lease metadata. -- **The probe is best-effort.** A missing `bwrap` binary, a missing passwordless `sudo -n` rule, a missing `su` binary, or an inaccessible workspace bind records `bwrapAvailable: false` and never fails the lease. -- **The writable set is the workspace plus the read-write sync destinations.** The wrapper binds the workspace directory read-write as the baseline; the workspace is always durable. It adds the read-write sync destinations that a sync-in recorded for the same lease. The set deduplicates the directories. The baseline keeps a safe result even when the collected set is empty. -- **The wrapper runs at execute time when the capability is present.** The driver wraps the command only when the lease reports `bwrapAvailable: true` and a username is known. It binds the workspace and the read-write sync destinations, keeps the root read-only for feedback, and re-binds the stdin file after the fresh `/tmp`. It runs the plain command when the capability or the username is missing. A wrap without a username would run as root and give the agent's files root ownership, so the driver keeps the plain command in that case. - -## Operator enablement (advisory bwrap) - -The advisory `bwrap` wrapper needs three run-time prerequisites on the image or -snapshot. The repository does not build the Daytona image or snapshot. It -references an external `image` or `snapshot`. So the three prerequisites are -image facts, not code facts. The runtime only probes for the capability and -degrades when the capability is absent. - -The wrapper is advisory, best-effort, and automatic. It adds no security. The -ephemeral sandbox model stays the only security posture. A missing prerequisite -degrades to the plain command. It never fails the lease. So the enablement below -is optional. It gives the agent real-time feedback on a non-durable write. It -does not change the security posture. - -The install and the sudoers change are environment provisioning at the image or -snapshot layer. Route them to DevOps through the board. Do not run the steps -from the runtime and do not commit a provisioning script to the repository. - -### 1. Install the `bubblewrap` package - -The repository does not state the Daytona base distribution. Confirm the -distribution on the referenced image or snapshot first, then run the matching -command: - -```bash -# Debian/Ubuntu -apt-get install -y bubblewrap -# Alpine -apk add bubblewrap -# Fedora/RHEL -dnf install -y bubblewrap -``` - -Confirm the binary path is `/usr/bin/bwrap` after the install. - -### 2. Add the passwordless sudoers rule - -The wrapper runs `bwrap` as root with `sudo -n`. Add this exact sudoers line. -Use the real sandbox user name and the real `bwrap` path: - -```text - ALL=(root) NOPASSWD: /usr/bin/bwrap -``` - -The `` is the account name that `id -un` returns inside the -sandbox. Use the account name, not a numeric id, in the sudoers line. The probe -reads the username with `id -un`. The driver resolves the sandbox work directory -first, then the user home directory. It uses `/home/daytona` only as a fallback -default when both are empty. Confirm the real home directory for your image or -snapshot. Install the `sudo` and `util-linux` (for `su`) packages in the image -or snapshot if they are absent. - -### 3. Verify the prerequisites - -Run this exact command as the sandbox user, replacing `` and -`` with real values: - -```bash -sudo -n bwrap --ro-bind / / --bind-try -- su -s /bin/sh -c true -``` - -A zero exit code means all prerequisites are met. A non-zero exit code means one -prerequisite is missing. The wrapper then stays off and runs the plain command. - -The probe binds the workspace directory and switches to the sandbox user with -`su`. This matches the exact invocation the live wrapper uses, so a passing probe -guarantees that execution commands will also succeed. - ## Local development ```bash