Skip to content

PROPOSAL: Sandboxed Agent Execution — provider-agnostic interface for secure remote environments #248

Description

@Konan69

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:

  1. Webhook ingestion — GitHub events create Paperclip issues
  2. Triage agent (in sandbox) — classifies PRs/issues as valid, duplicate, spam, needs-info
  3. Review agent (in sandbox) — deeper code review alongside Greptile
  4. 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

  1. Define SandboxProvider interface in packages/adapter-utils
  2. Implement E2B provider as first target (official Claude Code template)
  3. Build SandboxAdapter that composes provider + existing auth patterns
  4. Register in adapter system (server/ui/cli registries, shared constants)
  5. Add Cloudflare/Daytona providers as follow-ups
  6. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions