Ir al contenido

Backends de sandbox

Backend Valor Plataforma Disponibilidad
VM aislada microvm macOS, Linux, Windows (hipervisor de microVM) Condicionado por el sondeo del entorno de ejecución de microVM; se aplica a terminales interactivos — el shell se ejecuta dentro de un rig, no en el host
Nativo native macOS (Seatbelt), Linux y WSL2 (bubblewrap) Se sondea al arrancar; Linux rechaza una ejecución que exija denegaciones de escritura por glob de nombre de archivo, que bubblewrap no puede aplicar
Ninguno none Todas El valor predeterminado al analizar la opción, el predeterminado del terminal y el valor al que se recurre cuando no hay ningún backend disponible o se establece --sandbox off

SandboxBackend.fromName devuelve none para un valor almacenado nulo o no reconocido. Un "docker" almacenado se asigna a native.

microvm es el único backend con una frontera del kernel — la carga de trabajo realmente no se ejecuta en el host. Nunca es una alternativa silenciosa en ninguna dirección: pedirlo de forma explícita en un host que no puede arrancar una VM falla de forma ruidosa («pedí una VM y obtuve mi computadora portátil» es la única degradación que el recinto no puede permitirse), y solo un valor predeterminado sin especificar desciende a native, con una línea de registro que lo indica. El backend real de la sesión se informa de vuelta al cliente y se marca con una insignia, así que un terminal nunca puede afirmar estar dentro de un recinto mientras se ejecuta en el host. El ciclo de vida, las imágenes y la salida de la propia VM se cubren en la referencia de rigs.

Windows no tiene sandbox nativo. NativeSandboxAdapter.probe devuelve available: false en todos los host que no sean macOS o Linux/WSL2. Por lo tanto, el despacho de agentes en Windows usa none. El backend microvm es aparte: está condicionado por el sondeo del entorno de ejecución de microVM y se aplica a terminales interactivos y rigs, no a envolver bash en el host.

El sondeo es lo que condiciona la aplicación. Se ejecuta una sola vez, al arrancar el servidor.

Host available Nota o sugerencia
macOS true sandbox-exec (Seatbelt) — aislamiento de espacios de nombres, sin frontera del kernel
Linux o WSL2 con bwrap y socat true bubblewrap — aislamiento de espacios de nombres, sin frontera del kernel
Linux o WSL2 sin alguna de esas herramientas false requiresInstall: true, con una sugerencia de instalación que nombra los paquetes faltantes
Cualquier otra plataforma false El sandbox nativo no se ofrece en esta plataforma

El servidor registra el resultado en una sola línea de arranque: agent sandbox ON más la nota, no OS-native agent sandbox on this host más la sugerencia, o agent sandbox DISABLED by --sandbox off. GET /healthz no incluye ningún campo de sandbox.

--sandbox / CC_SERVER_SANDBOX acepta on (predeterminado) u off. Es una opción para desactivarlo, no para activarlo: on significa «envuelve cuando el host ofrece un backend», nunca «exige uno».

Usa el mecanismo de sandbox Seatbelt de Apple (el mismo sistema que utiliza el sandbox de apps de macOS).

El perfil generado es permisivo de forma predeterminada ((allow default)) y recorta denegaciones, porque un perfil totalmente de denegación por defecto vuelve inutilizable un shell interactivo: hay demasiadas llamadas dyld, XPC y Mach que enumerar. La consecuencia práctica es que un agente todavía puede leer buena parte del host; tus checkouts registrados están protegidos por denegaciones explícitas de escritura y de renombrado, no por invisibilidad.

  • Lecturas del sistema de archivos: se deniegan las rutas secretas (~/.ssh, ~/.aws, ~/.gnupg, ~/.config/gh, ~/Library/Keychains y el resto del conjunto de denegación de lectura)
  • Escrituras del sistema de archivos: se restablecen a denegar y luego se permiten subrutas explícitas, con las rutas de denegación obligatoria (archivos rc del shell, .git/hooks, la configuración de Claude, los checkouts protegidos) bloqueadas incluso dentro de una raíz escribible. file-write-unlink se deniega en cada ruta denegada y en sus ancestros, así que un renombrado no puede eludir una denegación de escritura
  • Procesos: se deniega process-exec para los binarios siempre peligrosos, además de un bloqueo a la ejecución de cualquier cosa desde un directorio escribible
  • Red: se restringe a los puertos del proxy en proceso más DNS; loopback no está permitido de forma general y los sockets Unix no están permitidos. Los proxies aplican la lista de permitidos de dominios por sesión (consulta Salida de red)
  • Configuración: los perfiles se generan en cada lanzamiento a partir del SandboxSpec

Requisitos:

  • sandbox-exec (/usr/bin/sandbox-exec), incluido en toda instalación de macOS: no se necesita ninguna herramienta adicional

Usa bubblewrap (bwrap) para crear espacios de nombres de montaje y de PID.

  • Sistema de archivos: crea un espacio de nombres de montaje donde solo son visibles las rutas montadas con bind
  • Red: se ejecuta en un espacio de nombres de red no compartido; el tráfico llega a los proxies del host a través de puentes de socket Unix de socat
  • Procesos: aislamiento del espacio de nombres de PID

Requisitos:

  • bubblewrap y socat instalados (sudo apt-get install bubblewrap socat en Debian/Ubuntu)
  • Compatibilidad con espacios de nombres del kernel (estándar en Linux moderno)

Bubblewrap puede ocultar una ruta existente, pero no puede prohibir un archivo .env, *.key o *.pem nuevo dentro de un montaje bind escribible. La política de despacho estándar exige estas denegaciones por glob de nombre de archivo, así que el despacho nativo de agentes actualmente falla cerrado en Linux/WSL2 incluso cuando el sondeo encuentra bubblewrap. No se ejecuta con una política silenciosamente más débil. Se necesita un backend con reglas de nombre de archivo en el momento de la creación para restaurar el despacho nativo en Linux. Deshabilitar el sandbox es una opción explícita y sin confinamiento, no un rodeo equivalente.

Sin sandbox. El proceso se ejecuta directamente en el host con el acceso del host al sistema de archivos, la red y los procesos. ACP y la herramienta bash del arnés siguen recibiendo saneamiento del entorno y la política de comandos; Claude Code a través de NoSandboxAdapter hereda el entorno del host. Es aquello a lo que recurre el despacho de agentes en un host sin ningún backend disponible o con --sandbox off, y es el valor predeterminado del terminal cuando un cliente no indica ninguno.

El terminal se somete a sandbox según sus propias reglas, no según el sondeo del despacho. El defaultBackend de TerminalSessionService es none y cc_server no lo sobrescribe, así que una sesión de terminal ejecuta el shell del host a menos que el cliente pida native de forma explícita; el panel de terminal de la aplicación de escritorio no lo hace.

Cuando se solicita native, el shell se envuelve a través de SandboxManager con un perfil de terminal fijo: $HOME y el directorio de trabajo de la sesión son escribibles, la red está abierta y se deniega la lectura de ~/.ssh, ~/.aws, ~/.gnupg, ~/.config/gh y ~/Library/Keychains. El token de forja de solo lectura y la pasarela de push no aplican: son competencia del despacho. Si la envoltura no es compatible, la sesión falla en lugar de mostrar una insignia de nativo en un PTY del shell del host.

Cuando se lanza un sandbox, el acceso saliente a la red lo aplican proxies en proceso, no reglas de firewall del kernel. En un host sin ningún backend disponible nada de esto aplica, y un proceso lanzado llega a la red exactamente como lo haría el usuario del servidor.

  • El entorno de ejecución del sandbox levanta un proxy HTTP/HTTPS y un proxy SOCKS5 en 127.0.0.1 dentro del proceso cc_server, un par por sesión restringida (http_proxy.dart, socks_proxy.dart). Las ejecuciones simultáneas no comparten un par.
  • Los procesos en sandbox reciben variables de entorno de proxy (HTTP_PROXY/HTTPS_PROXY → el proxy HTTP, ALL_PROXY → el proxy SOCKS; GIT_SSH_COMMAND enruta git sobre SSH a través del proxy SOCKS). En Linux el espacio de nombres de red no se comparte, así que los proxies son la única salida; en macOS el sandbox comparte el loopback del host y se comunica con ellos directamente.
  • El host de destino de cada conexión se compara con la lista de permitidos de dominios de la sesión; cualquier otra cosa se deniega. Hay dos formas de comodín, cada una con exactamente un *: una al principio, *.example.com, coincide con cualquier subdominio (incluido a.b.example.com) pero no con el dominio raíz; una en una etiqueta intermedia, bedrock.*.amazonaws.com, coincide con exactamente una etiqueta (bedrock.us-east-1.amazonaws.com, no bedrock.evil.attacker.amazonaws.com).
  • La lista de permitidos se resuelve por sesión a partir de la línea base curada (kBaselineAllowedDomains: proveedores de LLM, alojamiento de Git, registros de paquetes), más los dominios de GitHub (kGithubDomains), más SandboxSpec.egressAllowlist. La ruta de despacho nunca pasa entradas adicionales de egressAllowlist, así que en la práctica cada ejecución recibe la línea base más GitHub.
  • Una lista fija de denegación (kBaselineDeniedDomains: endpoints de metadatos de la nube, sumideros de telemetría) prevalece sobre todos los permisos.
  • networkEnabled: false igualmente arranca los proxies por sesión, pero la lista de permitidos está vacía, así que se rechaza toda conexión saliente. El despacho lo fija al arrancar la ejecución a partir de la regla Acceder a la red: denegar desactiva la red; permitir y preguntar primero la dejan activada.

La especificación que se pasa a SandboxPort.launch:

Campo Tipo Descripción
sessionId String Identificador estable de sesión (normalmente el id del espacio)
workspaceId String Id del espacio de trabajo propietario
agentId String? Agente vinculado actualmente al sandbox, si lo hay
bindMounts List<SandboxBindMount> Montajes host→huésped; el sandbox solo ve las rutas del host que se enumeran aquí
networkEnabled bool (predeterminado true) Lo fija el despacho a partir de la regla de salida a la red (desactivado solo cuando se resuelve como denegar). Cuando está desactivado, los proxies por sesión siguen arrancando, pero la lista de permitidos está vacía, así que se rechaza toda conexión saliente
egressAllowlist List<String> (predeterminado []) Dominios de salida adicionales permitidos; se admiten comodines (*.example.com, además de una forma intermedia de una sola etiqueta). El despacho nunca rellena esto, así que una ejecución envuelta recibe la línea base curada más los dominios de GitHub
guestWorkdir String? Directorio de trabajo predeterminado dentro del sandbox; cada llamada exec puede sobrescribirlo
mode Mode (predeterminado chat) Define las reglas de escritura del sistema de archivos: chat mantiene escribibles los montajes bind; review, plan y orchestrate son de solo lectura
protectedPaths List<String> (predeterminado []) Rutas del host que nunca deben ser escribibles dentro del sandbox, en ningún modo
runnerStateDirs List<String> (predeterminado []) Directorios del host donde el runner guarda su propio estado, escribibles en todos los modos (el actual es un CLAUDE_CONFIG_DIR administrado por Control Center)
execGrantRoots List<String> (predeterminado []) Árboles de directorios aprobados por el operador que reabren el bloqueo de exec de directorios escribibles en macOS. Linux los ignora: bwrap no tiene ningún bloqueo de exec de $HOME que reabrir

protectedPaths contiene los checkouts originales de los repos registrados, resueltos en cada despacho a partir de los repos del espacio de trabajo. Los agentes trabajan exclusivamente en worktrees de copia en escritura por conversación, así que los originales nunca deben ser escribibles desde dentro del sandbox; en macOS, el permiso de escritura general que Seatbelt concede a $HOME los dejaría, de lo contrario, escribibles por medio de bash. Se suman al conjunto de denegación de escritura de secretos en todos los modos, incluido chat.

Cada ruta de denegación de lectura y de escritura se emite tanto en su forma literal como en su forma resuelta por enlaces simbólicos. El kernel compara una regla de denegación con la ruta resuelta, así que una regla escrita contra una ruta con enlaces simbólicos nunca se activa, y en macOS ese es el caso habitual y no el exótico, ya que /tmp se resuelve como /private/tmp y /var/folders/… como /private/var/folders/…. Las entradas que contienen * o ? se tratan como globs y se dejan tal cual; una ruta que no se resuelve se conserva tal como se escribió.

Campo Tipo Descripción
hostPath String Ruta absoluta en el host
guestPath String Ruta dentro del sandbox (con el sandbox nativo es igual a hostPath; se conserva por simetría entre adaptadores)
readOnly bool (predeterminado false) Se monta en solo lectura cuando es true

Lo devuelve SandboxPort.launch:

Campo Tipo Descripción
sessionId String Identificador de sesión
backend SandboxBackend Qué backend se está ejecutando
state SandboxState Estado del ciclo de vida
error Object? Se establece cuando state es error
details Map<String, Object?> Registro interno del adaptador (directorio de trabajo, PID, ruta del perfil, etc.)
Estado Descripción
created La especificación se creó, pero la VM aún no ha arrancado
warm En ejecución y lista para ejecutar comandos
active Ejecutando un comando en este momento
suspended En pausa o con punto de control en disco para ahorrar RAM
destroyed Desmontado; el handle ya no es válido
error El lanzamiento falló; consulta SandboxHandle.error
Tipo de evento Descripción
stdout Salida estándar del sandbox
stderr Error estándar del sandbox
exit El proceso del sandbox terminó (incluye exitCode)
starting El sandbox está arrancando
ready El sandbox está listo para aceptar llamadas exec
killed El host mató el proceso (OOM, tiempo de espera agotado, detención manual)
violation Se infringió una política del sandbox (incluye un SandboxViolation)
Campo Tipo Descripción
action String El verbo denegado (p. ej. file-read*, network-outbound)
target String Ruta o host que fue el destino de la operación denegada
raw String? Línea de registro sin procesar, útil para la depuración