Einen Agent Code ausführen lassen, ohne die eigene Maschine zu ruinieren
Vor einigen Monaten beobachtete ich, wie ein Agent entschied, dass der sauberste Weg, die "Testdatenbank zurückzusetzen", ein rm -rf auf einem Pfad war, den er aus einer Variable konstruiert hatte, die sich als leer herausstellte. Der Befehl, den er tatsächlich vorschlug, war rm -rf /$DIR, und $DIR war nichts. Ich bemerkte es, weil ich im Standard-Modus lief und er zuerst fragte. Ich klickte auf Nein, korrigierte das Skript und ging mit leicht zitternden Händen Kaffee kochen.
Das war auf meinem echten Laptop. Derselbe Rechner, auf dem meine SSH-Schlüssel liegen, mein ~/.aws/credentials, mein Stripe-Eingeschränkter-Schlüssel in einem .env zwei Verzeichnisse weiter oben, und die einzige Kopie eines Nebenprojekts, das ich noch nicht gepusht hatte. Der Agent war nicht böswillig. Er lag einfach falsch, so wie ein schneller, selbstsicherer Junior falsch liegt — mit dem Unterschied, dass er 200 Befehle pro Minute tippt und nie müde genug wird, um langsamer zu werden.
Was ich zu lange nicht verinnerlicht hatte: Die Gefahr liegt nicht darin, dass der Agent ausrastet. Es ist die langweilige Schnittmenge aus einem selbstsicheren falschen Befehl, einer Anmeldeinformation in einer Umgebungsvariable und einer Netzwerkverbindung, die das offene Internet erreichen kann. Man braucht keinen Bösewicht. Man braucht einen Unfall und einen Exfiltrationspfad — und die meisten Setups liefern beides standardmäßig mit.
Die Kurzfassung: Isolation ist ein Spektrum, kein Schalter. Die günstigste Schicht sind die eigenen Permission-Prompts des Agents. Die stärkste ist eine microVM mit eigenem Kernel. Für die tägliche Arbeit an Code, den du selbst geschrieben hast, möchtest du OS-Level-Schutz plus Permission-Gates. Für alles, was du nicht selbst geschrieben hast — ein zufälliges Repo, ein gescraptes Skript, Code von einem anderen Agent — brauchst du eine echte Grenze, die das Betriebssystem nicht überreden kann zu ignorieren. Im Folgenden die gesamte Leiter und wo ich auf jeder Sprosse wirklich stehe.
Das Unfall-Modell, nicht das Bösewicht-Modell
Wenn man das Threat-Modelling ehrlich betreibt, vereinfacht sich das Bild. Es gibt drei Dinge, die schiefgehen können, wenn ein Agent Code ausführt:
- Er zerstört lokalen Zustand. Löscht Dateien, überschreibt das Falsche, force-pushed über deinen Branch.
- Er liest ein Geheimnis und schickt es irgendwohin. Grepped
~/.ssh, findet ein Token in einer Env-Variable,curlt es zu einer Domain. Das ist das, was Leute unterschätzen. - Er führt Code aus, dem man nie vertrauen sollte. Das Post-Install-Skript einer Abhängigkeit, eine generierte Payload, ein Repo, das man sich "nur mal anschauen" wollte.
Permission-Prompts adressieren (1) und teilweise (3). Gegen (2) tun sie fast nichts, weil das Geheimnis zu dem Zeitpunkt, wenn ein Befehl ausgeführt wird, bereits in der Prozessumgebung steckt. Die Lösung ist also nicht "das eine Tool zu finden, das alles löst." Sondern: eine günstige Schicht stapeln, die dumme Zerstörung verhindert, und dann darunter eine echte Grenze hinzufügen für die Fälle, wo ein Prompt allein nicht ausreicht.
Sprosse eins: die eigenen Permission-Gates des Agents
Coding-Agents werden bereits mit einem Berechtigungsmodell geliefert, und das ist das günstigste Containment, das man hat. Claude Code beispielsweise hat verschiedene Permission-Modi: default (Lesevorgänge laufen frei, alles andere fragt nach), acceptEdits (Datei-Edits und eine Handvoll Dateisystem-Befehle wie mkdir, mv, cp werden innerhalb des Arbeitsverzeichnisses automatisch genehmigt), plan (nur Recherche, keine Edits), auto (ein separates Klassifikator-Modell prüft jede Aktion und blockiert Eskalationen), dontAsk (nur vorab genehmigte Tools laufen, für gesperrte CI), und bypassPermissions — das Flag --dangerously-skip-permissions, über das die Dokumentation unmissverständlich ist: "Verwende diesen Modus nur in isolierten Umgebungen wie Containern, VMs oder Dev-Containern ohne Internetzugang."
Diese Modi sind real und nützlich, aber man muss verstehen, was sie sind: eine Entscheidung, die bevor der Befehl ausgeführt wird getroffen wird, basierend auf dem Befehls-String und, im Auto-Modus, dem Urteil eines Modells. Das ist eine Policy-Schicht, keine Mauer. Sie kann irren, und ein kreativer Befehl kann mehr tun, als sein Name andeutet. Ich verlasse mich auf den plan-Modus für die Erkundung und default für alles, was die Infrastruktur berührt, aber ich behandle keinen von beiden als Sicherheitsgrenze für Code, dem ich nicht vertraue. (Ich habe über Claude Code Hooks als Schutzgeländer anderswo geschrieben — gleicher Vorbehalt: ein Hook ist Policy, die im eigenen Prozess durchgesetzt wird, keine Isolation.)
Sprosse zwei: OS-Level-Schutz, mit dem das Modell nicht argumentieren kann
Das ist die Sprosse, die die meisten Solo-Builder überspringen, und sie hat das beste Aufwand-zu-Sicherheit-Verhältnis. Die Idee: das Betriebssystem eine Dateisystem- und Netzwerkgrenze für jeden Shell-Befehl und seine Kindprozesse durchsetzen lassen, unabhängig davon, was das Modell zu laufen entschieden hat.
Claude Code liefert das als sandgeboxtes Bash-Tool. Auf macOS wird das eingebaute Seatbelt-Framework verwendet — nichts zu installieren. Auf Linux und WSL2 wird bubblewrap für die Dateisystem-Isolation plus socat verwendet, um Datenverkehr über einen Proxy zu leiten. Standardmäßig können sandgeboxte Befehle nur in das Arbeitsverzeichnis und das temporäre Sitzungsverzeichnis schreiben, und der Netzwerkzugriff ist standardmäßig verweigert: "Keine Domains sind vorab erlaubt. Wenn ein Befehl zum ersten Mal eine neue Domain benötigt, fragt Claude Code nach Genehmigung."
Warum das einen Permission-Prompt schlägt: Die Dokumentation sagt es klar. "Das Betriebssystem setzt die Sandbox-Grenze im laufenden Prozess durch, sodass sie gilt, unabhängig davon, was das Modell zu laufen gewählt hat, und selbst wenn ein erlaubter Befehl mehr tut als sein Name andeutet." Das ist der Unterschied zwischen Policy und Durchsetzung.
Zwei Vorbehalte, die zweimal gelesen werden sollten, beide direkt aus der Dokumentation. Erstens erlaubt die Standard-Lese-Policy immer noch das Lesen von Anmeldedateien — "Dieser Standard erlaubt immer noch das Lesen von Anmeldedateien wie ~/.aws/credentials und ~/.ssh/." Man muss sie selbst zu denyRead hinzufügen. Zweitens setzt der Netzwerk-Proxy die Allowlist per Hostname durch und "terminiert oder führt keine TLS-Inspektion des ausgehenden Datenverkehrs durch", sodass eine breite Erlaubnis wie github.com über Domain-Fronting zum Exfiltrationspfad werden kann. Effektives Sandboxing, so die Formulierung, "erfordert sowohl Dateisystem- als auch Netzwerkisolation" — erweitert man eine Seite, kann man die andere still rückgängig machen.
Meine Einschätzung: Einschalten, Lesen von Anmeldeverzeichnissen verweigern und die Netzwerk-Allowlist knapp halten. Es ist kostenlos und stoppt die häufigsten Unfälle. Aber es ist eine Härtungsschicht auf der echten Maschine, kein Reinraum.
Sprosse drei: Container
Ein Container ist der offensichtliche nächste Schritt, und für vertrauenswürdige, aber unordentliche Arbeit ist er gut genug. Man lässt den Agent in Docker laufen, mountet nur das Projektverzeichnis, übergibt nur die Env-Variablen, die das Projekt benötigt, und der Blast-Radius ist der Container. Container löschen, Schaden ist weg.
Die ehrliche Einschränkung ist die, die Container immer hatten: Sie teilen den Host-Kernel. Ein Container sind Namespaces und Cgroups, keine separate Maschine. Für Code, den man selbst geschrieben hat, reicht das vollkommen — das realistische Risiko ist ein Unfall, und die Namespace-Grenze hält Unfälle gut zurück. Für wirklich nicht vertrauenswürdigen Code erreicht ein Kernel-Exploit im Container den Host: eine echte, wenn auch seltene Angriffskategorie. Es gibt auch eine mittlere Option — gVisor von Google fängt Syscalls eines Containers in einem Userspace-Kernel ab, bevor sie den Host erreichen, und verkleinert die Angriffsfläche ohne vollständige VM. Stärker als ein einfacher Container, schwächer als Hardware-Virtualisierung, mit einem messbaren I/O-Overhead.
Das praktische Container-Setup für einen Agent: ein Dev-Container, der den Agent als Non-Root-Benutzer ausführt, mit dem gemounteten Projekt und sonst nichts. Dieses Non-Root-Detail ist wichtig — Claude Code weigert sich, im Bypass-Permissions-Modus als Root zu starten, und die Dev-Container-Konfiguration existiert teilweise, um einen Non-Root-Benutzer bereitzustellen, damit autonome Läufe sicher unbeaufsichtigt laufen können.
Sprosse vier: microVMs, die echte Mauer
Wenn man Code ausführen muss, dem man nicht vertraut, ist der Goldstandard 2026 eine microVM: eine echte virtuelle Maschine mit eigenem Kernel, die in Millisekunden bootet, mit einem Gerätemodell, das auf fast nichts reduziert wurde. Firecracker, der Open-Source-VMM, den AWS für Lambda und Fargate entwickelt hat, ist das, was alle verwenden. Seine gesamte Design-Philosophie ist eine kleine Angriffsfläche — er "schließt unnötige Geräte und gastorientierte Funktionalität aus, um den Speicher-Footprint und die Angriffsfläche jeder microVM zu reduzieren", bootet einen minimalen Kernel ohne BIOS und ohne vollständiges Gerätemodell, und führt jeden Gast auf KVM-Hardware-Virtualisierung aus.
Das Sicherheitsargument ist strukturell: Jede Arbeitslast erhält ihren eigenen Kernel auf einer Hardware-Virtualisierungsgrenze, sodass ein Kernel-Exploit innerhalb einer microVM weder den Host noch eine benachbarte VM erreichen kann. Das ist die Grenze, die ein Container nicht geben kann, weil der Container keinen eigenen Kernel hat. Die Kosten lagen früher in der Startzeit; Firecrackers ~125ms Boots haben das größtenteils beseitigt.
Man wird Firecracker höchstwahrscheinlich nicht selbst betreiben wollen. Dafür gibt es Hosted-Dienste.
Sprosse fünf: Hosted-Sandbox-Dienste
Wenn "dem Agent einen Computer geben, der nicht meiner ist" richtig klingt, ist das ein Hosted-Sandbox, und das Feld ist im letzten Jahr deutlich gereifter geworden.
Vercel Sandbox wurde am 30. Januar 2026 allgemein verfügbar (Ankündigung). Es lässt jede Sandbox in einer Firecracker-microVM mit eigenem Dateisystem und Netzwerk auf Amazon Linux 2023 laufen, mit node26/node24/node22/python3.13-Runtimes und sudo-Zugang. Das Verkaufsargument für das Secret-Leak-Problem: Code in einer Sandbox ist von der Infrastruktur isoliert, sodass er nicht auf Umgebungsvariablen, Datenbankverbindungen oder Cloud-Ressourcen des Projekts zugreifen kann — diese Isolation ist das Produkt, keine Einstellung, an die man denken muss. Gesteuert wird es mit einem JS- oder Python-SDK oder einer CLI. Persistenz (automatisches Speichern und Fortsetzen) ist seit dem GA-Release standardmäßig aktiv.
E2B ist die andere offensichtliche Wahl, direkt auf die Ausführung von KI-generiertem Code ausgerichtet. Es ist Open-Source unter Apache-2.0, hat Python- und JavaScript-SDKs, nutzt eine Dockerfile zum Erstellen einer microVM-Vorlage (nicht zum Ausführen eines Containers), und — der Teil, den ich mag — ist per Terraform auf AWS, GCP, Azure oder den eigenen Linux-Maschinen selbst hostbar. Man kann auf ihrer Cloud beginnen und es später ohne Neuschreiben ins eigene Haus bringen.
Der Kompromiss ist der übliche: Latenz, Kosten pro Ausführung und ein Netzwerk-Round-Trip zwischen Agent und Code. Für ein Tool, das benutzereingereichte oder agentgenerierte Snippets ausführt, ist das ein fairer Preis für eine saubere Kernel-Grenze und automatische Secret-Isolation. Für die ganztägige Bearbeitung des eigenen Repos ist es übertrieben, und die Reibung wird nerven.
Was ich wirklich einsetze
Hier ist das konkrete Setup, aufgeteilt auf die zwei Fälle, die wichtig sind.
Für meinen eigenen Code, täglich: Claude Code auf meiner echten Maschine, im default- oder plan-Modus, mit aktiviertem OS-Sandbox. Die unverzichtbare Konfiguration ist das Verweigern von Lesezugriffen auf Anmeldeverzeichnisse und das Kurzhalten der Netzwerk-Allowlist:
{
"sandbox": {
"enabled": true,
"filesystem": { "denyRead": ["~/.aws", "~/.ssh", "~/.config/gh"] },
"allowedDomains": ["registry.npmjs.org", "github.com"]
}
}
Secrets liegen in einem .env, das das Arbeitsverzeichnis des Agents nicht lesen kann, und ich bereinige Provider-Anmeldedaten aus Subprozessen (CLAUDE_CODE_SUBPROCESS_ENV_SCRUB), damit ein verirrtes curl in einem Build-Skript meinen API-Schlüssel nicht aus der Umgebung greifen kann. Das ist Härtung, keine Mauer, und ich behandle es so.
Für alles, was ich nicht selbst geschrieben habe — ein Repo, das ich prüfe, generierten Code, eine Abhängigkeit, der ich nicht vertraue, einen Agent, der über Nacht unbeaufsichtigt läuft — kommt es in eine microVM. In der Praxis bedeutet das einen Hosted-Sandbox (Vercel Sandbox oder E2B), damit Kernel-Grenze und Secret-Isolation kostenlos kommen, oder ein Dev-Container, der den Agent als Non-Root mit bypassPermissions innerhalb des Containers laufen lässt, wo nichts Wertvolles zu beschädigen ist. Die Regel, der ich folge: Die Stärke der Grenze sollte dem Vertrauen in den Code entsprechen, nicht der Bequemlichkeit der Grenze.
Der Fehler, den ich am Anfang machte, war, das als eine Entscheidung zu behandeln — "ist Sandboxing an oder aus". Es sind zwei. Vertrauenswürdiger Code auf meiner Maschine möchte günstige Schutzmaßnahmen, die Unfälle aufhalten. Nicht vertrauenswürdiger Code möchte eine Mauer, die das Modell nicht überreden kann zu passieren. Wähle die Sprosse, die zum Vertrauen passt, verweigere in jedem Fall das Lesen deiner Secrets, und du kannst das Ding laufen lassen, ohne jeden Befehl zu überwachen — was der eigentliche Sinn war, einen Agent einzustellen.
