
sandbox-runtime v0.0.76
Uma ferramenta leve de sandboxing para aplicar restrições de sistema de arquivos e rede em processos arbitrários no nível do sistema operacional, sem exigir um contêiner.
Anthropic Sandbox Runtime (srt)
Uma ferramenta leve de sandboxing para impor restrições de sistema de arquivos e rede a processos arbitrários no nível do sistema operacional, sem exigir um contêiner.
srt usa primitivas nativas de sandboxing do sistema operacional (sandbox-exec no macOS, bubblewrap no Linux) e filtragem de rede baseada em proxy. Pode ser usado para colocar em sandbox o comportamento de agentes, servidores MCP locais, comandos bash e processos arbitrários.
Prévia de Pesquisa Beta
O Sandbox Runtime é uma prévia de pesquisa desenvolvida para o Claude Code para viabilizar agentes de IA mais seguros. Está sendo disponibilizado como uma prévia de código aberto inicial para ajudar o ecossistema mais amplo a construir sistemas agênticos mais seguros. Como esta é uma prévia de pesquisa inicial, as APIs e os formatos de configuração podem evoluir. Agradecemos feedback e contribuições para tornar os agentes de IA mais seguros por padrão!
Instalação```bash
npm install -g @anthropic-ai/sandbox-runtime
## Uso Básico```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
Visão Geral
Este pacote fornece uma implementação de sandbox autônoma que pode ser usada tanto como ferramenta CLI quanto como biblioteca. Ele foi projetado com uma filosofia segura por padrão, adaptada para casos de uso comuns de desenvolvedores: os processos iniciam com acesso mínimo, e você abre explicitamente apenas os buracos que precisa.
Principais capacidades:
- Restrições de rede: Controle quais hosts/domínios podem ser acessados via HTTP/HTTPS e outros protocolos
- Restrições de sistema de arquivos: Controle quais arquivos/diretórios podem ser lidos/escritos
- Restrições de socket Unix: Controle o acesso a sockets IPC locais
- Monitoramento de violações: No macOS, acesse o armazenamento de logs de violação do sandbox do sistema para alertas em tempo real
Exemplo de Caso de Uso: Sandboxing de Servidores MCP
Um caso de uso importante é o sandboxing de servidores Model Context Protocol (MCP) para restringir suas capacidades. Por exemplo, para colocar o servidor MCP de sistema de arquivos em sandbox:
Sem sandboxing (.mcp.json):```json
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem"]
}
}
}
**Com sandboxing** (`.mcp.json`):```json
{
"mcpServers": {
"filesystem": {
"command": "srt",
"args": ["npx", "-y", "@modelcontextprotocol/server-filesystem"]
}
}
}
Em seguida, configure as restrições em ~/.srt-settings.json:```json
{
"filesystem": {
"denyRead": [],
"allowWrite": ["."],
"denyWrite": ["~/sensitive-folder"]
},
"network": {
"allowedDomains": [],
"deniedDomains": []
}
}
Agora o servidor MCP será bloqueado de escrever no caminho negado:```
> Write a file to ~/sensitive-folder
✗ Error: EPERM: operation not permitted, open '/Users/ollie/sensitive-folder/test.txt'
Como Funciona
O sandbox usa primitivas em nível de sistema operacional para impor restrições que se aplicam a toda a árvore de processos:
- macOS: Usa
sandbox-execcom perfis Seatbelt gerados dinamicamente - Linux: Usa bubblewrap para containerização com isolamento de namespace de rede
- Windows: Executa o processo em sandbox sob uma conta de usuário local dedicada
srt-sandbox, com uma cerca de saída do Windows Filtering Platform vinculada ao SID dessa conta e ACEs explícitas por sessão na árvore de trabalho
0d1c612947c798aef48e6ab4beb7e8544da9d41a-4096x2305
Modelo de Isolamento Duplo
Tanto o isolamento de sistema de arquivos quanto o de rede são necessários para um sandboxing eficaz. Sem isolamento de arquivos, um processo comprometido poderia exfiltrar chaves SSH ou outros arquivos sensíveis. Sem isolamento de rede, um processo poderia escapar do sandbox e obter acesso irrestrito à rede.
Isolamento de Sistema de Arquivos impõe restrições de leitura e escrita:
- Leitura (padrão negar-então-permitir): Por padrão, o acesso de leitura é permitido em todos os lugares. Você pode negar regiões amplas (por exemplo,
/Users) e então permitir novamente caminhos específicos dentro delas (por exemplo,.).allowReadtem precedência sobredenyRead— o oposto da escrita, ondedenyWritetem precedência sobreallowWrite. Uma entradadenyReadque é mais específica do que a regiãoallowReadna qual ela se encontra (por exemplo,denyRead: ["**/.env"]ou["./secrets"]comallowRead: ["."]) permanece negada. - Escrita (padrão apenas-permitir): Por padrão, o acesso de escrita é negado em todos os lugares. Você deve permitir explicitamente caminhos (por exemplo,
.,/tmp). Uma lista de permissões vazia significa nenhum acesso de escrita.
Isolamento de Rede (padrão apenas-permitir): Por padrão, todo acesso à rede é negado. Você deve permitir domínios explicitamente. Uma lista allowedDomains vazia significa nenhum acesso à rede. O tráfego de rede é roteado através de servidores proxy em execução no host:
-
Linux: As requisições são roteadas via sistema de arquivos através de um socket de domínio Unix. O namespace de rede do processo em sandbox é removido completamente, então todo o tráfego de rede deve passar pelos proxies em execução no host (escutando em sockets Unix que são montados por bind no sandbox)
-
macOS: O perfil Seatbelt permite comunicação apenas para uma porta localhost específica. Os proxies escutam nessa porta, criando um canal controlado para todo o acesso à rede
-
Windows: Um conjunto de filtros WFP em toda a máquina bloqueia todas as conexões de saída originadas da conta
srt-sandbox, exceto loopback para a faixa de portas do proxy. Os proxies escutam dentro dessa faixa, criando um canal controlado para todo o acesso à rede
Tanto HTTP/HTTPS (via proxy HTTP) quanto outro tráfego TCP (via proxy SOCKS5) são mediados por esses proxies, que impõem suas listas de permissões e negações de domínios.
Para mais detalhes sobre sandboxing no Claude Code, consulte:
- Documentação de Sandboxing do Claude Code
- Beyond Permission Prompts: Making Claude Code More Secure and Autonomous
Arquitetura```
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
## Uso
### Como ferramenta CLI
O comando `srt` (Anthropic Sandbox Runtime) envolve qualquer comando com limites de segurança:```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
Como uma biblioteca```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()
})
**Atribuição de violações (`commandId` / `commandText`).** As violações observadas enquanto um comando encapsulado é executado (linhas de log do seatbelt, eventos do seccomp, negações do proxy) são armazenadas sob uma chave de atribuição, e `annotateStderrWithSandboxFailures(key, stderr)` / `getViolationsForCommand(key)` procuram-nas por essa mesma chave. Por predefinição, a chave é a própria string encapsulada. Passe um `commandId` opaco por invocação (por exemplo, um id de utilização de ferramenta) para usar esse como chave — recomendado: as chaves são comparadas pelos seus primeiros 100 caracteres, pelo que comandos longos que partilhem um prefixo seriam de outro modo atribuídos de forma cruzada, e uma reexecução do mesmo texto herdaria os eventos da execução anterior. Se a string que *executa* não for o comando que a invocação *representa* (por exemplo, encapsula um `source <snapshot> && eval '<cmd>'` montado), passe também `commandText: '<cmd>'`: é contra isto que os padrões de comando de `ignoreViolations` fazem correspondência e é o que cada violação reporta como o seu `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)
Exportações disponíveis```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'
## Configuração
### Localização do Arquivo de Configurações
Por padrão, o runtime do sandbox procura a configuração em `~/.srt-settings.json`. Você pode especificar um caminho personalizado usando a flag `--settings`:```bash
srt --settings /path/to/srt-settings.json <command>
Exemplo de Configuração 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 }
### Opções de Configuração
#### Configuração de Rede
Usa um **padrão allow-only** - todo acesso à rede é negado por padrão.
- `network.allowedDomains` - Array de domínios permitidos (suporta wildcards como `*.example.com`). Array vazio = sem acesso à rede. Um sufixo `:port` opcional (`api.example.com:443`, `*.example.com:8443`) restringe uma entrada a esse porto de destino; entradas sem porto correspondem a qualquer porto.
- Literais IPv6 devem estar entre parênteses retos, no estilo RFC 3986: `[::1]`, `[2001:db8::1]:443`. Uma entrada com múltiplos dois-pontos sem parênteses retos é rejeitada como ambígua (`2001:db8::1:443` é, por si só, um endereço válido).
- `network.deniedDomains` - Array de domínios negados (verificado primeiro, tem precedência sobre allowedDomains). Mesmo sufixo `:port`, e um `*` simples (ou `*:22`) é aceite para negar tudo.
- `network.deniedDomainReasons` - Mapa opcional de uma entrada de `deniedDomains` (correspondida por string exata) para um motivo voltado ao modelo que aparece na linha `<sandbox_violations>` quando essa entrada nega uma conexão — diga o que está bloqueado e a alternativa sancionada (por exemplo, `{"github.com:22": "SSH pushes to GitHub are blocked; use an https:// remote"}`). Entradas sem motivo reportam um genérico. Para destinos SSH (porto 22), o motivo também é entregue em banda: um cliente SSH tunelizado através de um ProxyCommand SOCKS sem autenticação (por exemplo, BSD `nc -X 5`) recebe uma desconexão SSH pré-troca-de-chaves cuja descrição é o motivo, que o OpenSSH imprime literalmente — mantenha tais motivos com menos de ~400 caracteres ASCII, imperativo primeiro, já que o OpenSSH trunca e escapa caracteres não-ASCII.
- `network.allowLocalBinding` - Permitir vinculação a portos locais (booleano, predefinição: false)
**Verificação de endereço resolvido.** As listas de permissão/negação correspondem por _nome_, mas quem controla o DNS de um nome permitido (ou qualquer etiqueta sob um wildcard permitido) controla aquilo para que ele resolve. Assim, antes de discar diretamente para um **hostname** permitido, o proxy resolve-o uma vez, descarta qualquer endereço num conjunto negado e conecta-se a um endereço sobrevivente (o endereço que passou na verificação é o que é discado — não há uma segunda consulta). Se nada sobreviver, a conexão é recusada como qualquer outra negação de política: HTTP/CONNECT recebem `403` (`X-Proxy-Error: blocked-by-sandbox-runtime`, o motivo no corpo), SOCKS recebe "connection not allowed by ruleset", e uma linha `deny network-outbound host:port (resolved to a loopback address)` — nomeando a classe de endereço (loopback, link-local, deste host, metadados da cloud, negado por lista, listado, …), não o endereço em si, que apenas o registo de depuração contém — é registada no armazenamento de violações.
O conjunto negado é: loopback (`127.0.0.0/8`, `::1`), não especificado (`0.0.0.0/8`, `::`), link-local (`169.254.0.0/16`, `fe80::/10`), multicast (`224.0.0.0/4`, `ff00::/8`), broadcast, os endpoints de metadados de instância cloud / plataforma que vivem fora do 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`), todos os endereços atualmente atribuídos a uma das interfaces de rede deste próprio host (um serviço vinculado a `0.0.0.0` responde na LAN ou endereço global exatamente como responde no loopback), todos os literais IP listados em `deniedDomains` (honrando o seu `:port` se tiver um), e qualquer coisa em `deniedResolvedAddresses`. Entradas IPv4 também correspondem às formas IPv6 que transportam um endereço IPv4 — endereços IPv4-mapeados, IPv4-compatíveis e IPv4-traduzidos, o prefixo bem conhecido NAT64 (`64:ff9b::/96`) e 6to4 (`2002::/16`) são julgados pelo endereço IPv4 que incorporam. O prefixo NAT64 de uso local `64:ff9b:1::/48` e prefixos específicos de rede não são descodificados — o seu layout (RFC 6052 permite o IPv4 em várias posições) não pode ser reconhecido apenas a partir do endereço; numa tal rede, liste as traduções do prefixo dos intervalos que nega (por exemplo, `<prefix>::a00:0/104` para `10.0.0.0/8`). Endereços que alcançam este host sem lhe serem atribuídos — um endereço público 1:1-NAT de uma instância cloud, um port-forward de router, um alias de host-gateway de contentor ou VM — não são cobertos automaticamente; liste-os em `deniedResolvedAddresses`.
O que a verificação deixa em paz: entradas da allowlist que **são** literais IP (permitir `127.0.0.1:3000` é uma escolha explícita) — e, pela mesma lógica, um hostname pode resolver para um endereço de outro modo negado quando esse literal IP (nesse porto) está ele próprio em `allowedDomains`, já que alcançá-lo por nome não concede nada que a entrada literal não conceda (um literal IP em `deniedDomains` ainda ganha, exatamente como faz para um pedido literal). Assim, uma configuração de desenvolvimento onde `myapp.test` mapeia para um servidor local via `/etc/hosts` permite `["myapp.test", "127.0.0.1:3000"]`; não há lista de exceções separada. `localhost` e nomes sob `.localhost` resolvem para loopback (ou um literal permitido) e nada mais. A verificação não é avaliada para conexões encaminhadas através de `parentProxy` (incluindo uma captada de `HTTP_PROXY` / `HTTPS_PROXY` no próprio ambiente do srt) ou `mitmProxy` — esse salto resolve o nome e possui a sua própria política de endereços — e apenas governa o que o proxy disca: no macOS, `allowLocalBinding` permite separadamente que o processo em sandbox se conecte a portos de loopback sem passar pelo proxy de todo.
- `network.deniedResolvedAddresses` - Endereços IP / intervalos CIDR extra (IPv4 ou IPv6, sem parênteses retos, qualquer porto) para os quais hostnames permitidos não devem resolver. O espaço de uso privado não é negado por predefinição porque permitir um hostname de intranet é legítimo; liste-o aqui quando nomes permitidos devem ficar fora dele, por exemplo, `["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16", "100.64.0.0/10", "fc00::/7"]`. Liste intervalos IPv4 e IPv6 separadamente — um intervalo IPv6 suficientemente amplo para cobrir o bloco IPv4-mapeado (`::ffff:0:0/96`), como `::/0`, corresponde a respostas IPv4 em alguns runtimes mas não noutros, por isso não confie nele para negar IPv4.
**Terminação TLS** (`network.tlsTerminate`, experimental): quando definido, os CONNECTs HTTPS são terminados em processo para que o SRT possa ver (e filtrar, via `network.filterRequest`) os pedidos desencriptados. O processo em sandbox é apontado para um pacote de confiança contendo a CA MITM (`caCertPath`/`caKeyPath`, ou uma CA efémera se omitidos) mais as raízes regulares do host, para que certificados emitidos pelo proxy e certificados reais do upstream ambos verifiquem.
- `network.tlsTerminate.excludeDomains` - Padrões de domínio (mesma sintaxe que `allowedDomains`) que **não** são terminados. CONNECTs correspondentes são tunelizados opacamente: continuam sujeitos à allowlist de domínios, mas o cliente dentro da sandbox completa o seu próprio handshake TLS com o upstream real, e `filterRequest` / injeção de credenciais não se aplicam ao seu tráfego HTTPS. Use isto para os dois casos que a terminação TLS quebra fundamentalmente:
- **Upstreams mTLS** - apenas o cliente dentro da sandbox possui o certificado de cliente, pelo que o proxy não pode re-originar a conexão em seu nome.
- **Clientes com certificate-pinning** - clientes que verificam a identidade do upstream eles próprios (CAs personalizadas, SAN pinning) e rejeitam o certificado MITM.
- `network.tlsTerminate.extraCaCertPaths` - Caminhos para ficheiros de certificado CA PEM anexados a esse pacote de confiança, após a CA MITM e as raízes regulares do host. Hosts excluídos (não terminados) são verificados pelo cliente dentro da sandbox, e as variáveis de ambiente de confiança que o SRT define (`SSL_CERT_FILE`, `GIT_SSL_CAINFO`, ...) _substituem_ a própria configuração de confiança de cada ferramenta, pelo que uma raiz local do site (por exemplo, uma CA mTLS interna) deve estar no pacote ou esses hosts nunca poderão ser verificados. Apenas os blocos `CERTIFICATE` de cada ficheiro são copiados para o pacote (qualquer outra coisa, por exemplo, uma chave privada num PEM combinado, nunca é exposta à sandbox); ficheiros que estão em falta, ilegíveis, ou não contêm nenhum bloco `CERTIFICATE` PEM são ignorados, pelo que é seguro listar caminhos que existem apenas em alguns hosts.```json
{
"network": {
"allowedDomains": ["*.example.com", "internal-mtls.example.net"],
"deniedDomains": [],
"tlsTerminate": {
"excludeDomains": ["internal-mtls.example.net"],
"extraCaCertPaths": ["/etc/internal-mtls-roots.pem"]
}
}
}
Configurações de Unix Socket (comportamento específico da plataforma):
| Configuração | macOS | Linux |
|---|---|---|
allowUnixSockets: string[] | Lista de permissões de caminhos de socket | Ignorado (seccomp não consegue filtrar por caminho) |
allowAllUnixSockets: boolean | Permitir todos os sockets | Desativar o bloqueio do seccomp |
Os Unix sockets são bloqueados por padrão em ambas as plataformas.
- macOS: Use
allowUnixSocketspara permitir caminhos específicos (por exemplo,["/var/run/docker.sock"]), ouallowAllUnixSockets: truepara permitir todos. - Linux: O bloqueio usa filtros seccomp (apenas x64/arm64). Se o seccomp não estiver disponível, os sockets ficam irrestritos e um aviso é exibido. Use
allowAllUnixSockets: truepara desativar explicitamente o bloqueio.
Configuração do Sistema de Arquivos
Usa dois padrões diferentes:
Restrições de leitura (padrão negar-então-permitir) - todas as leituras permitidas por padrão:
filesystem.denyRead- Array de caminhos para negar acesso de leitura. Array vazio = acesso total de leitura.filesystem.allowRead- Array de caminhos para permitir novamente o acesso de leitura dentro de regiões negadas (tem precedência sobre denyRead). Nota: isto é o oposto da escrita, ondedenyWritetem precedência sobreallowWrite.
Restrições de escrita (padrão apenas-permitir) - todas as escritas negadas por padrão:
filesystem.allowWrite- Array de caminhos para permitir acesso de escrita. Array vazio = sem acesso de escrita.filesystem.denyWrite- Array de caminhos para negar acesso de escrita dentro de caminhos permitidos (tem precedência sobre allowWrite)
Sintaxe de Caminho (macOS):
Os caminhos suportam padrões glob no estilo git no macOS, semelhantes à sintaxe do .gitignore:
*- Corresponde a quaisquer caracteres exceto/(por exemplo,*.tscorresponde afoo.tsmas não afoo/bar.ts)**- Corresponde a quaisquer caracteres incluindo/(por exemplo,src/**/*.tscorresponde a todos os arquivos.tsemsrc/)?- Corresponde a qualquer caractere único exceto/(por exemplo,file?.txtcorresponde afile1.txt)[abc]- Corresponde a qualquer caractere do conjunto (por exemplo,file[0-9].txtcorresponde afile3.txt)
Exemplos:
"allowWrite": ["src/"]- Permitir escrita em todo o diretóriosrc/"allowWrite": ["src/**/*.ts"]- Permitir escrita em todos os arquivos.tsemsrc/e subdiretórios"denyRead": ["~/.ssh"]- Negar leitura ao diretório SSH"denyRead": ["/Users"], "allowRead": ["."]- Negar leitura a todo o/Users, mas permitir novamente o diretório atual"denyWrite": [".env"]- Negar escrita ao arquivo.env(mesmo se o diretório atual for permitido)
Sintaxe de Caminho (Linux):
O Linux atualmente não suporta correspondência glob. Use apenas caminhos literais:
"allowWrite": ["src/"]- Permitir escrita no diretóriosrc/"denyRead": ["/home/user/.ssh"]- Negar leitura ao diretório SSH"denyRead": ["/home"], "allowRead": ["."]- Negar leitura a todo o/home, mas permitir novamente o diretório atual
Todas as plataformas:
- Os caminhos podem ser absolutos (por exemplo,
/home/user/.ssh) ou relativos ao diretório de trabalho atual (por exemplo,./src) ~expande para o diretório home do usuário
Outras Configurações
ignoreViolations- Objeto que mapeia padrões de comando para arrays de caminhos onde as violações devem ser ignoradasenableWeakerNestedSandbox- Ativa o modo de sandbox mais fraco para ambientes Docker (booleano, padrão: false)javaAgentJarPath- macOS/Linux: caminho absoluto parasrt-proxy-agent.jar, o agente JVM injetado viaJAVA_TOOL_OPTIONS(veja "JVM tools" em Network Isolation). Necessário apenas para consumidores que empacotam o sandbox-runtime e distribuem o jar separadamente; uma instalação npm normal o encontra emvendor/java-proxy-agent/.enableWeakerNetworkIsolation- Permite acesso acom.apple.trustd.agentno sandbox do macOS (booleano, padrão: false). Isto é necessário para programas Go (gh,gcloud,terraform,kubectl, etc.) verificarem certificados TLS ao usarhttpProxyPortcom um proxy MITM e CA personalizada. Aviso de segurança: ativar isto abre um potencial vetor de exfiltração de dados através do serviço trustd.allowAppleEvents- Permite enviar Apple Events e solicitações de abertura do Launch Services a partir do sandbox do macOS (booleano, padrão: false). Sem isto, comandos comoopen,osascripte qualquer coisa que abra URLs ou scripts de outros aplicativos via AppleScript falham com o erro AppleScript-600("Application isn't running") ou erros do LaunchServices (-10822,-54). Aviso de segurança: ativar isto significa que o sandbox não fornece mais isolamento de execução de código. Um comando em sandbox pode iniciar outros aplicativos viaopensem nenhum prompt do usuário, e qualquer coisa que ele inicie é executada fora das restrições de sistema de arquivos e rede do sandbox; a scriptagem de aplicativos já em execução via Apple Events é adicionalmente controlada pelo consentimento de automação TCC por aplicativo do usuário. Os embedders devem obter esta opção apenas de configuração confiável em nível de usuário — nunca de arquivos locais do projeto em um repositório verificado, o que permitiria que um projeto criado por um atacante elevasse suas próprias permissões de sandbox.
Receitas de Configuração Comuns
Permitir acesso ao GitHub (todos os endpoints necessários):```json { "network": { "allowedDomains": [ "github.com", "*.github.com", "lfs.github.com", "api.github.com" ], "deniedDomains": [] }, "filesystem": { "denyRead": [], "allowWrite": ["."], "denyWrite": [] } }
**Restringir a diretórios específicos:**```json
{
"network": {
"allowedDomains": [],
"deniedDomains": []
},
"filesystem": {
"denyRead": ["~/.ssh"],
"allowWrite": [".", "src/", "test/"],
"denyWrite": [".env", "secrets/"]
}
}
Acesso ao sistema de arquivos somente no workspace (negar leituras fora do workspace):```json { "network": { "allowedDomains": [], "deniedDomains": [] }, "filesystem": { "denyRead": ["/Users"], "allowRead": ["."], "allowWrite": ["."], "denyWrite": [] } }
Isso nega a leitura de qualquer coisa sob `/Users` (ou `/home` no Linux), e em seguida permite novamente o diretório de trabalho atual. Os caminhos de sistema (`/usr`, `/lib`, etc.) permanecem legíveis.
### Problemas Comuns e Dicas
**Executando o Jest:** Use a flag `--no-watchman` para evitar violações do sandbox:```bash
srt "jest --no-watchman"
O Watchman acessa arquivos fora dos limites do sandbox, o que acionará erros de permissão. Desativá-lo permite que o Jest seja executado com o observador de arquivos integrado.
Suporte de Plataforma
- macOS: Usa
sandbox-execcom perfis personalizados (sem dependências adicionais) - Linux: Usa
bubblewrap(bwrap) para containerização - Windows: Alpha — usa um auxiliar
srt-win.exeempacotado (sem dependências adicionais). Consulte Windows (alpha) abaixo para configuração, modelo de segurança e limitações conhecidas
Dependências Específicas de Plataforma
Linux requer:
bubblewrap- Runtime de contêiner- Ubuntu/Debian:
apt-get install bubblewrap - Fedora:
dnf install bubblewrap - Arch:
pacman -S bubblewrap
- Ubuntu/Debian:
socat- Retransmissor de socket para ponte de proxy- Ubuntu/Debian:
apt-get install socat - Fedora:
dnf install socat - Arch:
pacman -S socat
- Ubuntu/Debian:
ripgrep- Ferramenta de busca rápida para detecção de caminhos negados- Ubuntu/Debian:
apt-get install ripgrep - Fedora:
dnf install ripgrep - Arch:
pacman -S ripgrep
- Ubuntu/Debian:
Nota para Ubuntu 24.04+: Essas versões habilitam kernel.apparmor_restrict_unprivileged_userns por padrão, o que permite unshare(CLONE_NEWUSER), mas remove capacidades do namespace resultante. Tanto o bubblewrap quanto a camada de isolamento seccomp precisam de namespaces de usuário com capacidades. Desative a restrição com:```bash
sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0
ou adicione um perfil AppArmor que concede `userns` aos binários relevantes.
**Dependências opcionais do Linux (para fallback do seccomp):**
O pacote inclui filtros seccomp BPF pré-gerados para as arquiteturas x86-64 e arm. Essas dependências só são necessárias se você estiver em uma arquitetura diferente onde filtros pré-gerados não estão disponíveis:
- `gcc` ou `clang` - Compilador C
- `libseccomp-dev` - Arquivos de desenvolvimento da biblioteca Seccomp
- Ubuntu/Debian: `apt-get install gcc libseccomp-dev`
- Fedora: `dnf install gcc libseccomp-devel`
- Arch: `pacman -S gcc libseccomp`
**macOS requer:**
- `ripgrep` - Ferramenta de busca rápida para detecção de caminhos negados
- Instale via Homebrew: `brew install ripgrep`
- Ou baixe de: https://github.com/BurntSushi/ripgrep/releases
**Windows requer:**
- Nenhuma dependência adicional. O auxiliar `srt-win.exe` (x64 e arm64) está incluído no pacote npm. Uma etapa única de `windows-install` com privilégios elevados é necessária — veja abaixo.
## Windows (alpha)
O suporte ao Windows está em **alpha**. O processo em sandbox é executado sob uma conta de usuário local dedicada `srt-sandbox`, isolada do usuário chamador por primitivas de segurança nativas do Windows — uma cerca de egresso do Windows Filtering Platform (WFP) vinculada ao SID da conta de sandbox, e ACEs explícitas por sessão que concedem ou negam a esse SID acesso aos caminhos do sistema de arquivos configurados.
### Configuração
Execute uma vez por máquina (auto-eleva; um prompt UAC):```powershell
npx @anthropic-ai/sandbox-runtime windows-install
Isso provisiona a conta de usuário local srt-sandbox (com uma senha aleatória armazenada criptografada via DPAPI em HKLM\SOFTWARE\sandbox-runtime — em âmbito de máquina, de modo que instalações em frota executadas como SYSTEM funcionam e a rotação de um usuário atualiza a cópia que os outros leem), o grupo local sandbox-runtime-users, e instala um conjunto de filtros WFP em âmbito de máquina com chave no SID srt-sandbox. É idempotente — executá-lo novamente rotaciona a senha da conta de sandbox e reconcilia o conjunto de filtros.
Nenhum logout é necessário. Os filtros WFP têm como chave o SID da conta de sandbox dedicada, portanto sua própria rede, serviços e todos os outros principais na máquina não são afetados.
Após a instalação, SandboxManager.initialize() e a CLI srt funcionam como em outras plataformas. initialize() verifica se a conta de sandbox e a cerca WFP estão ativas e falha com um erro acionável caso não estejam.
A instalação/desinstalação programática é exportada como installWindowsSandbox() / uninstallWindowsSandbox().
Modelo de segurança
O comando em sandbox é executado como a conta srt-sandbox, não como o usuário chamador. O auxiliar srt-win.exe incluído faz um lançamento em dois saltos: o broker chama CreateProcessWithLogonW para iniciar um runner como srt-sandbox, e o runner gera o alvo sob um token restrito dentro de um job object. O filho herda o perfil isolado da conta de sandbox (%USERPROFILE%, %TEMP%, HKCU) e um ambiente novo sobreposto apenas com o PATH do broker e as variáveis de proxy geradas.
Executar sob um SID de usuário distinto fecha estruturalmente a classe de escape de spawn substituto (Task Scheduler, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS sobre um processo pertencente ao broker, BITS, COM fora de processo com RunAs="Interactive User"): qualquer processo que o filho consiga gerar fora de banda ainda carrega o SID srt-sandbox, portanto permanece sujeito à cerca de egresso WFP e não tem direitos sobre os arquivos do usuário chamador.
O isolamento de rede é um conjunto de dois filtros WFP na camada FWPM_LAYER_ALE_AUTH_CONNECT_V4/V6: um PERMIT para destinos de loopback dentro do intervalo de portas de proxy configurado (padrão 60080–60089), e um BLOCK para qualquer conexão cujo token carregue o SID srt-sandbox. O processo em sandbox alcança a internet apenas através dos proxies JS HTTP/SOCKS5 escutando nesse intervalo; um processo que remova seu ambiente de proxy e se conecte diretamente é bloqueado no kernel.
O isolamento de sistema de arquivos é imposto por ACLs discricionárias NTFS. A conta srt-sandbox não tem direitos inerentes sobre os arquivos do usuário chamador, portanto em initialize() o sandbox grava ACEs explícitas aditivas e herdáveis apenas para o SID srt-sandbox — ele nunca reescreve ou substitui o descritor de segurança existente de um caminho:
filesystem.allowWrite→ uma ACE ALLOWMODIFYherdável (READ|WRITE|EXECUTE|DELETE, comFILE_DELETE_CHILDretido). O processo em sandbox pode criar, modificar e excluir arquivos dentro da árvore de trabalho; reterFILE_DELETE_CHILDda concessão é defesa em profundidade para os carimbos de negação abaixo, não uma proteção na raiz da árvore.filesystem.allowRead→ uma ACE ALLOWREAD|EXECUTEherdávelfilesystem.denyRead/filesystem.denyWrite→ uma ACE DENY herdável sobre o alvo, mais uma DENY herdável deFILE_DELETE_CHILDsobre seu pai — juntamente com oFILE_DELETE_CHILDretido na concessão da árvore de trabalho, isso impede que o processo em sandbox renomeie ou exclua um caminho negado através de seu diretório pai
reset() remove toda ACE que esta sessão adicionou (com contagem de referências entre hosts concorrentes deste usuário via o banco de dados de sessão por usuário; uma passagem de recuperação de falhas no próximo initialize() limpa após uma saída não limpa). Alvos de diretório são suportados (as ACEs herdam para toda a subárvore). Padrões glob são expandidos para caminhos concretos no momento de initialize() — um caminho correspondente que apareça depois não é coberto.
Terminação TLS no Windows
network.tlsTerminate exige que a CA MITM esteja presente no repositório de certificados CurrentUser\Root do usuário de sandbox (schannel — o backend TLS usado por System32\curl.exe, PowerShell Invoke-WebRequest, .NET e git com backend padrão — confia apenas no repositório do SO, não em variáveis de ambiente). Este é um passo no momento da instalação, separado de windows-install:```typescript
import { windowsTrustCa } from '@anthropic-ai/sandbox-runtime'
windowsTrustCa('/path/to/mitm-ca.crt') // or: srt-win user trust-ca
`initialize()` compara o thumbprint do CA da sessão com o instalado e falha com uma mensagem acionável em caso de incompatibilidade, para que um CA obsoleto do momento da instalação não possa quebrar silenciosamente o TLS dentro do sandbox.
Clientes com suporte OpenSSL (`curl` do msys2, `git -c http.sslBackend=openssl`, Node, Python, cargo) são cobertos pela camada de confiança por variáveis de ambiente: o mesmo bundle de confiança usado no macOS/Linux é passado para o sandbox via `NODE_EXTRA_CA_CERTS`, `SSL_CERT_FILE`, `CURL_CA_BUNDLE`, `GIT_SSL_CAINFO`, `CARGO_HTTP_CAINFO`, etc., e o caminho do bundle é adicionado à concessão `allowRead` da sessão para que a conta do sandbox possa abri-lo.
### Configuração específica do Windows
Os blocos multiplataforma `filesystem` e `network` aplicam-se conforme descrito acima. As configurações exclusivas do Windows ficam em `windows`:
- `windows.proxyPortRange` — intervalo de portas inclusivo `[low, high]` no qual os proxies JS se vinculam. **Deve corresponder** ao intervalo passado para `windows-install --proxy-port-range` (padrão `[60080, 60089]`) — o PERMIT de loopback do WFP cobre apenas esse intervalo.
- `windows.sublayerGuid` — GUID da subcamada WFP sob a qual os filtros foram instalados. Omita para usar o padrão de tempo de compilação; defina apenas quando ferramentas empresariais instalaram os filtros sob uma subcamada personalizada.
- `windows.srtWin.path` — caminho para o binário `srt-win`. Omita para resolver o `vendor/srt-win/<arch>/srt-win.exe` empacotado. Defina ao incorporar a CLI do `srt-win` em um binário multicall; os spawns então passam `--srt-win` como `argv[1]` para que o dispatcher do incorporador possa rotear para `srt_win::run_from_args`.
### Limitações conhecidas
- **Revogação de certificado sob schannel.** A busca de CRL/OCSP do CryptoAPI sai via WinHTTP sob o token do chamador, ignorando o ambiente de proxy, portanto é bloqueada pela cerca de egresso do WFP. Ferramentas que usam schannel com verificação de revogação ativada por padrão falham com `CRYPT_E_REVOCATION_OFFLINE` (`0x80092013`) a menos que a revogação seja desativada por ferramenta: `curl --ssl-no-revoke`, `git -c http.schannelCheckRevoke=false`, `CARGO_HTTP_CHECK_REVOKE=false`. `Invoke-WebRequest`, `HttpClient` do .NET e `gh` não verificam revogação por padrão e não são afetados. Um ponto de distribuição de CRL servido a partir do proxy de loopback está planejado para remover essa solução alternativa.
- **Instalações de ferramentas por usuário não são acessíveis.** O processo em sandbox é executado como `srt-sandbox`, não como você, então ferramentas instaladas sob seu perfil (Node gerenciado por nvm/fnm, pacotes `winget`/Scoop por usuário, `pip install --user`, `%LOCALAPPDATA%\Programs\…`) resolvem no `PATH` herdado mas não podem ser abertas pela conta do sandbox. Prefira instalações em âmbito de máquina (`Program Files`, `choco`/`winget --scope machine`), ou adicione os caminhos específicos do perfil a `filesystem.allowRead`.
- **Substituições de `filesystem.allowRead` / `filesystem.allowWrite` por execução não são suportadas.** `allowRead`/`allowWrite` em nível de sessão (na configuração passada para `initialize()`) funcionam conforme descrito acima; passá-los por comando em `customConfig` de `wrapWithSandbox` lança erro — as concessões são aplicadas em toda a sessão via `srt-win acl grant` em `initialize()`, e `srt-win exec` expõe apenas negações por execução.
- **`proxyAuthToken` é visível na linha de comando do runner.** O ambiente de proxy (incluindo `HTTP_PROXY=http://srt:<token>@127.0.0.1:…`) é passado para o runner de dois saltos como argumentos `--env` no argv de `srt-win exec`, então o token é legível por qualquer principal local que possa abrir o processo do runner para `PROCESS_QUERY_LIMITED_INFORMATION`. O token existe para que o processo em sandbox possa se autenticar no proxy de loopback, então não é um segredo do próprio sandbox; em uma máquina de desenvolvimento de usuário único isso geralmente é aceitável, mas em um host compartilhado trate a allowlist do proxy como alcançável por outros principais da mesma sessão.
- **A resolução de DNS via o resolvedor do sistema não é cercada.** `getaddrinfo()` é atendido pelo serviço `Dnscache` executado como `NETWORK SERVICE`, então a resolução de nomes é bem-sucedida mesmo que o `connect()` subsequente do processo em sandbox seja bloqueado. Ferramentas que fazem seu próprio UDP/53 (`nslookup`, `dig`) são cercadas. Isso espelha o comportamento do macOS.
### Desinstalação```powershell
npx @anthropic-ai/sandbox-runtime windows-uninstall
Remove o conjunto de filtros WFP, a conta srt-sandbox e seu perfil, o grupo sandbox-runtime-users, e remove a chave HKLM\SOFTWARE\sandbox-runtime (credencial, marcador, registro CA) — um prompt do UAC. %ProgramData%\sandbox-runtime (o material da chave CA) é deixado no lugar; exclua-o (e %LOCALAPPDATA%\sandbox-runtime por usuário) manualmente para uma limpeza completa.
Desenvolvimento```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
### Compilando Binários Seccomp
O filtro BPF e o carregador `apply-seccomp` são compilados a partir do código-fonte C em `vendor/seccomp-src/` via `npm run build:seccomp` (apenas Linux; requer `gcc` e `libseccomp-dev`). O CI executa isso antes dos testes em cada arquitetura Linux, e o fluxo de trabalho de release compila ambas as arquiteturas e as empacota no pacote publicado.
## Detalhes de Implementação
### Arquitetura de Isolamento de Rede
O sandbox executa servidores proxy HTTP e SOCKS5 na máquina host que filtram todas as requisições de rede com base nas regras de permissão:
1. **Tráfego HTTP/HTTPS**: Um servidor proxy HTTP intercepta requisições e as valida contra domínios permitidos/negados
2. **Outro Tráfego de Rede**: Um proxy SOCKS5 lida com todas as outras conexões TCP (SSH, conexões de banco de dados, etc.)
3. **Aplicação de Permissões**: Os proxies aplicam as regras de `permissions` da sua configuração
**Comunicação de proxy específica por plataforma:**
- **Linux**: As requisições são roteadas via sistema de arquivos através de Unix domain sockets (usando `socat` para fazer a ponte). O network namespace é removido do contêiner bubblewrap, garantindo que todo o tráfego de rede deva passar pelos proxies.
- **macOS**: O perfil Seatbelt permite comunicação apenas para portas localhost específicas onde os proxies escutam. Todo outro acesso à rede é bloqueado.
- **Windows**: Um filtro WFP `ALE_AUTH_CONNECT` bloqueia toda conexão de saída da conta `srt-sandbox`, exceto loopback para a faixa de portas de proxy configurada. Os proxies se vinculam dentro dessa faixa. Variáveis de ambiente (`HTTP_PROXY`, `HTTPS_PROXY`, `ALL_PROXY`, …) apontam as ferramentas para os proxies, mas o filtro WFP é a fronteira — um processo que as ignora ou as desconfigura ainda está cercado.
**Ferramentas JVM (macOS/Linux):** a JVM ignora `HTTPS_PROXY`/`NO_PROXY` e não possui variável de ambiente para credenciais de proxy — a seleção de proxy vem das propriedades de sistema `https.proxyHost` e a credencial só pode ser fornecida através de `java.net.Authenticator`. Portanto, ferramentas baseadas em JVM (cache remoto gRPC do Bazel, Gradle, Maven, …) de outra forma discariam diretamente para o alvo e falhariam, ou alcançariam o proxy sem seu token e receberiam um 407. Para fechar essa lacuna, o srt injeta um pequeno `-javaagent` via `JAVA_TOOL_OPTIONS` (a variável de ambiente carrega apenas o caminho do jar, a credencial permanece em `HTTPS_PROXY`). Na inicialização da JVM, o agente define `http[s].proxyHost`/`Port` e `http.nonProxyHosts` a partir das variáveis de ambiente do proxy, reativa a autenticação Basic para túneis CONNECT e instala um Authenticator para o endpoint do proxy. Propriedades de proxy `-D` explícitas na linha de comando da JVM ainda prevalecem, e qualquer `JAVA_TOOL_OPTIONS` herdada é preservada (a menos que seja uma variável de ambiente de credencial negada). Toda JVM imprime uma linha `Picked up JAVA_TOOL_OPTIONS: …` no stderr como resultado; um runtime jlink'd compilado sem o módulo `java.instrument` não pode carregar agentes e se recusará a iniciar sob o sandbox — desconfigure `JAVA_TOOL_OPTIONS` no comando para tal ferramenta. O jar é distribuído no pacote npm como `vendor/java-proxy-agent/srt-proxy-agent.jar` (fonte: `vendor/java-proxy-agent-src/`; compilado pelo fluxo de trabalho de release, ou localmente com `npm run build:java-agent` — requer um JDK ≥ 17). Se não for encontrado, `JAVA_TOOL_OPTIONS` é deixada em paz e as JVMs se comportam como antes; bundlers podem apontar para sua própria cópia com `javaAgentJarPath`.
### Isolamento de Sistema de Arquivos
As restrições de sistema de arquivos são aplicadas no nível do SO:
- **macOS**: Usa `sandbox-exec` com perfis Seatbelt gerados dinamicamente que especificam caminhos de leitura/escrita permitidos
- **Linux**: Usa `bubblewrap` com bind mounts, marcando diretórios como somente leitura ou leitura-escrita com base na configuração
- **Windows**: Escreve ACEs explícitas aditivas `(OI)(CI)` para o SID `srt-sandbox` nos caminhos configurados (ALLOW em `allowRead`/`allowWrite`, DENY em `denyRead`/`denyWrite`), depois as remove em `reset()`
**Permissões de sistema de arquivos padrão:**
- **Leitura** (negar-depois-permitir): Permitida em todos os lugares por padrão. Você pode negar regiões amplas e depois re-permitir caminhos específicos dentro delas. `allowRead` tem precedência sobre `denyRead`.
- Exemplo: `denyRead: ["~/.ssh"]` para bloquear acesso a chaves SSH
- Exemplo: `denyRead: ["/Users"], allowRead: ["."]` para bloquear todo o `/Users` exceto o workspace
- `denyRead: []` vazio = acesso total de leitura (nada negado)
- **Escrita** (apenas-permitir): Negada em todos os lugares por padrão. Você deve permitir caminhos explicitamente.
- Exemplo: `allowWrite: [".", "/tmp"]` para permitir escritas no diretório atual e /tmp
- `allowWrite: []` vazio = sem acesso de escrita (nada permitido)
- `denyWrite` cria exceções dentro de caminhos permitidos (negar tem precedência)
**A precedência é intencionalmente oposta para leituras vs escritas:** `allowRead` sobrescreve `denyRead`, enquanto `denyWrite` sobrescreve `allowWrite`. Isso permite que você recorte regiões legíveis dentro de áreas negadas, e recorte regiões protegidas dentro de áreas graváveis.
### Caminhos de Negação Obrigatória (Arquivos Auto-Protegidos)
Certos arquivos e diretórios sensíveis são **sempre bloqueados para escrita**, mesmo que estejam dentro de um caminho de escrita permitido. Isso fornece defesa em profundidade contra escapes do sandbox e adulteração de configuração.
**Arquivos sempre bloqueados:**
- Arquivos de configuração de shell: `.bashrc`, `.bash_profile`, `.zshrc`, `.zprofile`, `.profile`
- Arquivos de configuração do Git: `.gitconfig`, `.gitmodules`
- Outros arquivos sensíveis: `.ripgreprc`, `.mcp.json`
**Diretórios sempre bloqueados:**
- Diretórios de IDE: `.vscode/`, `.idea/`
- Diretórios de configuração do Claude: `.claude/commands/`, `.claude/agents/`
- Hooks e configuração do Git: `.git/hooks/`, `.git/config`
Esses caminhos são bloqueados automaticamente - você não precisa adicioná-los a `denyWrite`. Por exemplo, mesmo com `allowWrite: ["."]`, escrever em `.bashrc` ou `.git/hooks/pre-commit` falhará:```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): No Linux, os caminhos de negação obrigatória apenas bloqueiam ficheiros que já existem. Ficheiros inexistentes nestes padrões não podem ser bloqueados pela abordagem de bind-mount do bubblewrap. O macOS usa padrões glob que bloqueiam tanto ficheiros existentes como novos.
Profundidade de pesquisa no Linux: No Linux, a sandbox usa ripgrep para procurar ficheiros perigosos em subdiretórios dentro dos caminhos de escrita permitidos. Por predefinição, pesquisa até 3 níveis de profundidade por motivos de desempenho. Pode configurar isto com mandatoryDenySearchDepth:```json
{
"mandatoryDenySearchDepth": 5,
"filesystem": {
"allowWrite": ["."]
}
}
- Padrão: `3` (pesquisa até 3 níveis de profundidade)
- Intervalo: `1` a `10`
- Valores mais altos oferecem mais proteção, mas desempenho mais lento
- Arquivos no CWD (profundidade 0) são sempre protegidos independentemente desta configuração
### Restrições de Unix Socket (Linux)
No Linux, o sandbox usa **seccomp BPF (Berkeley Packet Filter)** para bloquear a criação de Unix domain socket no nível de syscall. Isso fornece uma camada adicional de segurança para impedir que processos criem novos Unix domain sockets para IPC local (a menos que explicitamente permitido).
**Como funciona:**
1. **Filtro BPF embutido**: O pacote inclui um binário estático `apply-seccomp` para x64 e arm64 com o filtro seccomp BPF compilado. O filtro é específico da arquitetura, mas independente da libc, então o binário funciona tanto com glibc quanto com musl.
2. **Detecção em tempo de execução**: O sandbox detecta automaticamente a arquitetura do seu sistema e usa o binário `apply-seccomp` correspondente.
3. **Filtragem de syscall**: O filtro BPF intercepta a syscall `socket()` e bloqueia a criação de sockets `AF_UNIX` retornando `EPERM`. Isso impede que código em sandbox crie novos Unix domain sockets.
4. **Aplicação em dois estágios usando o binário apply-seccomp**:
- O bwrap externo cria o sandbox com restrições de filesystem, rede e namespace de PID
- Processos de ponte de rede (socat) iniciam dentro do sandbox (precisam de Unix sockets)
- apply-seccomp cria um namespace aninhado de usuário+PID+mount e remonta `/proc`
- Dentro do namespace aninhado, apply-seccomp atua como PID 1 (init/reaper non-dumpable)
- apply-seccomp faz fork, aplica o filtro seccomp via `prctl()` e executa o comando do usuário
- O comando do usuário é executado com todas as restrições do sandbox mais o bloqueio de criação de Unix socket
**Isolamento de namespace de PID**: O namespace de PID aninhado garante que o comando do usuário não possa ver ou endereçar qualquer processo que seja executado sem o filtro seccomp (o init do bwrap, o wrapper de shell ou os auxiliares socat). Isso mantém a fronteira do seccomp intacta independentemente de `kernel.yama.ptrace_scope`, já que auxiliares não filtrados não são alcançáveis via `ptrace` ou `/proc/N/mem`. O PID 1 interno define `PR_SET_DUMPABLE=0` para que também não seja ptraceable. Se a criação do namespace aninhado falhar, apply-seccomp aborta em vez de executar sem isolamento.
**Limitações de segurança**: O filtro bloqueia `socket(AF_UNIX, ...)` e as syscalls `io_uring_setup`/`io_uring_enter`/`io_uring_register` (as três últimas porque `IORING_OP_SOCKET` no Linux 5.19+ contornaria a regra de `socket()`). Ele não impede operações em descritores de arquivo de Unix socket herdados de processos pai ou passados via `SCM_RIGHTS`. Para a maioria dos cenários de sandbox, bloquear a criação de socket é suficiente para impedir IPC não autorizado.
**Zero dependências em tempo de execução**: Binários estáticos apply-seccomp pré-compilados e filtros BPF pré-gerados estão incluídos para arquiteturas x64 e arm64. Nenhuma ferramenta de compilação ou dependência externa é necessária em tempo de execução.
**Suporte de arquitetura**: x64 e arm64 são totalmente suportados com binários pré-compilados. Outras arquiteturas não são suportadas atualmente. Para usar sandbox sem bloqueio de Unix socket em arquiteturas não suportadas, defina `allowAllUnixSockets: true` na sua configuração.
### Detecção e Monitoramento de Violações
Quando um processo em sandbox tenta acessar um recurso restrito:
1. **Bloqueia a operação** no nível do SO (retorna erro `EPERM`)
2. **Registra a violação** (mecanismos específicos da plataforma)
3. **Notifica o usuário** (no Claude Code, isso aciona um prompt de permissão)
**macOS**: O runtime do sandbox acessa o armazenamento de log de violações do sandbox do sistema do macOS. Isso fornece notificações em tempo real com informações detalhadas sobre o que foi tentado e por que foi bloqueado. Este é o mesmo mecanismo que o Claude Code usa para detecção de violações.```bash
# View sandbox violations in real-time
log stream --predicate 'process == "sandbox-exec"' --style syslog
Linux: O Bubblewrap não fornece relatórios de violação integrados. Use strace para rastrear chamadas de sistema e identificar operações bloqueadas:```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
### Avançado: Traga Seu Próprio Proxy
Para uma filtragem de rede mais sofisticada, você pode configurar o sandbox para usar seu próprio proxy em vez dos integrados. Isso permite:
- **Inspeção de tráfego**: Use ferramentas como [mitmproxy](https://mitmproxy.org/) para inspecionar e modificar o tráfego
- **Lógica de filtragem personalizada**: Implemente regras complexas além de simples listas de permissões de domínio
- **Registro de auditoria**: Registre todas as requisições de rede para conformidade ou depuração
**Exemplo com mitmproxy:**```bash
# Start mitmproxy with custom filtering script
mitmproxy -s custom_filter.py --listen-port 8888
Nota: A configuração de proxy personalizado ainda não é suportada no novo formato de configuração. Esta funcionalidade será adicionada numa versão futura.
Consideração de segurança importante: Mesmo com listas de domínios permitidos, podem existir vetores de exfiltração. Por exemplo, permitir github.com deixa um processo fazer push para qualquer repositório. Com um proxy MITM personalizado e a configuração adequada de certificados, pode inspecionar e filtrar chamadas de API específicas para evitar isto.
Limitações de Segurança
- Limitações do Sandboxing de Rede: O sistema de filtragem de rede funciona restringindo os domínios aos quais os processos podem ligar-se. Não inspeciona de outra forma o tráfego que passa pelo proxy e os utilizadores são responsáveis por garantir que apenas permitem domínios de confiança na sua política. Os nomes de host permitidos são adicionalmente verificados contra um conjunto negado de endereços resolvidos antes de uma ligação direta (ver Verificação de endereços resolvidos acima), pelo que um nome permitido não pode ser apontado para loopback, link-local, os próprios endereços deste host ou um IP que listou em
deniedDomains; outros intervalos privados só são cobertos se os listar emdeniedResolvedAddresses(uma entrada wildcard num domínio cujo DNS não controla pode, de outra forma, ser direcionada para serviços na sua LAN), e as ligações que saem através deparentProxy/mitmProxydependem desse salto para a verificação equivalente.
- Escalação de Privilégios via Unix Sockets: A configuração
allowUnixSocketspode inadvertidamente conceder acesso a serviços de sistema poderosos que podem levar a contornar o sandbox. Por exemplo, se for usada para permitir acesso a/var/run/docker.sock, isto concederia efetivamente acesso ao sistema anfitrião através da exploração do socket do docker. Os utilizadores são encorajados a considerar cuidadosamente quaisquer unix sockets que permitam através do sandbox. - Escalação de Permissões do Sistema de Ficheiros: Permissões de escrita excessivamente amplas no sistema de ficheiros podem permitir ataques de escalação de privilégios. Permitir escritas em diretórios que contenham executáveis em
$PATH, diretórios de configuração do sistema, ou ficheiros de configuração de shell do utilizador (.bashrc,.zshrc) pode levar à execução de código em diferentes contextos de segurança quando outros utilizadores ou processos do sistema acedem a estes ficheiros. - Robustez do Sandbox no Linux: A implementação para Linux proporciona um forte isolamento de sistema de ficheiros e de rede, mas inclui um modo
enableWeakerNestedSandboxque lhe permite funcionar dentro de ambientes Docker sem namespaces privilegiados. Esta opção enfraquece consideravelmente a segurança e só deve ser usada em casos onde seja imposto isolamento adicional por outros meios. - Isolamento de Rede Mais Fraco (macOS): A opção
enableWeakerNetworkIsolationreativa o acesso acom.apple.trustd.agent, que é necessário para programas Go verificarem certificados TLS através da framework Security do macOS. Isto abre um potencial vetor de exfiltração de dados através do serviço trustd e só deve ser ativado quando a verificação TLS do Go for necessária (por exemplo, ao usarhttpProxyPortcom um proxy MITM e uma CA personalizada). - Apple Events (macOS): A opção
allowAppleEventsreativa o envio de Apple Events e pedidos de abertura do Launch Services ((allow appleevent-send),(allow lsopen), e mach-lookups paracom.apple.coreservices.appleevents,com.apple.CoreServices.coreservicesd, ecom.apple.coreservices.quarantine-resolver), queopen,osascript, e auxiliares de abertura de URL requerem. Com estes permitidos, um comando em sandbox pode lançar aplicações arbitrárias sem qualquer pedido ao utilizador, e as aplicações lançadas correm inteiramente fora do sandbox — pelo que esta opção remove o isolamento de execução de código, não apenas o enfraquece. A scriptagem de aplicações já em execução via Apple Events é adicionalmente condicionada pelo consentimento de automação TCC do macOS, mas o lançamento viaopennão é. Só ative isto quando os comandos dentro do sandbox precisarem genuinamente de abrir URLs ou aplicações.
Limitações Conhecidas e Trabalho Futuro
Bypass do proxy no Linux: Atualmente usa variáveis de ambiente (HTTP_PROXY, HTTPS_PROXY, ALL_PROXY) para direcionar o tráfego através de proxies. Isto funciona para a maioria das aplicações, mas pode ser ignorado por programas que não respeitam estas variáveis, levando a que não consigam ligar-se à internet.
Melhorias futuras:
-
Suporte a Proxychains: Adicionar suporte para
proxychainscomLD_PRELOADno Linux para intercetar chamadas de rede a um nível mais baixo, tornando o bypass mais difícil -
Monitorização de violações no Linux: Implementar deteção automática de violações baseada em
stracepara Linux, integrada com o armazenamento de violações. Atualmente, os utilizadores de Linux têm de executar manualmentestracepara ver violações, ao contrário do macOS que tem monitorização automática de violações através do armazenamento de logs do sistema