Summary
Paperclip needs a way to run agents in sandboxed, isolated environments to safely process untrusted input (e.g. GitHub issues, PRs) without risk of prompt injection compromising the host or leaking secrets.
This proposal introduces a provider-agnostic sandbox interface that lets operators bring their own sandbox runtime (E2B, Cloudflare Containers, Daytona, Fly.io Sprites, etc.) while Paperclip handles orchestration, auth, and lifecycle management.
Problem
Running agents that process untrusted external content (GitHub issues, PRs, webhook payloads) on the host machine is a security risk. A malicious payload embedded in an issue description could:
- Exfiltrate secrets from the agent's environment
- Execute arbitrary code on the host
- Compromise other agents or the control plane
Current adapters (claude_local, codex_local, process) all execute on the host with full environment access. The cursor_cloud plan partially addresses this but is locked to Cursor's infrastructure.
Proposed Architecture
1. SandboxProvider interface
A pluggable abstraction for sandbox runtimes:
interface SandboxProvider {
type: string;
create(opts: SandboxCreateOpts): Promise<SandboxInstance>;
destroy(instance: SandboxInstance): Promise<void>;
testConnection(config: Record<string, unknown>): Promise<SandboxTestResult>;
}
interface SandboxInstance {
id: string;
exec(command: string, opts?: ExecOpts): Promise<ExecResult>;
writeFile(path: string, content: string | Buffer): Promise<void>;
readFile(path: string): Promise<string>;
getEndpoint(): string; // URL for callbacks
status(): Promise<"running" | "stopped" | "error">;
}
Initial provider implementations:
- E2B — Official Claude Code template, Firecracker microVM isolation, ~$0.05/hr
- Cloudflare Sandbox — Edge-distributed containers, good for short-lived tasks
- Daytona — Docker-based, persistent state, GPU support
- Fly.io Sprites — Persistent Firecracker VMs with 100GB NVMe
2. SandboxAdapter (Paperclip adapter)
A new adapter type that composes a SandboxProvider with the existing adapter contract:
- Spins up a sandbox per heartbeat invocation
- Injects Paperclip env vars (
PAPERCLIP_API_KEY, PAPERCLIP_RUN_ID, etc.)
- Uses bootstrap token exchange (from the
cursor_cloud plan) for auth — no long-lived keys in the sandbox
- Streams logs back via the sandbox exec API
- Tears down sandbox on completion/timeout
- Optionally connects sandbox to a Tailscale ephemeral tailnet for private network access back to Paperclip
3. Networking layer (optional, Tailscale)
Paperclip already supports --tailscale-auth for private access. For sandboxes that need to reach back to a non-public Paperclip instance:
- Sandbox joins an ephemeral tailnet on creation
- Gets private access to Paperclip API without public exposure
- Network destroyed on sandbox teardown
- Tailscale's AI Gateway can proxy LLM API calls (keys never leave the gateway)
Research: Sandbox Provider Landscape
| Provider |
Isolation |
Claude Code? |
Persistence |
Price/hr (1vCPU) |
| E2B |
Firecracker microVM |
Official template |
Ephemeral |
$0.05 |
| Cloudflare Sandbox |
Container |
No official |
Loses state on idle |
~$0.072 |
| Daytona |
Docker |
Via Sandbox Agent SDK |
Persistent |
$0.067 |
| Fly.io Sprites |
Firecracker microVM |
Via Sandbox Agent SDK |
100GB NVMe |
Competitive |
| Northflank |
Kata/gVisor/Firecracker |
Via Sandbox Agent SDK |
Both |
$0.017 |
| Vercel Sandbox |
Firecracker microVM |
Via Sandbox Agent SDK |
Ephemeral |
$0.128 |
Note: Rivet Sandbox Agent SDK is a ~15MB binary that runs Claude Code, Codex, OpenCode, or Amp inside any sandbox via a unified HTTP API. Could be used as the execution layer inside sandboxes.
Use Case: Dogfooding — GitHub PR/Issue Triage Pipeline
The immediate motivating use case is using Paperclip to manage its own GitHub workflow:
- Webhook ingestion — GitHub events create Paperclip issues
- Triage agent (in sandbox) — classifies PRs/issues as valid, duplicate, spam, needs-info
- Review agent (in sandbox) — deeper code review alongside Greptile
- Action agent — closes duplicates, comments, merges (behind approval gates)
Running triage/review agents in sandboxes protects against prompt injection from untrusted issue content.
Implementation Path
- Define
SandboxProvider interface in packages/adapter-utils
- Implement E2B provider as first target (official Claude Code template)
- Build
SandboxAdapter that composes provider + existing auth patterns
- Register in adapter system (server/ui/cli registries, shared constants)
- Add Cloudflare/Daytona providers as follow-ups
- Optional: Tailscale ephemeral tailnet integration for private deployments
Open Questions
- Should sandbox lifecycle be per-heartbeat (ephemeral) or per-agent (persistent)?
- Should we vendor Rivet Sandbox Agent SDK or build our own execution layer?
- How should sandbox provider credentials be managed? (likely via existing company secrets)
- Do we need a separate
NetworkProvider interface or keep Tailscale as config-level option?
cc @cryppadotta @aaaaron @forgottenrunes
Summary
Paperclip needs a way to run agents in sandboxed, isolated environments to safely process untrusted input (e.g. GitHub issues, PRs) without risk of prompt injection compromising the host or leaking secrets.
This proposal introduces a provider-agnostic sandbox interface that lets operators bring their own sandbox runtime (E2B, Cloudflare Containers, Daytona, Fly.io Sprites, etc.) while Paperclip handles orchestration, auth, and lifecycle management.
Problem
Running agents that process untrusted external content (GitHub issues, PRs, webhook payloads) on the host machine is a security risk. A malicious payload embedded in an issue description could:
Current adapters (
claude_local,codex_local,process) all execute on the host with full environment access. Thecursor_cloudplan partially addresses this but is locked to Cursor's infrastructure.Proposed Architecture
1.
SandboxProviderinterfaceA pluggable abstraction for sandbox runtimes:
Initial provider implementations:
2.
SandboxAdapter(Paperclip adapter)A new adapter type that composes a
SandboxProviderwith the existing adapter contract:PAPERCLIP_API_KEY,PAPERCLIP_RUN_ID, etc.)cursor_cloudplan) for auth — no long-lived keys in the sandbox3. Networking layer (optional, Tailscale)
Paperclip already supports
--tailscale-authfor private access. For sandboxes that need to reach back to a non-public Paperclip instance:Research: Sandbox Provider Landscape
Note: Rivet Sandbox Agent SDK is a ~15MB binary that runs Claude Code, Codex, OpenCode, or Amp inside any sandbox via a unified HTTP API. Could be used as the execution layer inside sandboxes.
Use Case: Dogfooding — GitHub PR/Issue Triage Pipeline
The immediate motivating use case is using Paperclip to manage its own GitHub workflow:
Running triage/review agents in sandboxes protects against prompt injection from untrusted issue content.
Implementation Path
SandboxProviderinterface inpackages/adapter-utilsSandboxAdapterthat composes provider + existing auth patternsOpen Questions
NetworkProviderinterface or keep Tailscale as config-level option?cc @cryppadotta @aaaaron @forgottenrunes