Sandboxbackends
Backendoverzicht
Sectie getiteld “Backendoverzicht”| 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.
Probe-resultaten
Sectie getiteld “Probe-resultaten”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”.
Native backend
Sectie getiteld “Native backend”macOS: Seatbelt
Sectie getiteld “macOS: Seatbelt”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/Keychainsen 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-unlinkwordt 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
Linux: bubblewrap
Sectie getiteld “Linux: bubblewrap”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:
bubblewrapensocatgeïnstalleerd (sudo apt-get install bubblewrap socatop 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.
None-backend
Sectie getiteld “None-backend”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.
Door de server gehoste terminal
Sectie getiteld “Door de server gehoste terminal”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.
Netwerk-egress
Sectie getiteld “Netwerk-egress”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.1binnen hetcc_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_COMMANDleidt 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.commatcht elk subdomein (inclusiefa.b.example.com) maar niet het hoofddomein zelf; een middenlabelbedrock.*.amazonaws.commatcht precies één label (bedrock.us-east-1.amazonaws.com, nietbedrock.evil.attacker.amazonaws.com). - De allowlist wordt per sessie samengesteld uit de samengestelde basis (
kBaselineAllowedDomains: LLM-providers, githosting, pakketregisters), plus de GitHub-domeinen (kGithubDomains), plusSandboxSpec.egressAllowlist. Het dispatchpad geeft nooit extraegressAllowlist-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: falsestart 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.
SandboxSpec
Sectie getiteld “SandboxSpec”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.
SandboxBindMount
Sectie getiteld “SandboxBindMount”| 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 |
SandboxHandle
Sectie getiteld “SandboxHandle”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.) |
SandboxState
Sectie getiteld “SandboxState”| 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 |
Sandbox-gebeurtenissen
Sectie getiteld “Sandbox-gebeurtenissen”| 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) |
SandboxViolation
Sectie getiteld “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 |
Zie ook
Sectie getiteld “Zie ook”- Sandbox en beveiliging
- Sandboxbeleid
- Beveiligingen
- cc_server CLI: de
--sandbox-flag