Backend del sandbox
Panoramica dei backend
Sezione intitolata “Panoramica dei backend”| Backend | Valore | Piattaforma | Disponibilità |
|---|---|---|---|
| VM isolata | microvm |
macOS, Linux, Windows (hypervisor microVM) | Subordinato alla sonda sul runtime microVM; si applica ai terminali interattivi — la shell viene eseguita dentro un rig, non sull’host |
| Nativo | native |
macOS (Seatbelt), Linux e WSL2 (bubblewrap) | Sondato all’avvio; Linux rifiuta un’esecuzione che richiede dinieghi di scrittura con glob di nomi file, che bubblewrap non può applicare |
| Nessuno | none |
Tutte | Il valore predefinito in fase di analisi, il valore predefinito del terminale e il ripiego quando non è disponibile alcun backend o è impostato --sandbox off |
SandboxBackend.fromName restituisce none per un valore memorizzato nullo o non riconosciuto. Un valore memorizzato "docker" viene mappato su native.
microvm è l’unico backend con un confine del kernel — il carico di lavoro non viene davvero eseguito sull’host. Non è mai un ripiego silenzioso in nessuna delle due direzioni: chiederlo esplicitamente su un host che non può avviare una VM fallisce in modo rumoroso («ho chiesto una VM e mi sono ritrovato il portatile» è l’unica degradazione che il recinto non può permettersi), e solo un valore predefinito non specificato scende a native, con una riga di log che lo dichiara. Il backend effettivo della sessione viene riportato al client e contrassegnato con un badge, così un terminale non può mai dichiararsi racchiuso mentre viene eseguito sull’host. Ciclo di vita, immagini ed egress della VM stessa sono trattati nel riferimento sui rig.
Windows non ha alcun sandbox nativo. NativeSandboxAdapter.probe restituisce available: false su ogni host che non sia macOS o Linux/WSL2. L’invio degli agenti su Windows usa quindi none. Il backend microvm è separato: è subordinato alla sonda sul runtime microVM e si applica ai terminali interattivi e ai rig, non all’avvolgimento di bash sull’host.
Esiti della sonda
Sezione intitolata “Esiti della sonda”È la sonda a governare l’applicazione. Viene eseguita una sola volta, all’avvio del server.
| Host | available |
Nota / suggerimento |
|---|---|---|
| macOS | true |
sandbox-exec (Seatbelt) — isolamento a livello di namespace, nessun confine del kernel |
Linux o WSL2 con bwrap e socat |
true |
bubblewrap — isolamento a livello di namespace, nessun confine del kernel |
| Linux o WSL2 senza uno dei due strumenti | false |
requiresInstall: true, con un suggerimento di installazione che nomina i pacchetti mancanti |
| Qualsiasi altra piattaforma | false |
Il sandbox nativo non è offerto su questa piattaforma |
Il server registra l’esito in un’unica riga all’avvio: agent sandbox ON più la nota, no OS-native agent sandbox on this host più il suggerimento, oppure agent sandbox DISABLED by --sandbox off. GET /healthz non contiene alcun campo del sandbox.
--sandbox / CC_SERVER_SANDBOX accetta on (predefinito) o off. È un opt-out, non un’abilitazione: on significa «avvolgi quando l’host offre un backend», mai «esigine uno».
Backend nativo
Sezione intitolata “Backend nativo”macOS: Seatbelt
Sezione intitolata “macOS: Seatbelt”Usa il meccanismo di sandbox Seatbelt di Apple (lo stesso sistema usato dall’App Sandbox di macOS).
Il profilo generato è permissivo per impostazione predefinita ((allow default)) e ritaglia dei dinieghi, perché un profilo completamente deny-by-default rende inutilizzabile una shell interattiva — ci sono troppe chiamate dyld, XPC e Mach da enumerare. La conseguenza pratica è che un agente può ancora leggere gran parte dell’host; i tuoi checkout registrati sono protetti da dinieghi espliciti di scrittura e rinomina, non dall’invisibilità.
- Letture del filesystem: negate per i percorsi segreti (
~/.ssh,~/.aws,~/.gnupg,~/.config/gh,~/Library/Keychainse il resto dell’insieme delle letture negate) - Scritture del filesystem: riportate a deny, poi consentite esplicitamente su singoli sottopercorsi, con i percorsi a diniego obbligatorio (file rc della shell,
.git/hooks, configurazione di Claude, checkout protetti) bloccati anche dentro una radice scrivibile.file-write-unlinkè negato su ogni percorso negato e sui suoi antenati, così una rinomina non può aggirare un diniego di scrittura - Processi: dinieghi
process-execper i binari sempre pericolosi, più un blocco sull’esecuzione di qualsiasi cosa da una directory scrivibile - Rete: limitata alle porte dei proxy in-process più il DNS — il loopback non è consentito in modo indiscriminato e i socket Unix non sono ammessi. I proxy applicano la lista di autorizzazione dei domini per sessione (vedi Egress di rete)
- Configurazione: i profili vengono generati a ogni avvio dal
SandboxSpec
Requisiti:
sandbox-exec(/usr/bin/sandbox-exec), presente in ogni installazione di macOS — non serve alcuno strumento aggiuntivo
Linux: bubblewrap
Sezione intitolata “Linux: bubblewrap”Usa bubblewrap (bwrap) per creare namespace di mount e di PID.
- Filesystem: crea un namespace di mount in cui sono visibili solo i percorsi montati
- Rete: viene eseguito in un namespace di rete non condiviso; il traffico raggiunge i proxy dell’host tramite ponti socket Unix di
socat - Processi: isolamento del namespace dei PID
Requisiti:
bubblewrapesocatinstallati (sudo apt-get install bubblewrap socatsu Debian/Ubuntu)- Supporto ai namespace del kernel (standard su Linux moderno)
Bubblewrap può oscurare un percorso esistente ma non può vietare un file .env, *.key o *.pem nuovo dentro un bind scrivibile. La policy di invio standard richiede questi dinieghi basati su glob di nomi file, quindi oggi l’invio nativo degli agenti fallisce in modo chiuso su Linux/WSL2 anche quando la sonda trova bubblewrap. Non viene eseguito con una policy silenziosamente più debole. Per ripristinare l’invio nativo su Linux serve un backend con regole sui nomi file al momento della creazione. Disattivare il sandbox è una rinuncia esplicita senza confinamento, non una soluzione equivalente.
Backend none
Sezione intitolata “Backend none”Nessun sandbox. Il processo viene eseguito direttamente sull’host, con accesso al filesystem, alla rete e ai processi dell’host. ACP e lo strumento bash dell’harness ricevono comunque la sanificazione dell’ambiente e la policy dei comandi; Claude Code tramite NoSandboxAdapter eredita l’ambiente dell’host. È ciò su cui ripiega l’invio degli agenti su un host senza alcun backend disponibile o con --sandbox off, ed è il valore predefinito del terminale quando un client non ne indica nessuno.
Terminale ospitato sul server
Sezione intitolata “Terminale ospitato sul server”Il terminale viene racchiuso in un sandbox secondo regole proprie, non dalla sonda dell’invio. Il defaultBackend di TerminalSessionService è none e cc_server non lo sovrascrive, quindi una sessione di terminale esegue la shell dell’host a meno che il client non chieda esplicitamente native — il pannello del terminale del desktop non lo fa.
Quando viene richiesto native, la shell viene avvolta tramite SandboxManager con un profilo di terminale fisso: $HOME e la directory di lavoro della sessione sono scrivibili, la rete è aperta e ~/.ssh, ~/.aws, ~/.gnupg, ~/.config/gh e ~/Library/Keychains sono negati in lettura. Il token del forge di sola lettura e il gateway dei push non si applicano — sono una questione di invio. Se l’avvolgimento non è supportato, la sessione fallisce invece di mostrare un badge nativo su un PTY con la shell dell’host.
Egress di rete
Sezione intitolata “Egress di rete”Quando viene avviato un sandbox, l’accesso di rete in uscita è applicato da proxy in-process, non da regole di firewall del kernel. Su un host senza alcun backend disponibile nulla di tutto ciò si applica e un processo avviato raggiunge la rete esattamente come farebbe l’utente del server.
- Il runtime del sandbox esegue un proxy HTTP/HTTPS e un proxy SOCKS5 su
127.0.0.1all’interno del processocc_server, una coppia per sessione limitata (http_proxy.dart,socks_proxy.dart). Esecuzioni concorrenti non condividono una coppia. - I processi racchiusi in un sandbox ricevono le variabili d’ambiente dei proxy (
HTTP_PROXY/HTTPS_PROXY→ il proxy HTTP,ALL_PROXY→ il proxy SOCKS;GIT_SSH_COMMANDinstrada git-over-SSH attraverso il proxy SOCKS). Su Linux il namespace di rete non è condiviso, quindi i proxy sono l’unica via d’uscita; su macOS il sandbox condivide il loopback dell’host e comunica direttamente con loro. - L’host di destinazione di ogni connessione viene confrontato con la lista di autorizzazione dei domini della sessione; qualsiasi altra cosa viene negata. Due forme con caratteri jolly, ciascuna con esattamente un
*: un*.example.cominiziale corrisponde a qualsiasi sottodominio (compresoa.b.example.com) ma non al dominio radice stesso; unbedrock.*.amazonaws.comcon etichetta centrale corrisponde esattamente a un’etichetta (bedrock.us-east-1.amazonaws.com, nonbedrock.evil.attacker.amazonaws.com). - La lista di autorizzazione viene risolta per sessione dalla base di riferimento curata (
kBaselineAllowedDomains: provider LLM, hosting Git, registry dei pacchetti), più i domini GitHub (kGithubDomains), piùSandboxSpec.egressAllowlist. Il percorso di invio non passa mai vociegressAllowlistaggiuntive, quindi in pratica ogni esecuzione ottiene la base di riferimento più GitHub. - Un elenco fisso di domini negati (
kBaselineDeniedDomains: endpoint di metadati cloud, destinazioni di telemetria) prevale su tutte le autorizzazioni. networkEnabled: falseavvia comunque i proxy per sessione, ma la lista di autorizzazione è vuota, quindi ogni connessione in uscita viene rifiutata. L’invio lo imposta all’avvio dell’esecuzione dalla regola Accedere alla rete: nega disattiva la rete, consenti e chiedi prima la lasciano attiva.
SandboxSpec
Sezione intitolata “SandboxSpec”La specifica passata a SandboxPort.launch:
| Campo | Tipo | Descrizione |
|---|---|---|
sessionId |
String |
Identificatore di sessione stabile (di norma l’id dello spazio) |
workspaceId |
String |
Id dello spazio di lavoro proprietario |
agentId |
String? |
Agente attualmente associato al sandbox, se presente |
bindMounts |
List<SandboxBindMount> |
Mount host→guest; il sandbox vede solo i percorsi dell’host elencati qui |
networkEnabled |
bool (predefinito true) |
Impostato all’invio dalla regola di uscita di rete (disattivato solo quando si risolve in nega). Se disattivato, i proxy per sessione si avviano comunque ma la lista di autorizzazione è vuota, quindi ogni connessione in uscita viene rifiutata |
egressAllowlist |
List<String> (predefinito []) |
Domini di egress consentiti in aggiunta; caratteri jolly supportati (*.example.com, più una forma centrale a un’etichetta). L’invio non popola mai questo campo, quindi un’esecuzione avvolta ottiene la base di riferimento curata più i domini GitHub |
guestWorkdir |
String? |
Directory di lavoro predefinita dentro il sandbox; le singole chiamate exec possono sovrascriverla |
mode |
Mode (predefinito chat) |
Ritaglia le regole di scrittura del filesystem: chat mantiene scrivibili i bind mount; review, plan e orchestrate sono di sola lettura |
protectedPaths |
List<String> (predefinito []) |
Percorsi dell’host che non devono mai essere scrivibili dentro il sandbox, in nessuna modalità |
runnerStateDirs |
List<String> (predefinito []) |
Directory dell’host in cui il runner conserva il proprio stato, scrivibili in ogni modalità (quella attuale è una CLAUDE_CONFIG_DIR gestita da Control Center) |
execGrantRoots |
List<String> (predefinito []) |
Alberi di directory approvati dall’operatore che riaprono il blocco di exec delle directory scrivibili su macOS. Linux li ignora — bwrap non ha alcun blocco di exec su $HOME da riaprire |
protectedPaths contiene i checkout originali dei repo registrati, risolti a ogni invio dai repo dello spazio di lavoro. Gli agenti lavorano esclusivamente in worktree copy-on-write per conversazione, quindi gli originali non devono mai essere scrivibili dall’interno del sandbox — su macOS, l’autorizzazione indiscriminata di scrittura su $HOME di Seatbelt li lascerebbe altrimenti scrivibili tramite bash. Si aggiungono all’insieme dei dinieghi di scrittura dei segreti in ogni modalità, chat compresa.
Ogni percorso di lettura negata e di scrittura negata viene emesso sia nella sua grafia letterale sia in quella risolta dai symlink. Il kernel confronta una regola di diniego con il percorso risolto, quindi una regola scritta su un percorso con symlink non scatta mai — e su macOS questo è il caso comune, non quello esotico, dato che /tmp viene risolto in /private/tmp e /var/folders/… in /private/var/folders/…. Le voci che contengono * o ? sono trattate come glob e lasciate invariate; un percorso che non viene risolto viene mantenuto così com’è scritto.
SandboxBindMount
Sezione intitolata “SandboxBindMount”| Campo | Tipo | Descrizione |
|---|---|---|
hostPath |
String |
Percorso assoluto sull’host |
guestPath |
String |
Percorso dentro il sandbox (con il sandbox nativo coincide con hostPath; mantenuto per simmetria tra gli adapter) |
readOnly |
bool (predefinito false) |
Monta in sola lettura quando è true |
SandboxHandle
Sezione intitolata “SandboxHandle”Restituito da SandboxPort.launch:
| Campo | Tipo | Descrizione |
|---|---|---|
sessionId |
String |
Identificatore di sessione |
backend |
SandboxBackend |
Quale backend è in esecuzione |
state |
SandboxState |
Stato del ciclo di vita |
error |
Object? |
Impostato quando state è error |
details |
Map<String, Object?> |
Contabilità interna dell’adapter (directory di lavoro, PID, percorso del profilo e così via) |
SandboxState
Sezione intitolata “SandboxState”| Stato | Descrizione |
|---|---|
created |
Specifica creata ma la VM non è ancora partita |
warm |
In esecuzione e pronta a eseguire comandi |
active |
Sta eseguendo un comando |
suspended |
In pausa / con checkpoint su disco per risparmiare RAM |
destroyed |
Smantellata; l’handle non è più valido |
error |
Avvio non riuscito — vedi SandboxHandle.error |
Eventi del sandbox
Sezione intitolata “Eventi del sandbox”| Tipo di evento | Descrizione |
|---|---|
stdout |
Output standard dal sandbox |
stderr |
Errore standard dal sandbox |
exit |
Il processo del sandbox è terminato (porta exitCode) |
starting |
Il sandbox si sta avviando |
ready |
Il sandbox è pronto ad accettare chiamate exec |
killed |
Processo terminato dall’host (OOM, timeout, arresto manuale) |
violation |
Una policy del sandbox è stata violata (porta una SandboxViolation) |
SandboxViolation
Sezione intitolata “SandboxViolation”| Campo | Tipo | Descrizione |
|---|---|---|
action |
String |
Il verbo negato (ad es. file-read*, network-outbound) |
target |
String |
Percorso o host che era l’obiettivo dell’operazione negata |
raw |
String? |
Riga di log grezza, utile per il debug |
Vedi anche
Sezione intitolata “Vedi anche”- Sandbox e sicurezza
- Policy del sandbox
- Guardrail
- CLI di cc_server: il flag
--sandbox