Torna agli aggiornamenti
New releaseAug 27, 2026

sandbox-runtime v0.0.74

Uno strumento di sandboxing leggero per applicare restrizioni su filesystem e rete a processi arbitrari a livello di sistema operativo, senza richiedere un container.

Condividi

Anthropic Sandbox Runtime (srt)

Uno strumento di sandboxing leggero per applicare restrizioni sul filesystem e sulla rete a processi arbitrari a livello di sistema operativo, senza richiedere un container.

srt utilizza primitive di sandboxing native del sistema operativo (sandbox-exec su macOS, bubblewrap su Linux) e filtraggio di rete basato su proxy. Può essere utilizzato per confinare il comportamento di agenti, server MCP locali, comandi bash e processi arbitrari.

Anteprima di Ricerca Beta

Il Sandbox Runtime è un'anteprima di ricerca sviluppata per Claude Code per consentire agenti AI più sicuri. Viene resa disponibile come anteprima open source precoce per aiutare l'ecosistema più ampio a costruire sistemi agentici più sicuri. Trattandosi di un'anteprima di ricerca precoce, le API e i formati di configurazione potrebbero evolversi. Accogliamo con favore feedback e contributi per rendere gli agenti AI più sicuri per impostazione predefinita!

Installazione```bash

npm install -g @anthropic-ai/sandbox-runtime

## Utilizzo di base```bash
# Network restrictions
$ srt "curl anthropic.com"
Running: curl anthropic.com
<html>...</html>  # Request succeeds

$ srt "curl example.com"
Running: curl example.com
Connection blocked by network allowlist  # Request blocked

# Filesystem restrictions
$ srt "cat README.md"
Running: cat README.md
# Anthropic Sandb...  # Current directory access allowed

$ srt "cat ~/.ssh/id_rsa"
Running: cat ~/.ssh/id_rsa
cat: /Users/ollie/.ssh/id_rsa: Operation not permitted  # Specific file blocked

Panoramica

Questo pacchetto fornisce un'implementazione sandbox autonoma che può essere utilizzata sia come strumento CLI che come libreria. È progettato con una filosofia secure-by-default (sicuro per impostazione predefinita) adattata ai casi d'uso comuni degli sviluppatori: i processi partono con accesso minimo e si aprono esplicitamente solo i varchi necessari.

Capacità principali:

  • Restrizioni di rete: Controlla quali host/domini possono essere accessibili tramite HTTP/HTTPS e altri protocolli
  • Restrizioni del filesystem: Controlla quali file/directory possono essere letti/scritti
  • Restrizioni dei socket Unix: Controlla l'accesso ai socket IPC locali
  • Monitoraggio delle violazioni: Su macOS, accede all'archivio dei log delle violazioni della sandbox di sistema per avvisi in tempo reale

Caso d'uso di esempio: Sandboxing dei server MCP

Un caso d'uso chiave è il sandboxing dei server Model Context Protocol (MCP) per limitarne le capacità. Ad esempio, per applicare il sandboxing al server MCP del filesystem:

Senza sandboxing (.mcp.json):```json { "mcpServers": { "filesystem": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem"] } } }

**Con sandboxing** (`.mcp.json`):```json
{
  "mcpServers": {
    "filesystem": {
      "command": "srt",
      "args": ["npx", "-y", "@modelcontextprotocol/server-filesystem"]
    }
  }
}

Then configure restrictions in ~/.srt-settings.json:```json { "filesystem": { "denyRead": [], "allowWrite": ["."], "denyWrite": ["~/sensitive-folder"] }, "network": { "allowedDomains": [], "deniedDomains": [] } }

Ora al server MCP sarà impedito di scrivere nel percorso negato:```
> Write a file to ~/sensitive-folder
✗ Error: EPERM: operation not permitted, open '/Users/ollie/sensitive-folder/test.txt'

Come funziona

La sandbox utilizza primitive a livello di sistema operativo per applicare restrizioni che valgono per l'intero albero dei processi:

  • macOS: Utilizza sandbox-exec con profili Seatbelt generati dinamicamente
  • Linux: Utilizza bubblewrap per la containerizzazione con isolamento del namespace di rete
  • Windows: Esegue il processo in sandbox sotto un account utente locale dedicato srt-sandbox, con una barriera in uscita basata su Windows Filtering Platform associata al SID di quell'account e ACE espliciti per sessione sull'albero di lavoro

0d1c612947c798aef48e6ab4beb7e8544da9d41a-4096x2305

Modello di isolamento duale

Sia l'isolamento del filesystem che quello della rete sono necessari per una sandbox efficace. Senza l'isolamento dei file, un processo compromesso potrebbe esfiltrare chiavi SSH o altri file sensibili. Senza l'isolamento della rete, un processo potrebbe evadere dalla sandbox e ottenere accesso di rete senza restrizioni.

Isolamento del filesystem applica restrizioni di lettura e scrittura:

  • Lettura (pattern nega-poi-consenti): Per impostazione predefinita, l'accesso in lettura è consentito ovunque. È possibile negare ampie regioni (ad es. /Users) e poi ri-consentire percorsi specifici al loro interno (ad es. .). allowRead ha la precedenza su denyRead — l'opposto della scrittura, dove denyWrite ha la precedenza su allowWrite. Una voce denyRead più specifica della regione allowRead in cui ricade (ad es. denyRead: ["**/.env"] o ["./secrets"] con allowRead: ["."]) rimane comunque negata.
  • Scrittura (pattern solo-consenti): Per impostazione predefinita, l'accesso in scrittura è negato ovunque. È necessario consentire esplicitamente i percorsi (ad es. ., /tmp). Una lista di consensi vuota significa nessun accesso in scrittura.

Isolamento della rete (pattern solo-consenti): Per impostazione predefinita, tutto l'accesso alla rete è negato. È necessario consentire esplicitamente i domini. Una lista allowedDomains vuota significa nessun accesso alla rete. Il traffico di rete viene instradato attraverso server proxy in esecuzione sull'host:

  • Linux: Le richieste vengono instradate tramite il filesystem attraverso un socket di dominio Unix. Il namespace di rete del processo in sandbox viene rimosso completamente, quindi tutto il traffico di rete deve passare attraverso i proxy in esecuzione sull'host (in ascolto su socket Unix che vengono montati tramite bind nella sandbox)

  • macOS: Il profilo Seatbelt consente la comunicazione solo verso una specifica porta localhost. I proxy sono in ascolto su questa porta, creando un canale controllato per tutto l'accesso alla rete

  • Windows: Un set di filtri WFP a livello di macchina blocca tutte le connessioni in uscita provenienti dall'account srt-sandbox tranne il loopback verso l'intervallo di porte del proxy. I proxy sono in ascolto all'interno di tale intervallo, creando un canale controllato per tutto l'accesso alla rete

Sia il traffico HTTP/HTTPS (tramite proxy HTTP) che altro traffico TCP (tramite proxy SOCKS5) sono mediati da questi proxy, che applicano le liste di domini consentiti e negati.

Per maggiori dettagli sul sandboxing in Claude Code, consulta:

Architettura```

src/ ├── index.ts # Library exports ├── cli.ts # CLI entrypoint (srt command) ├── utils/ # Shared utilities │ ├── debug.ts # Debug logging │ ├── settings.ts # Settings reader (permissions + sandbox config) │ ├── platform.ts # Platform detection │ └── exec.ts # Command execution utilities └── sandbox/ # Sandbox implementation ├── sandbox-manager.ts # Main sandbox manager ├── sandbox-schemas.ts # Zod schemas for validation ├── sandbox-violation-store.ts # Violation tracking ├── sandbox-utils.ts # Shared sandbox utilities ├── http-proxy.ts # HTTP/HTTPS proxy for network filtering ├── socks-proxy.ts # SOCKS5 proxy for network filtering ├── linux-sandbox-utils.ts # Linux bubblewrap sandboxing ├── macos-sandbox-utils.ts # macOS sandbox-exec sandboxing └── windows-sandbox-utils.ts # Windows srt-win sandboxing

## Utilizzo

### Come strumento CLI

Il comando `srt` (Anthropic Sandbox Runtime) avvolge qualsiasi comando con confini di sicurezza:```bash
# Run a command in the sandbox
srt echo "hello world"

# With debug logging
srt --debug curl https://example.com

# Specify custom settings file
srt --settings /path/to/srt-settings.json npm install

Come libreria```typescript

import { SandboxManager, type SandboxRuntimeConfig, } from '@anthropic-ai/sandbox-runtime' import { spawn } from 'child_process'

// Define your sandbox configuration const config: SandboxRuntimeConfig = { network: { allowedDomains: ['example.com', 'api.github.com'], deniedDomains: [], }, filesystem: { denyRead: ['~/.ssh'], allowWrite: ['.', '/tmp'], denyWrite: ['.env'], }, }

// Initialize the sandbox (starts proxy servers, etc.) await SandboxManager.initialize(config)

// Wrap a command with sandbox restrictions const sandboxedCommand = await SandboxManager.wrapWithSandbox( 'curl https://example.com', )

// Execute the sandboxed command const child = spawn(sandboxedCommand, { shell: true, stdio: 'inherit' })

// Handle exit and cleanup after child process completes child.on('exit', async code => { console.log(Command exited with code ${code}) // Cleanup when done (optional, happens automatically on process exit) await SandboxManager.reset() })

**Attribuzione delle violazioni (`commandId` / `commandText`).** Le violazioni osservate durante l'esecuzione di un comando wrappato (righe di log di seatbelt, eventi seccomp, deny del proxy) vengono memorizzate sotto una chiave di attribuzione, e `annotateStderrWithSandboxFailures(key, stderr)` / `getViolationsForCommand(key)` le cercano tramite quella stessa chiave. Per impostazione predefinita la chiave è la stringa wrappata stessa. Passa un `commandId` opaco per singola invocazione (ad es. un id di tool-use) per usare quello come chiave — consigliato: le chiavi vengono confrontate sui loro primi 100 caratteri, quindi comandi lunghi che condividono un prefisso verrebbero altrimenti attribuiti in modo incrociato, e una riesecuzione dello stesso testo erediterebbe gli eventi dell'esecuzione precedente. Se la stringa che *esegui* non è il comando che l'invocazione *rappresenta* (ad es. wrappi un `source <snapshot> && eval '<cmd>'` assemblato), passa anche `commandText: '<cmd>'`: è ciò contro cui vengono confrontati i pattern di comando di `ignoreViolations` e ciò che ogni violazione riporta come proprio `command`.```typescript
const wrapped = await SandboxManager.wrapWithSandbox(
  assembledCommand, // what actually runs
  undefined,
  undefined,
  undefined,
  { commandId: invocationId, commandText: rawCommand },
)
// ... run it ...
const annotated = SandboxManager.annotateStderrWithSandboxFailures(invocationId, stderr)

Export disponibili```typescript

// Main sandbox manager export { SandboxManager } from '@anthropic-ai/sandbox-runtime'

// Violation tracking export { SandboxViolationStore } from '@anthropic-ai/sandbox-runtime'

// TypeScript types export type { SandboxRuntimeConfig, NetworkConfig, FilesystemConfig, IgnoreViolationsConfig, SandboxAskCallback, FsReadRestrictionConfig, FsWriteRestrictionConfig, NetworkRestrictionConfig, } from '@anthropic-ai/sandbox-runtime'

## Configurazione

### Posizione del file delle impostazioni

Per impostazione predefinita, il runtime della sandbox cerca la configurazione in `~/.srt-settings.json`. È possibile specificare un percorso personalizzato utilizzando il flag `--settings`:```bash
srt --settings /path/to/srt-settings.json <command>

Esempio di configurazione completa```json

{ "network": { "allowedDomains": [ "github.com", ".github.com", "lfs.github.com", "api.github.com", "npmjs.org", ".npmjs.org" ], "deniedDomains": ["malicious.com"], "allowUnixSockets": ["/var/run/docker.sock"], "allowLocalBinding": false }, "filesystem": { "denyRead": ["~/.ssh"], "allowRead": [], "allowWrite": [".", "src/", "test/", "/tmp"], "denyWrite": [".env", "config/production.json"] }, "ignoreViolations": { "*": ["/usr/bin", "/System"], "git push": ["/usr/bin/nc"], "npm": ["/private/tmp"] }, "enableWeakerNestedSandbox": false, "enableWeakerNetworkIsolation": false, "allowAppleEvents": false }

### Opzioni di configurazione

#### Configurazione di rete

Utilizza un **pattern allow-only** - tutto l'accesso alla rete è negato per impostazione predefinita.

- `network.allowedDomains` - Array di domini consentiti (supporta wildcard come `*.example.com`). Array vuoto = nessun accesso alla rete. Un suffisso opzionale `:port` (`api.example.com:443`, `*.example.com:8443`) limita una voce a quella porta di destinazione; le voci senza porta corrispondono a qualsiasi porta.
  - I letterali IPv6 devono essere racchiusi tra parentesi quadre, in stile RFC 3986: `[::1]`, `[2001:db8::1]:443`. Una voce non racchiusa tra parentesi con più due punti viene rifiutata come ambigua (`2001:db8::1:443` è di per sé un indirizzo valido).
- `network.deniedDomains` - Array di domini negati (verificati per primi, hanno precedenza su allowedDomains). Stesso suffisso `:port`, e un `*` nudo (o `*:22`) è accettato per negare tutto.
- `network.deniedDomainReasons` - Mappa opzionale da una voce di `deniedDomains` (corrispondenza per stringa esatta) a un motivo rivolto al modello che appare nella riga `<sandbox_violations>` quando quella voce nega una connessione — indica cosa è bloccato e l'alternativa autorizzata (ad es. `{"github.com:22": "SSH pushes to GitHub are blocked; use an https:// remote"}`). Le voci senza motivo riportano uno generico. Per le destinazioni SSH (porta 22), il motivo viene anche consegnato in-band: un client SSH incanalato attraverso un ProxyCommand SOCKS senza autenticazione (ad es. BSD `nc -X 5`) riceve una disconnessione SSH pre-scambio-di-chiavi la cui descrizione è il motivo, che OpenSSH stampa testualmente — mantieni tali motivi sotto ~400 caratteri ASCII, con l'imperativo all'inizio, poiché OpenSSH tronca ed esegue l'escape dei caratteri non ASCII.
- `network.allowLocalBinding` - Consente il binding a porte locali (booleano, predefinito: false)

**Verifica dell'indirizzo risolto.** Le liste allow/deny corrispondono per _nome_, ma chi controlla il DNS di un nome consentito (o qualsiasi etichetta sotto un wildcard consentito) controlla ciò a cui esso si risolve. Quindi, prima di contattare direttamente un **hostname** consentito, il proxy lo risolve una volta, scarta qualsiasi indirizzo in un insieme negato e si connette a un indirizzo sopravvissuto (l'indirizzo che ha superato la verifica è quello contattato — non c'è una seconda risoluzione). Se nulla sopravvive, la connessione viene rifiutata come qualsiasi altra negazione di policy: HTTP/CONNECT ricevono `403` (`X-Proxy-Error: blocked-by-sandbox-runtime`, con il motivo nel corpo), SOCKS riceve "connection not allowed by ruleset", e una riga `deny network-outbound host:port (resolved to a loopback address)` — che nomina la classe di indirizzo (loopback, link-local, di questo host, cloud metadata, in deny-list, in lista, …), non l'indirizzo stesso, che è riportato solo nel log di debug — viene registrata nell'archivio delle violazioni.

L'insieme negato è: loopback (`127.0.0.0/8`, `::1`), non specificato (`0.0.0.0/8`, `::`), link-local (`169.254.0.0/16`, `fe80::/10`), multicast (`224.0.0.0/4`, `ff00::/8`), broadcast, gli endpoint di metadati dell'istanza cloud / della piattaforma che risiedono al di fuori del link-local (`100.100.100.200`, `168.63.129.16`, `192.0.0.192`, `fd00:ec2::/32`, `fd20:ce::254`, `fd00:c1::a9fe:a9fe`, `fd00:42::42`), ogni indirizzo attualmente assegnato a una delle interfacce di rete di questo host (un servizio in ascolto su `0.0.0.0` risponde sulla LAN o sull'indirizzo globale esattamente come fa su loopback), ogni letterale IP elencato in `deniedDomains` (onorando il suo `:port` se ne ha uno), e qualsiasi cosa in `deniedResolvedAddresses`. Le voci IPv4 corrispondono anche alle forme IPv6 che trasportano un indirizzo IPv4 — gli indirizzi IPv4-mapped, IPv4-compatible e IPv4-translated, il prefisso well-known NAT64 (`64:ff9b::/96`) e 6to4 (`2002::/16`) sono giudicati in base all'indirizzo IPv4 che incorporano. Il prefisso NAT64 local-use `64:ff9b:1::/48` e i prefissi specifici della rete non vengono decodificati — il loro layout (RFC 6052 consente l'IPv4 in diverse posizioni) non può essere riconosciuto dal solo indirizzo; su una tale rete, elenca le traduzioni del prefisso degli intervalli che neghi (ad es. `<prefix>::a00:0/104` per `10.0.0.0/8`). Gli indirizzi che raggiungono questo host senza essergli assegnati — l'indirizzo pubblico 1:1-NAT di un'istanza cloud, un port-forward di un router, un alias host-gateway di un container o VM — non sono coperti automaticamente; elencali in `deniedResolvedAddresses`.

Ciò che la verifica lascia stare: le voci della allowlist che **sono** letterali IP (inserire in allowlist `127.0.0.1:3000` è una scelta esplicita) — e, per lo stesso motivo, un hostname può risolversi a un indirizzo altrimenti negato quando quel letterale IP (su quella porta) è esso stesso in `allowedDomains`, poiché raggiungerlo per nome non concede nulla che la voce letterale non conceda già (un letterale IP in `deniedDomains` vince comunque, esattamente come fa per una richiesta letterale). Quindi un setup di sviluppo in cui `myapp.test` mappa a un server locale tramite `/etc/hosts` inserisce in allowlist `["myapp.test", "127.0.0.1:3000"]`; non esiste una lista di eccezioni separata. `localhost` e i nomi sotto `.localhost` si risolvono a loopback (o a un letterale in allowlist) e nient'altro. La verifica non viene valutata per le connessioni instradate attraverso `parentProxy` (incluso uno rilevato da `HTTP_PROXY` / `HTTPS_PROXY` nell'ambiente di srt stesso) o `mitmProxy` — quel salto risolve il nome e possiede la propria policy sugli indirizzi — e governa solo ciò che il proxy contatta: su macOS, `allowLocalBinding` consente separatamente al processo in sandbox di connettersi a porte loopback senza passare affatto attraverso il proxy.

- `network.deniedResolvedAddresses` - Indirizzi IP / intervalli CIDR extra (IPv4 o IPv6, senza parentesi, qualsiasi porta) a cui gli hostname consentiti non devono risolversi. Lo spazio a uso privato non è negato per impostazione predefinita perché inserire in allowlist un hostname di intranet è legittimo; elencalo qui quando i nomi in allowlist devono restarne fuori, ad es. `["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16", "100.64.0.0/10", "fc00::/7"]`. Elenca gli intervalli IPv4 e IPv6 separatamente — un intervallo IPv6 abbastanza ampio da coprire il blocco IPv4-mapped (`::ffff:0:0/96`), come `::/0`, corrisponde alle risposte IPv4 su alcuni runtime ma non su altri, quindi non fare affidamento su di esso per negare IPv4.

**Terminazione TLS** (`network.tlsTerminate`, sperimentale): quando impostata, i CONNECT HTTPS vengono terminati in-process così che SRT possa vedere (e filtrare, tramite `network.filterRequest`) le richieste decifrate. Il processo in sandbox viene indirizzato a un trust bundle contenente la CA MITM (`caCertPath`/`caKeyPath`, o una CA effimera se omessi) più le root regolari dell'host, così sia i certificati emessi dal proxy sia i certificati upstream reali vengono verificati.

- `network.tlsTerminate.excludeDomains` - Pattern di dominio (stessa sintassi di `allowedDomains`) che **non** vengono terminati. I CONNECT corrispondenti vengono invece incanalati in modo opaco: sono comunque soggetti alla allowlist dei domini, ma il client all'interno della sandbox completa il proprio handshake TLS con l'upstream reale, e `filterRequest` / l'iniezione delle credenziali non si applicano al loro traffico HTTPS. Usalo per i due casi che la terminazione TLS rompe fondamentalmente:
  - **Upstream mTLS** - solo il client nella sandbox possiede il certificato client, quindi il proxy non può ri-originare la connessione per suo conto.
  - **Client con certificate-pinning** - client che verificano da soli l'identità dell'upstream (CA personalizzate, SAN pinning) e rifiutano il certificato MITM.
- `network.tlsTerminate.extraCaCertPaths` - Percorsi a file di certificati CA PEM aggiunti a quel trust bundle, dopo la CA MITM e le root regolari dell'host. Gli host esclusi (non terminati) vengono verificati dal client all'interno della sandbox, e le variabili d'ambiente di trust impostate da SRT (`SSL_CERT_FILE`, `GIT_SSL_CAINFO`, ...) _sostituiscono_ la configurazione di trust propria di ciascuno strumento, quindi una root locale al sito (ad es. una CA mTLS interna) deve essere nel bundle, altrimenti quegli host non potranno mai essere verificati. Solo i blocchi `CERTIFICATE` di ciascun file vengono copiati nel bundle (qualsiasi altra cosa, ad es. una chiave privata in un PEM combinato, non viene mai esposta alla sandbox); i file mancanti, illeggibili o che non contengono alcun blocco `CERTIFICATE` PEM vengono saltati, quindi è sicuro elencare percorsi che esistono solo su alcuni host.```json
{
  "network": {
    "allowedDomains": ["*.example.com", "internal-mtls.example.net"],
    "deniedDomains": [],
    "tlsTerminate": {
      "excludeDomains": ["internal-mtls.example.net"],
      "extraCaCertPaths": ["/etc/internal-mtls-roots.pem"]
    }
  }
}

Impostazioni dei socket Unix (comportamento specifico per piattaforma):

ImpostazionemacOSLinux
allowUnixSockets: string[]Allowlist dei percorsi socketIgnorato (seccomp non può filtrare per percorso)
allowAllUnixSockets: booleanConsenti tutti i socketDisabilita il blocco seccomp

I socket Unix sono bloccati per impostazione predefinita su entrambe le piattaforme.

  • macOS: Usa allowUnixSockets per consentire percorsi specifici (ad es., ["/var/run/docker.sock"]), oppure allowAllUnixSockets: true per consentirli tutti.
  • Linux: Il blocco utilizza filtri seccomp (solo x64/arm64). Se seccomp non è disponibile, i socket sono senza restrizioni e viene mostrato un avviso. Usa allowAllUnixSockets: true per disabilitare esplicitamente il blocco.

Configurazione del filesystem

Utilizza due pattern diversi:

Restrizioni di lettura (pattern deny-then-allow) - tutte le letture consentite per impostazione predefinita:

  • filesystem.denyRead - Array di percorsi a cui negare l'accesso in lettura. Array vuoto = accesso completo in lettura.
  • filesystem.allowRead - Array di percorsi a cui ri-consentire l'accesso in lettura all'interno delle regioni negate (ha precedenza su denyRead). Nota: questo è l'opposto della scrittura, dove denyWrite ha precedenza su allowWrite.

Restrizioni di scrittura (pattern allow-only) - tutte le scritture negate per impostazione predefinita:

  • filesystem.allowWrite - Array di percorsi a cui consentire l'accesso in scrittura. Array vuoto = nessun accesso in scrittura.
  • filesystem.denyWrite - Array di percorsi a cui negare l'accesso in scrittura all'interno dei percorsi consentiti (ha precedenza su allowWrite)

Sintassi dei percorsi (macOS):

I percorsi supportano pattern glob in stile git su macOS, simili alla sintassi di .gitignore:

  • * - Corrisponde a qualsiasi carattere tranne / (ad es., *.ts corrisponde a foo.ts ma non a foo/bar.ts)
  • ** - Corrisponde a qualsiasi carattere incluso / (ad es., src/**/*.ts corrisponde a tutti i file .ts in src/)
  • ? - Corrisponde a qualsiasi singolo carattere tranne / (ad es., file?.txt corrisponde a file1.txt)
  • [abc] - Corrisponde a qualsiasi carattere nell'insieme (ad es., file[0-9].txt corrisponde a file3.txt)

Esempi:

  • "allowWrite": ["src/"] - Consenti la scrittura nell'intera directory src/
  • "allowWrite": ["src/**/*.ts"] - Consenti la scrittura in tutti i file .ts in src/ e nelle sottodirectory
  • "denyRead": ["~/.ssh"] - Nega la lettura alla directory SSH
  • "denyRead": ["/Users"], "allowRead": ["."] - Nega la lettura a tutto /Users, ma ri-consenti la directory corrente
  • "denyWrite": [".env"] - Nega la scrittura al file .env (anche se la directory corrente è consentita)

Sintassi dei percorsi (Linux):

Linux attualmente non supporta la corrispondenza glob. Usa solo percorsi letterali:

  • "allowWrite": ["src/"] - Consenti la scrittura nella directory src/
  • "denyRead": ["/home/user/.ssh"] - Nega la lettura alla directory SSH
  • "denyRead": ["/home"], "allowRead": ["."] - Nega la lettura a tutto /home, ma ri-consenti la directory corrente

Tutte le piattaforme:

  • I percorsi possono essere assoluti (ad es., /home/user/.ssh) o relativi alla directory di lavoro corrente (ad es., ./src)
  • ~ si espande nella directory home dell'utente

Altre configurazioni

  • ignoreViolations - Oggetto che mappa pattern di comandi ad array di percorsi in cui le violazioni devono essere ignorate
  • enableWeakerNestedSandbox - Abilita la modalità sandbox più debole per ambienti Docker (booleano, predefinito: false)
  • javaAgentJarPath - macOS/Linux: percorso assoluto a srt-proxy-agent.jar, l'agente JVM iniettato tramite JAVA_TOOL_OPTIONS (vedi "JVM tools" in Network Isolation). Necessario solo per i consumer che includono sandbox-runtime e distribuiscono il jar separatamente; una normale installazione npm lo trova in vendor/java-proxy-agent/.
  • enableWeakerNetworkIsolation - Consenti l'accesso a com.apple.trustd.agent nel sandbox macOS (booleano, predefinito: false). Questo è necessario per i programmi Go (gh, gcloud, terraform, kubectl, ecc.) per verificare i certificati TLS quando si utilizza httpProxyPort con un proxy MITM e una CA personalizzata. Avviso di sicurezza: abilitare questa opzione apre un potenziale vettore di esfiltrazione dati attraverso il servizio trustd.
  • allowAppleEvents - Consenti l'invio di Apple Events e richieste di apertura Launch Services dal sandbox macOS (booleano, predefinito: false). Senza questo, comandi come open, osascript e qualsiasi cosa che apra URL o script di altre app tramite AppleScript falliscono con l'errore AppleScript -600 ("Application isn't running") o errori LaunchServices (-10822, -54). Avviso di sicurezza: abilitare questa opzione significa che il sandbox non fornisce più isolamento dell'esecuzione del codice. Un comando in sandbox può avviare altre applicazioni tramite open senza alcun prompt utente, e qualsiasi cosa avvii viene eseguita al di fuori delle restrizioni di filesystem e rete del sandbox; lo scripting di app già in esecuzione tramite Apple Events è inoltre vincolato dal consenso di automazione TCC per-app dell'utente. Gli embedder dovrebbero ottenere questa opzione solo da configurazioni affidabili a livello utente — mai da file locali al progetto in un repository checked-out, il che permetterebbe a un progetto creato da un attaccante di elevare i propri permessi di sandbox.

Ricette di configurazione comuni

Consenti accesso a GitHub (tutti gli endpoint necessari):```json { "network": { "allowedDomains": [ "github.com", "*.github.com", "lfs.github.com", "api.github.com" ], "deniedDomains": [] }, "filesystem": { "denyRead": [], "allowWrite": ["."], "denyWrite": [] } }

**Limita a directory specifiche:**```json
{
  "network": {
    "allowedDomains": [],
    "deniedDomains": []
  },
  "filesystem": {
    "denyRead": ["~/.ssh"],
    "allowWrite": [".", "src/", "test/"],
    "denyWrite": [".env", "secrets/"]
  }
}

Accesso al filesystem solo nella workspace (nega le letture al di fuori della workspace):```json { "network": { "allowedDomains": [], "deniedDomains": [] }, "filesystem": { "denyRead": ["/Users"], "allowRead": ["."], "allowWrite": ["."], "denyWrite": [] } }

Questo nega la lettura di qualsiasi cosa sotto `/Users` (o `/home` su Linux), poi ri-consente la directory di lavoro corrente. I percorsi di sistema (`/usr`, `/lib`, ecc.) rimangono leggibili.

### Problemi comuni e suggerimenti

**Esecuzione di Jest:** Usa il flag `--no-watchman` per evitare violazioni della sandbox:```bash
srt "jest --no-watchman"

Watchman accede a file al di fuori dei confini della sandbox, il che attiverà errori di autorizzazione. Disabilitarlo consente a Jest di funzionare con il file watcher integrato.

Supporto Piattaforme

  • macOS: Utilizza sandbox-exec con profili personalizzati (nessuna dipendenza aggiuntiva)
  • Linux: Utilizza bubblewrap (bwrap) per la containerizzazione
  • Windows: Alpha — utilizza un helper srt-win.exe incluso (nessuna dipendenza aggiuntiva). Vedi Windows (alpha) di seguito per la configurazione, il modello di sicurezza e le limitazioni note

Dipendenze Specifiche per Piattaforma

Linux richiede:

  • bubblewrap - Runtime del container
    • Ubuntu/Debian: apt-get install bubblewrap
    • Fedora: dnf install bubblewrap
    • Arch: pacman -S bubblewrap
  • socat - Relay socket per il bridging del proxy
    • Ubuntu/Debian: apt-get install socat
    • Fedora: dnf install socat
    • Arch: pacman -S socat
  • ripgrep - Strumento di ricerca veloce per il rilevamento dei percorsi negati
    • Ubuntu/Debian: apt-get install ripgrep
    • Fedora: dnf install ripgrep
    • Arch: pacman -S ripgrep

Nota per Ubuntu 24.04+: Queste release abilitano kernel.apparmor_restrict_unprivileged_userns per impostazione predefinita, il che consente unshare(CLONE_NEWUSER) ma rimuove le capability dal namespace risultante. Sia bubblewrap che il livello di isolamento seccomp necessitano di user namespace con capability. Disabilita la restrizione con:```bash sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0

oppure aggiungi un profilo AppArmor che conceda `userns` ai binari pertinenti.

**Dipendenze Linux opzionali (per il fallback seccomp):**

Il pacchetto include filtri seccomp BPF pre-generati per le architetture x86-64 e arm. Queste dipendenze sono necessarie solo se ti trovi su un'architettura diversa in cui i filtri pre-generati non sono disponibili:

- `gcc` o `clang` - Compilatore C
- `libseccomp-dev` - File di sviluppo della libreria Seccomp
  - Ubuntu/Debian: `apt-get install gcc libseccomp-dev`
  - Fedora: `dnf install gcc libseccomp-devel`
  - Arch: `pacman -S gcc libseccomp`

**macOS richiede:**

- `ripgrep` - Strumento di ricerca veloce per il rilevamento dei percorsi negati
  - Installa tramite Homebrew: `brew install ripgrep`
  - Oppure scarica da: https://github.com/BurntSushi/ripgrep/releases

**Windows richiede:**

- Nessuna dipendenza aggiuntiva. L'helper `srt-win.exe` (x64 e arm64) è incluso nel pacchetto npm. È richiesto un passaggio `windows-install` con privilegi elevati una tantum — vedi sotto.

## Windows (alpha)

Il supporto Windows è in **alpha**. Il processo in sandbox viene eseguito sotto un account utente locale dedicato `srt-sandbox`, isolato dall'utente chiamante tramite primitive di sicurezza native di Windows — una barriera di uscita Windows Filtering Platform (WFP) basata sul SID dell'account sandbox, e ACE espliciti per sessione che concedono o negano a tale SID l'accesso ai percorsi del filesystem configurati.

### Configurazione

Esegui una volta per macchina (si auto-eleva; un prompt UAC):```powershell
npx @anthropic-ai/sandbox-runtime windows-install

Questo effettua il provisioning dell'account utente locale srt-sandbox (con una password casuale memorizzata cifrata con DPAPI in HKLM\SOFTWARE\sandbox-runtime — a livello di macchina, così le installazioni su flotta in esecuzione come SYSTEM funzionano e la rotazione di un utente aggiorna la copia che gli altri leggono), del gruppo locale sandbox-runtime-users, e installa un set di filtri WFP a livello di macchina basato sul SID di srt-sandbox. È idempotente — rieseguirlo ruota la password dell'account sandbox e riconcilia il set di filtri.

Non è richiesto alcun logout. I filtri WFP si basano sul SID dell'account sandbox dedicato, quindi la tua rete, i servizi e ogni altro principal sulla macchina non sono interessati.

Dopo l'installazione, SandboxManager.initialize() e la CLI srt funzionano come sulle altre piattaforme. initialize() verifica che l'account sandbox e la barriera WFP siano attivi, e fallisce con un errore azionabile in caso contrario.

L'installazione/disinstallazione programmatica è esportata come installWindowsSandbox() / uninstallWindowsSandbox().

Modello di sicurezza

Il comando sandboxed viene eseguito come account srt-sandbox, non come utente chiamante. L'helper srt-win.exe incluso esegue un avvio a due salti: il broker chiama CreateProcessWithLogonW per avviare un runner come srt-sandbox, e il runner genera il target sotto un token ristretto all'interno di un job object. Il figlio eredita il profilo isolato dell'account sandbox (%USERPROFILE%, %TEMP%, HKCU) e un ambiente nuovo sovrapposto solo con il PATH del broker e le variabili proxy generate.

L'esecuzione sotto un SID utente distinto chiude strutturalmente la classe di escape del tipo surrogate-spawn (Task Scheduler, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS su un processo di proprietà del broker, BITS, COM out-of-process con RunAs="Interactive User"): qualsiasi processo che il figlio riesca a generare fuori banda porta comunque il SID srt-sandbox, quindi rimane soggetto alla barriera di egress WFP e non ha diritti sui file dell'utente chiamante.

L'isolamento di rete è un set WFP a due filtri a livello FWPM_LAYER_ALE_AUTH_CONNECT_V4/V6: un PERMIT per destinazioni loopback all'interno dell'intervallo di porte proxy configurato (predefinito 60080–60089), e un BLOCK per qualsiasi connessione il cui token porti il SID srt-sandbox. Il processo sandboxed raggiunge internet solo tramite i proxy JS HTTP/SOCKS5 in ascolto in quell'intervallo; un processo che rimuove il proprio ambiente proxy e si connette direttamente viene bloccato a livello di kernel.

L'isolamento del filesystem è applicato tramite ACL discrezionali NTFS. L'account srt-sandbox non ha diritti intrinseci sui file dell'utente chiamante, quindi a initialize() la sandbox scrive ACE espliciti additivi e con ereditarietà solo per il SID srt-sandbox — non riscrive né sostituisce mai il security descriptor esistente di un percorso:

  • filesystem.allowWrite → un ACE ALLOW MODIFY con ereditarietà (READ|WRITE|EXECUTE|DELETE, con FILE_DELETE_CHILD escluso). Il processo sandboxed può creare, modificare ed eliminare file all'interno dell'albero di lavoro; l'esclusione di FILE_DELETE_CHILD dalla concessione è difesa in profondità per i deny stamp sottostanti, non una protezione sulla radice dell'albero.
  • filesystem.allowRead → un ACE ALLOW READ|EXECUTE con ereditarietà
  • filesystem.denyRead / filesystem.denyWrite → un ACE DENY con ereditarietà sul target, più un DENY FILE_DELETE_CHILD con ereditarietà sul suo genitore — insieme al FILE_DELETE_CHILD escluso sulla concessione dell'albero di lavoro, questo impedisce al processo sandboxed di rinominare o eliminare un percorso negato tramite la sua directory genitore

reset() rimuove ogni ACE aggiunto da questa sessione (con conteggio dei riferimenti tra gli host concorrenti di questo utente tramite il DB di sessione per utente; una passata di crash-recovery al successivo initialize() ripulisce dopo un'uscita non pulita). I target di directory sono supportati (gli ACE ereditano all'intero sottoalbero). I pattern glob vengono espansi in percorsi concreti al momento di initialize() — un percorso corrispondente che appare successivamente non è coperto.

Terminazione TLS su Windows

network.tlsTerminate richiede che la CA MITM sia presente nell'archivio certificati CurrentUser\Root dell'utente sandbox (schannel — il backend TLS usato da System32\curl.exe, PowerShell Invoke-WebRequest, .NET e git con backend predefinito — si fida solo dell'archivio del sistema operativo, non delle variabili d'ambiente). Questo è un passaggio in fase di installazione, separato da windows-install:```typescript import { windowsTrustCa } from '@anthropic-ai/sandbox-runtime' windowsTrustCa('/path/to/mitm-ca.crt') // or: srt-win user trust-ca

`initialize()` confronta il thumbprint della CA di sessione con quello installato e fallisce con un messaggio actionable in caso di mancata corrispondenza, così una CA obsoleta installata al momento dell'installazione non può interrompere silenziosamente il TLS all'interno della sandbox.

I client basati su OpenSSL (`curl` di msys2, `git -c http.sslBackend=openssl`, Node, Python, cargo) sono coperti dal livello di trust basato su variabili d'ambiente: lo stesso bundle di trust usato su macOS/Linux viene passato nella sandbox tramite `NODE_EXTRA_CA_CERTS`, `SSL_CERT_FILE`, `CURL_CA_BUNDLE`, `GIT_SSL_CAINFO`, `CARGO_HTTP_CAINFO`, ecc., e il percorso del bundle viene aggiunto alla concessione `allowRead` della sessione in modo che l'account della sandbox possa aprirlo.

### Configurazione specifica per Windows

I blocchi cross-platform `filesystem` e `network` si applicano come descritto sopra. Le impostazioni specifiche di Windows risiedono sotto `windows`:

- `windows.proxyPortRange` — intervallo di porte inclusivo `[low, high]` in cui si legano i proxy JS. **Deve corrispondere** all'intervallo passato a `windows-install --proxy-port-range` (predefinito `[60080, 60089]`) — il PERMIT del loopback WFP copre solo quell'intervallo.
- `windows.sublayerGuid` — GUID del sublayer WFP sotto cui sono stati installati i filtri. Omettere per usare il valore predefinito in fase di compilazione; impostare solo quando strumenti enterprise hanno installato i filtri sotto un sublayer personalizzato.
- `windows.srtWin.path` — percorso del binario `srt-win`. Omettere per risolvere il pacchetto `vendor/srt-win/<arch>/srt-win.exe`. Impostare quando si incorpora la CLI di `srt-win` in un binario multicall; gli spawn passano quindi `--srt-win` come `argv[1]` in modo che il dispatcher dell'embedder possa instradare verso `srt_win::run_from_args`.

### Limitazioni note

- **Revoca dei certificati sotto schannel.** Il recupero CRL/OCSP di CryptoAPI esce tramite WinHTTP sotto il token del chiamante, ignorando l'ambiente del proxy, quindi viene bloccato dal fence di egress WFP. Gli strumenti che usano schannel con il controllo di revoca attivo per impostazione predefinita falliscono con `CRYPT_E_REVOCATION_OFFLINE` (`0x80092013`) a meno che la revoca non venga disabilitata per singolo strumento: `curl --ssl-no-revoke`, `git -c http.schannelCheckRevoke=false`, `CARGO_HTTP_CHECK_REVOKE=false`. `Invoke-WebRequest`, `HttpClient` di .NET e `gh` non controllano la revoca per impostazione predefinita e non sono interessati. È previsto un punto di distribuzione CRL servito dal proxy di loopback per rimuovere questa soluzione alternativa.
- **Le installazioni di strumenti per-utente non sono raggiungibili.** Il processo in sandbox viene eseguito come `srt-sandbox`, non come te, quindi gli strumenti installati sotto il tuo profilo (Node gestito da nvm/fnm, pacchetti `winget`/Scoop per-utente, `pip install --user`, `%LOCALAPPDATA%\Programs\…`) vengono risolti sul `PATH` ereditato ma non possono essere aperti dall'account della sandbox. Preferisci installazioni a livello macchina (`Program Files`, `choco`/`winget --scope machine`), oppure aggiungi i percorsi specifici del profilo a `filesystem.allowRead`.
- **Gli override per-exec di `filesystem.allowRead` / `filesystem.allowWrite` non sono supportati.** `allowRead`/`allowWrite` a livello di sessione (nella config passata a `initialize()`) funzionano come descritto sopra; passarli per-comando nel `customConfig` di `wrapWithSandbox` genera un errore — le concessioni vengono applicate a livello di sessione tramite `srt-win acl grant` in `initialize()`, e `srt-win exec` espone solo i deny per-exec.
- **`proxyAuthToken` è visibile nella command line del runner.** L'ambiente del proxy (incluso `HTTP_PROXY=http://srt:<token>@127.0.0.1:…`) viene passato al runner a due hop come argomenti `--env` sull'argv di `srt-win exec`, quindi il token è leggibile da qualsiasi principal locale che possa aprire il processo del runner per `PROCESS_QUERY_LIMITED_INFORMATION`. Il token esiste affinché il processo in sandbox possa autenticarsi al proxy di loopback, quindi non è un segreto rispetto alla sandbox stessa; su una macchina di sviluppo mono-utente questo è generalmente accettabile, ma su un host condiviso considera l'allowlist del proxy come raggiungibile da altri principal della stessa sessione.
- **La risoluzione DNS tramite il resolver di sistema non è sottoposta a fence.** `getaddrinfo()` è servito dal servizio `Dnscache` in esecuzione come `NETWORK SERVICE`, quindi la risoluzione dei nomi riesce anche se la successiva `connect()` dal processo in sandbox viene bloccata. Gli strumenti che fanno il proprio UDP/53 (`nslookup`, `dig`) sono sottoposti a fence. Questo rispecchia il comportamento di macOS.

### Disinstallazione```powershell
npx @anthropic-ai/sandbox-runtime windows-uninstall

Rimuove il set di filtri WFP, l'account srt-sandbox e il suo profilo, il gruppo sandbox-runtime-users, e rimuove la chiave HKLM\SOFTWARE\sandbox-runtime (credenziale, marker, record CA) — un solo prompt UAC. %ProgramData%\sandbox-runtime (il materiale della chiave CA) viene lasciato in posizione; eliminalo (e %LOCALAPPDATA%\sandbox-runtime per utente) manualmente per una pulizia completa.

Sviluppo```bash

Install dependencies

npm install

Build the project

npm run build

Run tests

npm test

Type checking

npm run typecheck

Lint code

npm run lint

Format code

npm run format

### Compilazione dei binari Seccomp

Il filtro BPF e il loader `apply-seccomp` vengono compilati dal codice sorgente C in `vendor/seccomp-src/` tramite `npm run build:seccomp` (solo Linux; richiede `gcc` e `libseccomp-dev`). La CI lo esegue prima dei test su ogni architettura Linux, e il workflow di release compila entrambe le architetture e le include nel pacchetto pubblicato.

## Dettagli di implementazione

### Architettura di isolamento di rete

La sandbox esegue server proxy HTTP e SOCKS5 sulla macchina host che filtrano tutte le richieste di rete in base alle regole di autorizzazione:

1. **Traffico HTTP/HTTPS**: un server proxy HTTP intercetta le richieste e le convalida rispetto ai domini consentiti/negati
2. **Altro traffico di rete**: un proxy SOCKS5 gestisce tutte le altre connessioni TCP (SSH, connessioni a database, ecc.)
3. **Applicazione delle autorizzazioni**: i proxy applicano le regole `permissions` dalla tua configurazione

**Comunicazione proxy specifica per piattaforma:**

- **Linux**: le richieste vengono instradate tramite il filesystem su socket di dominio Unix (usando `socat` come bridge). Il network namespace viene rimosso dal container bubblewrap, garantendo che tutto il traffico di rete debba passare attraverso i proxy.

- **macOS**: il profilo Seatbelt consente la comunicazione solo verso specifiche porte localhost su cui i proxy sono in ascolto. Tutti gli altri accessi di rete sono bloccati.

- **Windows**: un filtro WFP `ALE_AUTH_CONNECT` blocca ogni connessione in uscita dall'account `srt-sandbox` tranne il loopback verso l'intervallo di porte proxy configurato. I proxy si legano all'interno di tale intervallo. Le variabili d'ambiente (`HTTP_PROXY`, `HTTPS_PROXY`, `ALL_PROXY`, …) indirizzano gli strumenti verso i proxy, ma il filtro WFP è il confine — un processo che le ignora o le rimuove è comunque confinato.

**Strumenti JVM (macOS/Linux):** la JVM ignora `HTTPS_PROXY`/`NO_PROXY` e non ha una variabile d'ambiente per le credenziali del proxy — la selezione del proxy deriva dalle proprietà di sistema `https.proxyHost` e la credenziale può essere fornita solo tramite `java.net.Authenticator`. Quindi gli strumenti basati su JVM (la cache remota gRPC di Bazel, Gradle, Maven, …) altrimenti si collegherebbero direttamente al target e fallirebbero, oppure raggiungerebbero il proxy senza il suo token e otterrebbero un 407. Per colmare questa lacuna srt inietta un piccolo `-javaagent` tramite `JAVA_TOOL_OPTIONS` (la variabile d'ambiente contiene solo il percorso del jar, la credenziale rimane in `HTTPS_PROXY`). All'avvio della JVM l'agente imposta `http[s].proxyHost`/`Port` e `http.nonProxyHosts` dalle variabili d'ambiente del proxy, riabilita l'autenticazione Basic per i tunnel CONNECT e installa un Authenticator per l'endpoint del proxy. Le proprietà proxy `-D` esplicite sulla riga di comando della JVM hanno comunque la precedenza, e qualsiasi `JAVA_TOOL_OPTIONS` ereditata viene preservata (a meno che non sia una variabile d'ambiente di credenziali negata). Di conseguenza ogni JVM stampa una riga `Picked up JAVA_TOOL_OPTIONS: …` su stderr; un runtime jlink'd compilato senza il modulo `java.instrument` non può caricare agenti e rifiuterà di avviarsi sotto la sandbox — rimuovi `JAVA_TOOL_OPTIONS` nel comando per tale strumento. Il jar viene distribuito nel pacchetto npm come `vendor/java-proxy-agent/srt-proxy-agent.jar` (sorgente: `vendor/java-proxy-agent-src/`; compilato dal workflow di release, o localmente con `npm run build:java-agent` — richiede un JDK ≥ 17). Se non viene trovato, `JAVA_TOOL_OPTIONS` viene lasciata invariata e le JVM si comportano come prima; i bundler possono puntare alla propria copia con `javaAgentJarPath`.

### Isolamento del filesystem

Le restrizioni sul filesystem sono applicate a livello di sistema operativo:

- **macOS**: usa `sandbox-exec` con profili Seatbelt generati dinamicamente che specificano i percorsi di lettura/scrittura consentiti
- **Linux**: usa `bubblewrap` con bind mount, contrassegnando le directory come di sola lettura o di lettura-scrittura in base alla configurazione
- **Windows**: scrive ACE espliciti additivi `(OI)(CI)` per il SID `srt-sandbox` sui percorsi configurati (ALLOW su `allowRead`/`allowWrite`, DENY su `denyRead`/`denyWrite`), poi li rimuove al `reset()`

**Autorizzazioni predefinite del filesystem:**

- **Lettura** (nega-poi-consenti): consentita ovunque per impostazione predefinita. Puoi negare ampie regioni, poi ri-consentire percorsi specifici al loro interno. `allowRead` ha la precedenza su `denyRead`.

  - Esempio: `denyRead: ["~/.ssh"]` per bloccare l'accesso alle chiavi SSH
  - Esempio: `denyRead: ["/Users"], allowRead: ["."]` per bloccare tutto `/Users` tranne il workspace
  - `denyRead: []` vuoto = accesso completo in lettura (nulla negato)

- **Scrittura** (solo-consenti): negata ovunque per impostazione predefinita. Devi consentire esplicitamente i percorsi.
  - Esempio: `allowWrite: [".", "/tmp"]` per consentire scritture nella directory corrente e in /tmp
  - `allowWrite: []` vuoto = nessun accesso in scrittura (nulla consentito)
  - `denyWrite` crea eccezioni all'interno dei percorsi consentiti (deny ha la precedenza)

**La precedenza è intenzionalmente opposta per letture e scritture:** `allowRead` sovrascrive `denyRead`, mentre `denyWrite` sovrascrive `allowWrite`. Questo ti consente di ritagliare regioni leggibili all'interno di aree negate, e ritagliare regioni protette all'interno di aree scrivibili.

### Percorsi di negazione obbligatoria (file auto-protetti)

Alcuni file e directory sensibili sono **sempre bloccati dalla scrittura**, anche se rientrano in un percorso di scrittura consentito. Questo fornisce una difesa in profondità contro le evasioni dalla sandbox e la manomissione della configurazione.

**File sempre bloccati:**

- File di configurazione della shell: `.bashrc`, `.bash_profile`, `.zshrc`, `.zprofile`, `.profile`
- File di configurazione di Git: `.gitconfig`, `.gitmodules`
- Altri file sensibili: `.ripgreprc`, `.mcp.json`

**Directory sempre bloccate:**

- Directory IDE: `.vscode/`, `.idea/`
- Directory di configurazione di Claude: `.claude/commands/`, `.claude/agents/`
- Hook e configurazione di Git: `.git/hooks/`, `.git/config`

Questi percorsi sono bloccati automaticamente - non è necessario aggiungerli a `denyWrite`. Ad esempio, anche con `allowWrite: ["."]`, la scrittura su `.bashrc` o `.git/hooks/pre-commit` fallirà:```bash
$ srt 'echo "malicious" >> .bashrc'
/bin/bash: .bashrc: Operation not permitted

$ srt 'echo "bad" > .git/hooks/pre-commit'
/bin/bash: .git/hooks/pre-commit: Operation not permitted

Nota (Linux): Su Linux, i percorsi di negazione obbligatoria bloccano solo i file che esistono già. I file non esistenti che corrispondono a questi pattern non possono essere bloccati dall'approccio bind-mount di bubblewrap. macOS utilizza pattern glob che bloccano sia i file esistenti che quelli nuovi.

Profondità di ricerca su Linux: Su Linux, la sandbox utilizza ripgrep per scansionare file pericolosi nelle sottodirectory all'interno dei percorsi di scrittura consentiti. Per impostazione predefinita, cerca fino a 3 livelli di profondità per motivi di prestazioni. È possibile configurare questo comportamento con mandatoryDenySearchDepth:```json { "mandatoryDenySearchDepth": 5, "filesystem": { "allowWrite": ["."] } }

- Predefinito: `3` (cerca fino a 3 livelli di profondità)
- Intervallo: da `1` a `10`
- Valori più alti offrono maggiore protezione ma prestazioni più lente
- I file nella CWD (profondità 0) sono sempre protetti indipendentemente da questa impostazione

### Restrizioni sui socket Unix (Linux)

Su Linux, la sandbox utilizza **seccomp BPF (Berkeley Packet Filter)** per bloccare la creazione di socket di dominio Unix a livello di syscall. Questo fornisce un ulteriore livello di sicurezza per impedire ai processi di creare nuovi socket di dominio Unix per IPC locale (a meno che non sia esplicitamente consentito).

**Come funziona:**

1. **Filtro BPF integrato**: Il pacchetto include un binario statico `apply-seccomp` per x64 e arm64 con il filtro seccomp BPF compilato all'interno. Il filtro è specifico per l'architettura ma indipendente da libc, quindi il binario funziona sia con glibc che con musl.

2. **Rilevamento a runtime**: La sandbox rileva automaticamente l'architettura del tuo sistema e utilizza il binario `apply-seccomp` corrispondente.

3. **Filtraggio delle syscall**: Il filtro BPF intercetta la syscall `socket()` e blocca la creazione di socket `AF_UNIX` restituendo `EPERM`. Questo impedisce al codice in sandbox di creare nuovi socket di dominio Unix.

4. **Applicazione in due fasi tramite il binario apply-seccomp**:
   - Il bwrap esterno crea la sandbox con restrizioni su filesystem, rete e namespace PID
   - I processi di bridging di rete (socat) vengono avviati all'interno della sandbox (necessitano di socket Unix)
   - apply-seccomp crea un namespace annidato user+PID+mount e rimonta `/proc`
   - All'interno del namespace annidato, apply-seccomp agisce come PID 1 (init/reaper non dumpable)
   - apply-seccomp esegue il fork, applica il filtro seccomp tramite `prctl()` ed esegue il comando utente
   - Il comando utente viene eseguito con tutte le restrizioni della sandbox più il blocco della creazione di socket Unix

**Isolamento del namespace PID**: Il namespace PID annidato garantisce che il comando utente non possa vedere o indirizzare alcun processo che viene eseguito senza il filtro seccomp (l'init di bwrap, il wrapper della shell o gli helper socat). Questo mantiene intatto il confine seccomp indipendentemente da `kernel.yama.ptrace_scope`, poiché gli helper non filtrati non sono raggiungibili tramite `ptrace` o `/proc/N/mem`. Il PID 1 interno imposta `PR_SET_DUMPABLE=0` in modo che non sia nemmeno ptraceable. Se la creazione del namespace annidato fallisce, apply-seccomp si interrompe anziché essere eseguito senza isolamento.

**Limitazioni di sicurezza**: Il filtro blocca `socket(AF_UNIX, ...)` e le syscall `io_uring_setup`/`io_uring_enter`/`io_uring_register` (le ultime tre perché `IORING_OP_SOCKET` su Linux 5.19+ altrimenti aggirerebbe la regola `socket()`). Non impedisce le operazioni sui descrittori di file di socket Unix ereditati dai processi padre o passati tramite `SCM_RIGHTS`. Per la maggior parte degli scenari di sandboxing, bloccare la creazione di socket è sufficiente per prevenire IPC non autorizzate.

**Zero dipendenze a runtime**: I binari statici apply-seccomp precompilati e i filtri BPF pregenerati sono inclusi per le architetture x64 e arm64. Non sono richiesti strumenti di compilazione o dipendenze esterne a runtime.

**Supporto architetture**: x64 e arm64 sono completamente supportate con binari precompilati. Altre architetture non sono attualmente supportate. Per utilizzare il sandboxing senza il blocco dei socket Unix su architetture non supportate, imposta `allowAllUnixSockets: true` nella tua configurazione.

### Rilevamento e monitoraggio delle violazioni

Quando un processo in sandbox tenta di accedere a una risorsa limitata:

1. **Blocca l'operazione** a livello di sistema operativo (restituisce l'errore `EPERM`)
2. **Registra la violazione** (meccanismi specifici della piattaforma)
3. **Notifica l'utente** (in Claude Code, questo attiva una richiesta di autorizzazione)

**macOS**: Il runtime della sandbox si collega all'archivio dei log delle violazioni della sandbox di sistema di macOS. Questo fornisce notifiche in tempo reale con informazioni dettagliate su ciò che è stato tentato e sul motivo per cui è stato bloccato. Questo è lo stesso meccanismo utilizzato da Claude Code per il rilevamento delle violazioni.```bash
# View sandbox violations in real-time
log stream --predicate 'process == "sandbox-exec"' --style syslog

Linux: Bubblewrap non fornisce report integrati delle violazioni. Usa strace per tracciare le chiamate di sistema e identificare le operazioni bloccate:```bash

Trace all denied operations

strace -f srt 2>&1 | grep EPERM

Trace specific file operations

strace -f -e trace=open,openat,stat,access srt 2>&1 | grep EPERM

Trace network operations

strace -f -e trace=network srt 2>&1 | grep EPERM

### Avanzato: Porta il Tuo Proxy

Per un filtraggio di rete più sofisticato, puoi configurare la sandbox per utilizzare il tuo proxy invece di quelli integrati. Questo consente:

- **Ispezione del traffico**: Usa strumenti come [mitmproxy](https://mitmproxy.org/) per ispezionare e modificare il traffico
- **Logica di filtraggio personalizzata**: Implementa regole complesse oltre le semplici allowlist di domini
- **Registrazione di audit**: Registra tutte le richieste di rete per conformità o debug

**Esempio con mitmproxy:**```bash
# Start mitmproxy with custom filtering script
mitmproxy -s custom_filter.py --listen-port 8888

Nota: la configurazione personalizzata del proxy non è ancora supportata nel nuovo formato di configurazione. Questa funzionalità sarà aggiunta in una versione futura.

Considerazione importante sulla sicurezza: anche con le allowlist dei domini, possono esistere vettori di esfiltrazione. Ad esempio, consentire github.com permette a un processo di eseguire il push su qualsiasi repository. Con un proxy MITM personalizzato e una corretta configurazione dei certificati, è possibile ispezionare e filtrare specifiche chiamate API per prevenirlo.

Limitazioni di sicurezza

  • Limitazioni del sandboxing di rete: il sistema di filtraggio della rete opera limitando i domini a cui i processi sono autorizzati a connettersi. Non ispeziona altrimenti il traffico che passa attraverso il proxy e gli utenti sono responsabili di garantire che nella propria policy siano consentiti solo domini fidati. I nomi host consentiti vengono inoltre verificati rispetto a un insieme negato di indirizzi risolti prima di una connessione diretta (vedere Controllo degli indirizzi risolti sopra), quindi un nome consentito non può essere puntato verso loopback, link-local, gli indirizzi di questo host o un IP elencato in deniedDomains; altri intervalli privati sono coperti solo se li elenchi in deniedResolvedAddresses (una voce wildcard su un dominio di cui non controlli il DNS può altrimenti essere indirizzata verso servizi sulla tua LAN), e le connessioni che escono tramite parentProxy/mitmProxy si affidano a quel salto per il controllo equivalente.
Gli utenti devono essere consapevoli dei potenziali rischi derivanti dal consentire domini ampi come `github.com`, che possono permettere l'esfiltrazione di dati. Inoltre, in alcuni casi potrebbe essere possibile aggirare il filtraggio della rete tramite il [domain fronting](https://en.wikipedia.org/wiki/Domain_fronting).
  • Escalation di privilegi tramite socket Unix: la configurazione allowUnixSockets può concedere inavvertitamente l'accesso a potenti servizi di sistema che potrebbero portare a bypass del sandbox. Ad esempio, se viene utilizzata per consentire l'accesso a /var/run/docker.sock, ciò concederebbe effettivamente l'accesso al sistema host sfruttando il socket docker. Si invita gli utenti a considerare attentamente qualsiasi socket unix che consentono attraverso il sandbox.
  • Escalation dei permessi del filesystem: permessi di scrittura eccessivamente ampi sul filesystem possono abilitare attacchi di escalation di privilegi. Consentire scritture in directory contenenti eseguibili in $PATH, directory di configurazione di sistema o file di configurazione della shell utente (.bashrc, .zshrc) può portare all'esecuzione di codice in contesti di sicurezza diversi quando altri utenti o processi di sistema accedono a questi file.
  • Robustezza del sandbox Linux: l'implementazione Linux fornisce un forte isolamento del filesystem e della rete, ma include una modalità enableWeakerNestedSandbox che le consente di funzionare all'interno di ambienti Docker senza namespace privilegiati. Questa opzione indebolisce considerevolmente la sicurezza e dovrebbe essere utilizzata solo nei casi in cui sia altrimenti applicato un isolamento aggiuntivo.
  • Isolamento di rete più debole (macOS): l'opzione enableWeakerNetworkIsolation riabilita l'accesso a com.apple.trustd.agent, necessario ai programmi Go per verificare i certificati TLS tramite il framework Security di macOS. Ciò apre un potenziale vettore di esfiltrazione di dati attraverso il servizio trustd e dovrebbe essere abilitato solo quando è richiesta la verifica TLS di Go (ad esempio, quando si utilizza httpProxyPort con un proxy MITM e una CA personalizzata).
  • Apple Events (macOS): l'opzione allowAppleEvents riabilita l'invio di Apple Events e delle richieste di apertura di Launch Services ((allow appleevent-send), (allow lsopen) e mach-lookup per com.apple.coreservices.appleevents, com.apple.CoreServices.coreservicesd e com.apple.coreservices.quarantine-resolver), richieste da open, osascript e dagli helper di apertura URL. Con queste autorizzazioni, un comando in sandbox può avviare applicazioni arbitrarie senza alcuna richiesta all'utente, e le applicazioni avviate vengono eseguite completamente al di fuori del sandbox — quindi questa opzione rimuove l'isolamento dell'esecuzione del codice, non lo indebolisce soltanto. Lo scripting di applicazioni già in esecuzione tramite Apple Events è inoltre vincolato al consenso all'automazione TCC di macOS, ma l'avvio tramite open non lo è. Abilitare questa opzione solo quando i comandi all'interno del sandbox hanno realmente bisogno di aprire URL o applicazioni.

Limitazioni note e lavori futuri

Bypass del proxy su Linux: attualmente utilizza variabili d'ambiente (HTTP_PROXY, HTTPS_PROXY, ALL_PROXY) per indirizzare il traffico attraverso i proxy. Funziona per la maggior parte delle applicazioni ma può essere ignorato da programmi che non rispettano queste variabili, portandoli a non riuscire a connettersi a Internet.

Miglioramenti futuri:

  • Supporto a Proxychains: aggiungere il supporto a proxychains con LD_PRELOAD su Linux per intercettare le chiamate di rete a un livello inferiore, rendendo il bypass più difficile

  • Monitoraggio delle violazioni su Linux: implementare il rilevamento automatico delle violazioni basato su strace per Linux, integrato con l'archivio delle violazioni. Attualmente, gli utenti Linux devono eseguire manualmente strace per vedere le violazioni, a differenza di macOS che dispone di un monitoraggio automatico delle violazioni tramite l'archivio dei log di sistema

Categorie