Ga naar inhoud

Sandboxbackends

Backend Waarde Platform Beschikbaarheid
Omhulde VM microvm macOS, Linux, Windows (microVM-hypervisor) Alleen als de probe op de microVM-runtime slaagt; geldt voor interactieve terminals — de shell draait in een rig, niet op de host
Native native macOS (Seatbelt), Linux en WSL2 (bubblewrap) Bij het opstarten geprobeerd; Linux weigert een run die schrijfweigeringen op bestandsnaamglobs vereist, wat bubblewrap niet kan afdwingen
Geen none Alle De standaardwaarde bij het parsen, de standaardwaarde van de terminal en de terugval wanneer er geen backend beschikbaar is of --sandbox off is ingesteld

SandboxBackend.fromName geeft none terug voor een null-waarde of een niet-herkende opgeslagen waarde. Een opgeslagen "docker" wordt toegewezen aan native.

microvm is de enige backend met een kernelgrens — de workload draait echt niet op de host. Hij is nooit een stille terugval, in geen van beide richtingen: hem expliciet aanvragen op een host die geen VM kan opstarten mislukt luidruchtig (“ik vroeg om een VM en kreeg mijn laptop” is de ene verslechtering die de omhulling zich niet kan permitteren), en alleen een niet-opgegeven standaard stapt af naar native, met een logregel die dat zegt. De werkelijke backend van de sessie wordt aan de client teruggerapporteerd en van een badge voorzien, zodat een terminal nooit kan beweren omhuld te zijn terwijl hij op de host draait. Levenscyclus, images en uitgaand verkeer van de VM zelf staan in de rigs-referentie.

Windows heeft geen native sandbox. NativeSandboxAdapter.probe geeft available: false terug op elke host die geen macOS of Linux/WSL2 is. Het dispatchen van agenten op Windows gebruikt daarom none. De microvm-backend staat apart: hij is alleen beschikbaar als de probe op de microVM-runtime slaagt en geldt voor interactieve terminals en rigs, niet voor het omhullen van bash op de host.

De probe bepaalt de afdwinging. Hij draait één keer, bij het opstarten van de server.

Host available Opmerking / hint
macOS true sandbox-exec (Seatbelt) — namespace-isolatie, geen kernelgrens
Linux of WSL2 met bwrap en socat true bubblewrap — namespace-isolatie, geen kernelgrens
Linux of WSL2 zonder een van beide tools false requiresInstall: true, met een installatiehint die de ontbrekende pakketten noemt
Elk ander platform false Native sandbox wordt op dit platform niet aangeboden

De server logt de uitkomst op één opstartregel: agent sandbox ON plus de opmerking, no OS-native agent sandbox on this host plus de hint, of agent sandbox DISABLED by --sandbox off. GET /healthz bevat geen sandboxveld.

--sandbox / CC_SERVER_SANDBOX accepteert on (standaard) of off. Het is een afmelding, geen aanmelding: on betekent “omhullen wanneer de host een backend biedt”, nooit “er een vereisen”.

Gebruikt Apples Seatbelt-sandboxmechanisme (hetzelfde systeem dat macOS App Sandbox gebruikt).

Het gegenereerde profiel is standaard toestaan ((allow default)) en haalt daar weigeringen uit, omdat een profiel dat standaard alles weigert een interactieve shell onbruikbaar maakt — er zijn te veel dyld-, XPC- en Mach-aanroepen om te enumereren. De praktische consequentie is dat een agent nog steeds het grootste deel van de host kan lezen; je geregistreerde checkouts worden beschermd door expliciete schrijf- en renameweigeringen, niet door onzichtbaarheid.

  • Bestandssysteemlezen: geweigerd voor de geheime paden (~/.ssh, ~/.aws, ~/.gnupg, ~/.config/gh, ~/Library/Keychains en de rest van de set met leesweigeringen)
  • Bestandssysteemschrijven: teruggezet naar weigeren, daarna expliciete toestemmingen voor subpaden, waarbij de verplicht te weigeren paden (shell-rc-bestanden, .git/hooks, Claude-configuratie, beschermde checkouts) ook binnen een beschrijfbare root geblokkeerd blijven. file-write-unlink wordt geweigerd op elk geweigerd pad en zijn voorouders, zodat een rename een schrijfweigering niet kan omzeilen
  • Proces: process-exec-weigeringen voor de altijd gevaarlijke binaries, plus een blokkade op het uitvoeren van alles uit een beschrijfbare map
  • Netwerk: beperkt tot de in-process proxypoorten plus DNS — loopback is niet in het algemeen toegestaan en Unix-sockets zijn niet toegestaan. De proxies dwingen de domein-allowlist per sessie af (zie Netwerk-egress)
  • Configuratie: profielen worden per start gegenereerd uit de SandboxSpec

Vereisten:

  • sandbox-exec (/usr/bin/sandbox-exec), onderdeel van elke macOS-installatie — geen extra tooling nodig

Gebruikt bubblewrap (bwrap) om mount- en PID-namespaces te maken.

  • Bestandssysteem: maakt een mount-namespace waarin alleen de gebonden paden zichtbaar zijn
  • Netwerk: draait in een niet-gedeelde netwerknamespace; verkeer bereikt de host-proxies via socat-Unix-socketbruggen
  • Proces: PID-namespace-isolatie

Vereisten:

  • bubblewrap en socat geïnstalleerd (sudo apt-get install bubblewrap socat op Debian/Ubuntu)
  • Ondersteuning voor kernel-namespaces (standaard op moderne Linux)

Bubblewrap kan een bestaand pad overschaduwen, maar kan een nieuw .env, *.key- of *.pem-bestand binnen een beschrijfbare bind niet verbieden. Het standaarddispatchbeleid vereist deze weigeringen op bestandsnaamglobs, dus native agentdispatch faalt fail-closed op Linux/WSL2, zelfs wanneer de probe bubblewrap vindt. Hij draait niet met een stilzwijgend zwakker beleid. Er is een backend met regels op bestandsnaam bij aanmaak nodig om native dispatch op Linux te herstellen. Sandboxing uitschakelen is een expliciete onbeperkte afmelding, geen gelijkwaardige workaround.

Geen sandboxing. Het proces draait rechtstreeks op de host, met de bestandssysteem-, netwerk- en procestoegang van de host. ACP en de bash-tool van de harness krijgen nog steeds omgevingssanering en het opdrachtbeleid; Claude Code via NoSandboxAdapter erft de omgeving van de host. Hierop valt het dispatchen van agenten terug op een host zonder beschikbare backend of met --sandbox off, en het is de standaardwaarde van de terminal wanneer een client er geen noemt.

De terminal wordt gesandboxed op zijn eigen voorwaarden, niet door de dispatchprobe. defaultBackend van TerminalSessionService is none en cc_server overschrijft dat niet, dus een terminalsessie draait de hostshell tenzij de client expliciet native vraagt — het terminalpaneel van de desktop doet dat niet.

Wanneer native wordt gevraagd, wordt de shell omhuld via SandboxManager onder een vast terminalprofiel: $HOME en de werkmap van de sessie zijn beschrijfbaar, het netwerk staat open en ~/.ssh, ~/.aws, ~/.gnupg, ~/.config/gh en ~/Library/Keychains krijgen leesweigering. Het forge-token met alleen leesrechten en de push-gateway zijn hier niet van toepassing — dat zijn dispatchzaken. Als het omhullen niet wordt ondersteund, mislukt de sessie in plaats van een native badge te tonen op een PTY met de hostshell.

Wanneer een sandbox wordt gestart, wordt uitgaande netwerktoegang afgedwongen door in-process proxies, niet door kernel-firewallregels. Op een host zonder beschikbare backend geldt niets hiervan en bereikt een gestart proces het netwerk precies zoals de servergebruiker dat zou doen.

  • De sandboxruntime draait een HTTP/HTTPS-proxy en een SOCKS5-proxy op 127.0.0.1 binnen het cc_server-proces, één paar per beperkte sessie (http_proxy.dart, socks_proxy.dart). Gelijktijdige runs delen geen paar.
  • Gesandboxte processen krijgen proxy-omgevingsvariabelen (HTTP_PROXY/HTTPS_PROXY → de HTTP-proxy, ALL_PROXY → de SOCKS-proxy; GIT_SSH_COMMAND leidt git-over-SSH via de SOCKS-proxy). Op Linux is de netwerknamespace niet gedeeld, dus zijn de proxies de enige uitweg; op macOS deelt de sandbox de loopback van de host en praat hij er rechtstreeks mee.
  • De doelhost van elke verbinding wordt gematcht tegen de domein-allowlist van de sessie; al het andere wordt geweigerd. Twee jokervormen, elk met precies één *: een vooraanstaande *.example.com matcht elk subdomein (inclusief a.b.example.com) maar niet het hoofddomein zelf; een middenlabel bedrock.*.amazonaws.com matcht precies één label (bedrock.us-east-1.amazonaws.com, niet bedrock.evil.attacker.amazonaws.com).
  • De allowlist wordt per sessie samengesteld uit de samengestelde basis (kBaselineAllowedDomains: LLM-providers, githosting, pakketregisters), plus de GitHub-domeinen (kGithubDomains), plus SandboxSpec.egressAllowlist. Het dispatchpad geeft nooit extra egressAllowlist-vermeldingen door, dus in de praktijk krijgt elke run de basis plus GitHub.
  • Een vaste weigerlijst (kBaselineDeniedDomains: cloudmetadata-eindpunten, telemetrie-sinks) gaat vóór alle toestemmingen.
  • networkEnabled: false start de proxies per sessie nog steeds, maar de allowlist is leeg, dus elke uitgaande verbinding wordt geweigerd. Dispatch stelt de waarde bij de start van de run in op basis van de regel Toegang tot het netwerk: weigeren zet het netwerk uit, toestaan en eerst vragen laten het aan.

De specificatie die aan SandboxPort.launch wordt doorgegeven:

Veld Type Beschrijving
sessionId String Stabiele sessie-identificatie (meestal het ruimte-id)
workspaceId String Id van de eigenaarswerkruimte
agentId String? Agent die momenteel aan de sandbox is gebonden, indien van toepassing
bindMounts List<SandboxBindMount> Host→guest-mounts; de sandbox ziet alleen de hostpaden die hier worden genoemd
networkEnabled bool (standaard true) Door dispatch ingesteld op basis van de regel voor uitgaand netwerkverkeer (alleen uit wanneer die op weigeren uitkomt). Staat het uit, dan starten de proxies per sessie nog steeds, maar is de allowlist leeg, dus wordt elke uitgaande verbinding geweigerd
egressAllowlist List<String> (standaard []) Extra toegestane egress-domeinen; jokers worden ondersteund (*.example.com, plus een middenvorm met één label). Dispatch vult dit nooit, dus een omhulde run krijgt de samengestelde basis plus de GitHub-domeinen
guestWorkdir String? Standaardwerkmap binnen de sandbox; afzonderlijke exec-aanroepen kunnen die overschrijven
mode Mode (standaard chat) Bepaalt de schrijfregels voor het bestandssysteem: chat houdt bind-mounts beschrijfbaar; review, plan en orchestrate zijn alleen-lezen
protectedPaths List<String> (standaard []) Hostpaden die in geen enkele modus beschrijfbaar mogen zijn binnen de sandbox
runnerStateDirs List<String> (standaard []) Hostmappen waarin de runner zijn eigen staat bewaart, in elke modus beschrijfbaar (een door Control Center beheerde CLAUDE_CONFIG_DIR is de huidige)
execGrantRoots List<String> (standaard []) Door de operator goedgekeurde mappenbomen die de exec-blokkade op beschrijfbare mappen op macOS weer openen. Linux negeert ze — bwrap heeft geen $HOME-execblokkade om te heropenen

protectedPaths bevat de oorspronkelijke geregistreerde repo-checkouts, per dispatch bepaald uit de repo’s van de werkruimte. Agenten werken uitsluitend in copy-on-write-worktrees per gesprek, dus de originelen mogen nooit beschrijfbaar zijn van binnenuit de sandbox — op macOS zou de algemene $HOME-schrijftoestemming van Seatbelt ze anders via bash beschrijfbaar laten. Ze voegen zich in elke modus bij de set met schrijfweigeringen voor geheimen, chat inbegrepen.

Elk pad waarvoor lezen of schrijven wordt geweigerd, wordt in zowel zijn letterlijke spelling als zijn symlink-opgeloste spelling uitgevaardigd. De kernel matcht een weigeringsregel tegen het opgeloste pad, dus een regel die tegen een symlinkpad is geschreven, vuurt nooit — en op macOS is dat het gewone geval in plaats van het exotische, aangezien /tmp verwijst naar /private/tmp en /var/folders/… naar /private/var/folders/…. Vermeldingen met * of ? worden als globs behandeld en met rust gelaten; een pad dat niet resolveert, blijft staan zoals het is geschreven.

Veld Type Beschrijving
hostPath String Absoluut pad op de host
guestPath String Pad binnen de sandbox (bij de native sandbox is dit gelijk aan hostPath; behouden voor adapter-symmetrie)
readOnly bool (standaard false) Alleen-lezen mounten wanneer waar

Teruggegeven door SandboxPort.launch:

Veld Type Beschrijving
sessionId String Sessie-identificatie
backend SandboxBackend Welke backend draait
state SandboxState Levenscyclusstatus
error Object? Ingesteld wanneer state error is
details Map<String, Object?> Adapter-eigen boekhouding (werkmap, PID, profielpad, enz.)
Status Beschrijving
created Spec aangemaakt, maar de VM is nog niet gestart
warm Draait en klaar om commando’s uit te voeren
active Voert momenteel een commando uit
suspended Gepauzeerd / gecheckpoint naar schijf om RAM te sparen
destroyed Afgebroken; de handle is niet meer geldig
error Starten mislukt — zie SandboxHandle.error
Gebeurtenistype Beschrijving
stdout Standaarduitvoer van de sandbox
stderr Standaardfout van de sandbox
exit Sandboxproces beëindigd (draagt exitCode)
starting Sandbox is aan het opstarten
ready Sandbox is klaar om exec-aanroepen te accepteren
killed Proces gedood door de host (OOM, timeout, handmatige stop)
violation Een sandboxbeleid is geschonden (draagt een SandboxViolation)
Veld Type Beschrijving
action String Het geweigerde werkwoord (bijv. file-read*, network-outbound)
target String Pad of host die het doel was van de geweigerde handeling
raw String? Ruwe logregel, nuttig voor het debuggen