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
Nicht-Ziele
- Vollständige Container-Isolation
- Sandboxing der Datei-Tools (dort greifen Permission-Regeln)
- Netz-Allowlist über einen Proxy (Ausbaustufe)
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
--yessetzen — 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
bashin 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
sandbox-execmit generiertem SBPL-Profilbubblewrap(bwrap), falls vorhanden; sonst nicht verfügbarKein 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
Verhalten
bash.write_file/edit_filelaufen weiter über Permission-Regeln — dort ist der Pfad bekannt und prüfbar, eine Sandbox bringt wenig zusätzlichen Schutz.[approval] mode = "auto"wird dadurch vertretbar). Das ist der eigentliche Gewinn und sollte im README so erklärt werden.sandbox: falseerlaubt einem einzelnen Call den Ausbruch — immer mit Approval-Prompt, unabhängig vom Modus, und abschaltbar überallow_unsandboxed = false(CC v2.0.30).macOS-Profil (Skizze)
Anmerkungen:
~/.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-execist von Apple als deprecated markiert, funktioniert aber weiterhin und wird von anderen Werkzeugen genutzt. Das Risiko ist zu dokumentieren.Linux (bubblewrap)
Netz-Allowlist ist mit
--unshare-netnur als „ganz aus" umsetzbar. Fürallowlistbräuchte es einen Proxy im Namespace — das ist eine Ausbaustufe, nicht Teil dieses Issues. Stufe 1 unterstütztdenyundallow;allowlistwird auf macOS ebenfalls zunächst alsdenybehandelt und muss dann eine klare Warnung ausgeben statt stillschweigend etwas anderes zu tun.Umsetzung
Neue Dateien
Änderungen
src/smith/tools/bash.cr: Kommando durch das Backend wrappen;sandbox-Parametersrc/smith/config.cr:[sandbox]-Sektionsrc/smith/cli.cr: Verfügbarkeit prüfen, Status im Banner (🔒 Sandbox: macOS (network: deny)bzw. deutlicher Hinweis bei Nichtverfügbarkeit trotzenabled = 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).
available?liefert auf einer Plattform ohne Backendfalseenabled = trueohne Backend → Warnung, Ausführung ungesandboxt, nicht stiller Weiterlaufsandbox: falseerzwingt einen Approval-Prompt auch beimode = "auto"allow_unsandboxed = falselehntsandbox: falseabnetwork = "deny"schlägt fehlAkzeptanzkriterien
allowlistwird nicht vorgetäuscht, solange sie nicht umgesetzt istsandbox-execNicht-Ziele