Skip to content

Bash-Sandbox auf macOS (sandbox-exec) und Linux (bubblewrap) #30

Description

@webmatze

Priorität: 3 — ambitioniert, aber die eigentliche Antwort auf Approval-Fatigue und ein echtes Alleinstellungsmerkmal für ein lokales Harness. Setzt das Permissions-Issue voraus.

Referenz: Claude Code v2.0.24 (Sandbox-Modus für BashTool auf Linux & macOS), v2.0.30 (allowUnsandboxedCommands), v2.1.187 (sandbox.credentials), v2.1.216 (Dateisystem-Isolation abschaltbar bei erhaltener Netzkontrolle), v2.1.219 (strikte Netzwerk-Allowlist), v2.1.221 (File-Masking), v2.1.224 (Credential-Masking) — dass Anthropic hier über zehn Releases nachgeschärft hat, zeigt zugleich, wie fehleranfällig das Thema ist.

Motivation

Das Approval-Modell hat eine unangenehme Eigenschaft: Es fragt bei jedem mutierenden Call. In der Praxis führt das dazu, dass Nutzer nach kurzer Zeit --yes setzen — und damit jede Schutzwirkung aufgeben. Feinere Regeln (Permissions-Issue) mildern das, lösen es aber nicht: Sie beschreiben, was erlaubt ist, erzwingen es aber nicht auf Betriebssystemebene.

Eine Sandbox dreht das Verhältnis um: Statt bei jedem Schreibzugriff zu fragen, wird bash in einer Umgebung ausgeführt, in der ein Ausbruch aus dem Projektverzeichnis oder ein unerwarteter Netzzugriff technisch nicht möglich ist. Dann kann man die meisten Kommandos bedenkenlos ohne Nachfrage laufen lassen.

Für ein Werkzeug, das sich als „local-first" positioniert, ist das ein starkes Argument: Der Nutzer gibt einem Agenten Shell-Zugriff, ohne die Maschine preiszugeben.

Spezifikation

Plattformen

Plattform Mechanismus
macOS sandbox-exec mit generiertem SBPL-Profil
Linux bubblewrap (bwrap), falls vorhanden; sonst nicht verfügbar
sonst nicht verfügbar

Kein eigener Kernel-Kram, keine Container-Abhängigkeit. Ist der Mechanismus nicht verfügbar, bleibt es beim heutigen Approval-Verhalten — mit einem klaren Hinweis, dass die Sandbox inaktiv ist. Ein Feature, das vorgibt zu schützen, es aber nicht tut, ist gefährlicher als keines.

Konfiguration

[sandbox]
enabled = false                # Default: aus, Opt-in
filesystem = true              # Schreibzugriff auf Projekt + tmp beschränken
network = "deny"               # deny | allow | allowlist
network_allowlist = ["registry.npmjs.org", "github.com"]
writable = [".", "/tmp"]       # zusätzliche Schreibpfade
allow_unsandboxed = true       # darf ein Call die Sandbox explizit umgehen?

Verhalten

  • Gilt zunächst nur für bash. write_file/edit_file laufen weiter über Permission-Regeln — dort ist der Pfad bekannt und prüfbar, eine Sandbox bringt wenig zusätzlichen Schutz.
  • Bei aktiver Sandbox können Kommandos ohne Nachfrage laufen ([approval] mode = "auto" wird dadurch vertretbar). Das ist der eigentliche Gewinn und sollte im README so erklärt werden.
  • Escape-Hatch: Ein Tool-Parameter sandbox: false erlaubt einem einzelnen Call den Ausbruch — immer mit Approval-Prompt, unabhängig vom Modus, und abschaltbar über allow_unsandboxed = false (CC v2.0.30).

macOS-Profil (Skizze)

(version 1)
(deny default)
(allow process-exec process-fork)
(allow file-read*)                                  ; Lesen breit erlauben
(allow file-write* (subpath "/path/to/project"))
(allow file-write* (subpath "/tmp"))
(deny file-read* (subpath "/Users/x/.ssh"))         ; Credentials trotz Lesefreigabe sperren
(deny network*)

Anmerkungen:

  • Lesen breit zu erlauben ist pragmatisch — Compiler und Toolchains lesen an vielen Stellen. Der Schutz liegt auf Schreiben und Netz.
  • Credential-Pfade (~/.ssh, ~/.aws, ~/.config/gh, .env) müssen trotzdem explizit gesperrt werden, sonst kann ein Kommando Secrets lesen und über einen erlaubten Netzpfad exfiltrieren. Das ist genau der Punkt, den CC in v2.1.187 und v2.1.224 nachgezogen hat.
  • sandbox-exec ist von Apple als deprecated markiert, funktioniert aber weiterhin und wird von anderen Werkzeugen genutzt. Das Risiko ist zu dokumentieren.

Linux (bubblewrap)

bwrap --ro-bind / / --bind <project> <project> --bind /tmp /tmp \
      --unshare-net --dev /dev --proc /proc -- <command>

Netz-Allowlist ist mit --unshare-net nur als „ganz aus" umsetzbar. Für allowlist bräuchte es einen Proxy im Namespace — das ist eine Ausbaustufe, nicht Teil dieses Issues. Stufe 1 unterstützt deny und allow; allowlist wird auf macOS ebenfalls zunächst als deny behandelt und muss dann eine klare Warnung ausgeben statt stillschweigend etwas anderes zu tun.

Umsetzung

Neue Dateien

src/smith/sandbox.cr             # Abstraktion + Verfügbarkeitsprüfung
src/smith/sandbox/macos.cr       # SBPL-Generierung, sandbox-exec
src/smith/sandbox/linux.cr       # bwrap-Argumente
module Smith::Sandbox
  abstract class Backend
    abstract def available? : Bool
    abstract def wrap(command : String, settings : Settings) : Array(String)
  end

  def self.detect : Backend?
end

Änderungen

  • src/smith/tools/bash.cr: Kommando durch das Backend wrappen; sandbox-Parameter
  • src/smith/config.cr: [sandbox]-Sektion
  • src/smith/cli.cr: Verfügbarkeit prüfen, Status im Banner (🔒 Sandbox: macOS (network: deny) bzw. deutlicher Hinweis bei Nichtverfügbarkeit trotz enabled = true)

Tests (spec/sandbox_spec.cr)

Die Profilgenerierung ist plattformunabhängig testbar; die tatsächliche Durchsetzung nur auf der jeweiligen Plattform (in CI entsprechend markieren/überspringen).

  • SBPL enthält die konfigurierten Schreibpfade und die Credential-Deny-Regeln
  • bwrap-Argumente korrekt zusammengesetzt
  • Projektpfad mit Leerzeichen wird korrekt gequotet
  • available? liefert auf einer Plattform ohne Backend false
  • enabled = true ohne Backend → Warnung, Ausführung ungesandboxt, nicht stiller Weiterlauf
  • sandbox: false erzwingt einen Approval-Prompt auch bei mode = "auto"
  • allow_unsandboxed = false lehnt sandbox: false ab
  • Integrationstest (nur macOS/Linux): Schreibversuch außerhalb des Projekts schlägt fehl; Schreiben im Projekt gelingt; Netzzugriff bei network = "deny" schlägt fehl

Akzeptanzkriterien

  • macOS- und Linux-Backend, sauberes Fallback auf anderen Plattformen
  • Nichtverfügbarkeit wird laut gemeldet, nie stillschweigend übergangen
  • Credential-Pfade sind auch bei breitem Lesezugriff gesperrt
  • Escape-Hatch nur mit Approval und abschaltbar
  • allowlist wird nicht vorgetäuscht, solange sie nicht umgesetzt ist
  • Integrationstests belegen die tatsächliche Durchsetzung auf mindestens einer Plattform
  • README-Abschnitt „Sandbox" inkl. ehrlicher Grenzen und Deprecation-Hinweis zu sandbox-exec

Nicht-Ziele

  • Vollständige Container-Isolation
  • Sandboxing der Datei-Tools (dort greifen Permission-Regeln)
  • Netz-Allowlist über einen Proxy (Ausbaustufe)

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestprio:3Gross, strategisch, spaeterready-for-agentFully specified, ready for an AFK agentroadmapTeil der Claude-Code-Feature-Analyse

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions