Saltar al contenido
Menú
¿Lo necesito?Lo que un agente puede alcanzar en tu máquinaCómo funcionaLas capas entre el agente y tu sistemaCompararSandboxes integrados, Docker y VMsConfigurarAbre solo lo que la tarea necesitaSeguridadEl modelo de amenazas y sus límitesDescargarBinarios, checksums y notas de la versiónInstalar
Seguridad

Una capa útil, con bordes conocidos

ai-jail está hecho para frenar los errores de un agente de confianza y mantener el daño dentro del proyecto: el directorio del proyecto es el radio de impacto, y tu home, tus claves y la red quedan fuera de él. Es un sandbox de procesos que comparte tu kernel, así que no es una frontera contra código hostil ni contra un atacante decidido, y no reemplaza a una máquina virtual desechable.

Para quien firma la aprobación, y después para el ingeniero de seguridad.

Lo que está hecho para detener

Un agente de confianza igual escribe mal un comando, ejecuta un script que sube por encima de la raíz del proyecto o se deja engañar por una página web o un paquete. Esto es lo que entonces intenta alcanzar, y no encuentra.

↔ Desliza hacia un lado para ver el diagrama completo

Los valores por defecto. Todo lo que está fuera se queda ahí hasta que lo abras tú.

Fuera de alcance

  • Tu directorio home y las credenciales que contiene. El agente recibe un home nuevo y vacío, así que ~/.ssh y ~/.aws no existen ahí dentro.
  • Los secretos de tu shell. ai-jail reduce las variables de entorno a una lista de permitidos pequeña, así que los tokens exportados se quedan fuera. La única excepción es la clave de API del propio harness que arrancas, por ejemplo ANTHROPIC_API_KEY para Claude, copiada por defecto junto con su login; --no-agent-state lo impide.
  • La red. Está cerrada, con dos excepciones que pasan por el proxy filtrado: una lista corta de registries de paquetes cuando las toolchains están activadas, lo normal en Linux, y, para un agente conocido, el host de su propia API, en ambas plataformas. Los hosts de telemetría siguen cerrados. --no-network cierra ambas cosas.
  • La memoria compartida del host, tu servidor gráfico y tu portapapeles. La salida del agente pasa por un filtro que descarta las secuencias de terminal de portapapeles y de consulta.
  • Escribir en tu terminal. Linux bloquea la llamada TIOCSTI, que falsifica pulsaciones de teclas, y macOS limita el control de terminal a la única terminal que ai-jail creó para esa ejecución.
  • Sus propias reglas. Un archivo .ai-jail dentro de un repositorio no es de confianza: puede endurecer el sandbox y nunca abrirlo.
Cómo lo hace cada capa

Dónde termina el muro

La jaula y tu sistema se apoyan en el mismo kernel. Un bug en ese kernel, en un driver o en el backend del sandbox es una forma de rodear el muro, y ai-jail no puede hacer nada al respecto. Una máquina virtual trae su propio kernel, y por eso es la frontera más fuerte.

↔ Desliza hacia un lado para ver el diagrama completo

Un sandbox comparte el suelo con lo que protege, y una VM trae el suyo.

Lo que esto significa para tus datos

  • Secretos dentro del proyecto. Un archivo .env en el repositorio se puede leer salvo que lo enmascares. Mira cómo enmascarar archivos.
  • Las máscaras cubren solo las rutas que existen cuando arranca el sandbox. Un archivo con secretos creado después, durante la sesión, no queda oculto.
  • Un host permitido es de confianza por completo. Permitir github.com con --allow-host deja que el agente haga push a cualquier repositorio de ahí, no solo a los tuyos.
  • --network abre toda la red, así que todo lo que el agente pueda leer, tu proyecto incluido, puede enviarlo fuera.
  • ai-jail monta el login del propio agente por defecto, en lectura y escritura, así que un agente engañado puede usarlo mientras dure el arranque. El proyecto lo documenta como una concesión por comodidad; --no-agent-state da una ejecución sin sesión.
  • El git del host confía en el .git/ del proyecto, que es escribible. Un programa nombrado en .git/config, como core.fsmonitor o core.pager, o dejado en .git/hooks/ corre como tú, fuera del sandbox, la próxima vez que un comando git que coincida se ejecute en el host; para core.fsmonitor basta un simple git status, incluso uno que tu editor lance en segundo plano, y nada aparece en git diff. --lockdown lo cierra al dejar el proyecto en solo lectura, y --map .git mantiene el repositorio en solo lectura en una ejecución normal, a cambio de no poder hacer commit desde dentro. Después de una sesión que te sorprenda, lee .git/config y lista .git/hooks con herramientas de archivos simples antes de ejecutar git en el host, porque el propio git config --list arranca el pager configurado.
  • --mask y --deny-path cambian solo lo que ve el sandbox. Cualquier cosa fuera del sandbox que actúe por el agente sigue leyendo los archivos reales: el daemon de Docker bajo --docker, un servidor MCP alcanzado por un socket mapeado o un servicio detrás de --forward-port.
Para el ingeniero de seguridad
  • Vulnerabilidades del kernel y de los drivers. Cada proceso aislado habla con el mismo kernel que el resto de tu máquina.
  • Bugs en tu emulador de terminal, sobre todo con --terminal-passthrough, que apaga el filtro de salida.
  • Defectos en el propio backend del sandbox: bubblewrap, Landlock y seccomp en Linux, sandbox-exec en macOS.
  • Landlock, las reglas del propio kernel, solo valla los sockets Unix abstractos y las señales en kernels 6.12 o más nuevos, en modo best-effort. Los kernels más antiguos se quedan solo con las reglas de sistema de archivos y de red, así que con --x11, --network o --systemd-user los sockets abstractos y las señales del host siguen al alcance.
  • Canales laterales y algunas clases de comunicación entre procesos.
  • La salida filtrada es solo TCP. No hay UDP, así que un programa que lo necesite no funciona; tampoco puede sacar nada por ahí.
  • El DNS bajo --allow-host. En Linux, las consultas de nombres dentro del sandbox fallan, así que no hay canal DNS hacia fuera. En macOS el resolver del sistema no está vallado, así que queda un canal DNS de poco ancho de banda, la misma brecha que Anthropic documenta para su propio sandbox-runtime.
  • El proxy ve el host, el puerto y el momento de cada conexión. Lo que viaja dentro queda entre los dos extremos. Cómo está construida la salida filtrada.
  • Las credenciales fantasma trasladan la confianza al propio ai-jail. Con --secret, las peticiones al host vinculado pasan por ai-jail en claro para que pueda insertar la clave real, y las vuelve a cifrar al salir. Los túneles hacia cualquier otro host siguen siendo opacos. Solo cubre a los clientes que pueden hablar HTTP plano con el proxy para ese host.
  • Credenciales que pasas con --github, --aws, --kube, --gcloud o --docker-config. Solo lectura protege el archivo contra cambios, no la credencial contra el uso: cualquier cosa dentro del sandbox puede actuar como tú en ese servicio mientras siga siendo válida.
  • En macOS, sandbox-exec está marcado como obsoleto por Apple y no equivale al aislamiento de Linux. Mira las diferencias en macOS.

Interruptores que abren el muro

Todo lo de abajo está apagado hasta que lo activas, salvo dos interruptores que vienen activados por defecto: --toolchains en Linux y --agent-state en todas partes. La mayoría le da al agente un acceso real. Cómo configurarlos está en la página Configurar.

Mostrar todos los interruptores y sus consecuencias
InterruptorLo que puede hacer entonces cualquier cosa dentro del sandbox
--networkEnviar todo lo que pueda leer a cualquier sitio, sin restricción de tráfico. El valor por defecto permite solo el host de la API de un agente conocido y, en Linux, los registries de paquetes; --allow-host es la alternativa más estricta.
--allow-hostAlcanzar exactamente los hosts que listas, y sus subdominios, por TCP a través de un proxy integrado. Cada host de la lista es de confianza por completo. Tu lista se suma al host de la propia API del agente; --no-network con una lista te deja solo esa lista.
--forward-portUsar por completo un servicio del loopback de tu host. Lo que acepte el servidor MCP, el socket del editor o la base de datos en ese puerto, el agente puede pedirlo, sin lista de permitidos, sin inspección y sin registro de auditoría. Todos los demás puertos del host siguen cerrados. Solo Linux, y se rechaza con --network.
--toolchainsActivado por defecto en Linux. Ejecutar tus toolchains: ~/.cargo/bin y ~/.rustup en solo lectura, una caché de dependencias propia de la jaula en ~/.local/share/ai-jail/cache/ que sobrevive entre ejecuciones, y salida filtrada hacia los registries de paquetes. Las cachés reales del host nunca se montan. Apagado bajo --lockdown y con --no-toolchains.
--secretNada nuevo. El valor real de esa clave nunca entra al sandbox: el agente ve un marcador de posición, y el proxy pone el valor real solo en las peticiones HTTP plano al único host al que la vinculaste. El propio proceso de ai-jail ve esa petición en claro.
--audit-logNada nuevo. Este interruptor no debilita nada: escribe una línea por arranque en un archivo con modo 0600 fuera del sandbox, así que el agente nunca lo ve.
--dockerActuar como root en tu máquina a través del daemon de Docker.
--kvmAbrir /dev/kvm, la interfaz de virtualización del kernel, para que QEMU, Firecracker o el emulador de Android corran a velocidad de hardware. Solo en Linux. Los guests solo tienen la red del sandbox, y no se pasa ningún /dev/net/tun.
--x11Registrar pulsaciones de teclas y tomar capturas de otras ventanas de X11.
--systemd-userPedirle a tu gestor de usuario de systemd que ejecute servicios en el host.
--inherit-envLeer todo el entorno de tu shell, secretos incluidos. Para las claves de API, --env-from-file pasa un solo archivo en su lugar.
--agent-stateActivado por defecto. Usar el login guardado del agente, por ejemplo el ~/.claude de Claude o los ~/.local/share/devin y ~/.config/devin de Devin, montados en lectura y escritura, más su clave de API copiada de tu shell si está definida, para que arranque con la sesión iniciada. Cualquier cosa dentro del sandbox puede usar esas credenciales mientras dure el arranque. --no-agent-state da una ejecución aislada y sin sesión; apagado bajo --lockdown.
--githubActuar como tú en GitHub. El directorio de configuración de gh se monta en solo lectura, y el token activo de github.com se lee de tu llavero en el host y se reenvía como GH_TOKEN para ese arranque, nunca por la línea de comandos ni por disco. La solo lectura protege el archivo; el token sigue funcionando mientras sea válido.
--awsActuar como tú en AWS con ~/.aws, montado en solo lectura.
--kubeActuar como tú en todos los clústeres de ~/.kube, montado en solo lectura.
--gcloudActuar como tú en Google Cloud con ~/.config/gcloud, montado en solo lectura.
--docker-configUsar tus logins de registries de contenedores en ~/.docker/config.json, montado en solo lectura.
--audioGrabar y reproducir audio mientras esté activado.
--no-private-homeVer tu directorio home real. Es una excepción amplia; mejor mapea la única ruta que necesitas.

Ante la duda, se niega a arrancar

Un sandbox que arranca en silencio más débil de lo que pediste es peor que uno que se detiene con un error. En estos casos ai-jail se detiene.

  • Un archivo de configuración que existe y es inválido o ilegible.
  • Un .ai-jail de proyecto que es un symlink. Un ~/.ai-jail global que es un symlink se sigue solo hasta un archivo regular del que eres dueño, que nadie más puede escribir y que está fuera del proyecto.
  • --lockdown cuando Landlock, las reglas de sistema de archivos del propio kernel, falta, es parcial o no se puede aplicar. --lockdown --no-landlock también se rechaza.
  • --allow-tcp-port. Esa interfaz no puede restringir UDP, así que el flag se acepta por compatibilidad, el arranque falla y el error apunta a --allow-host.
  • --network junto con --allow-host, o --browser con --allow-host. Los dos se contradicen, así que ai-jail se niega a arrancar.
  • --forward-port junto con --network, donde el loopback del host ya está al alcance; fuera de Linux; y para el puerto 0 o un puerto por debajo de 1024, que el sandbox no puede enlazar. Una entrada forward_ports en la tabla base del archivo global tropieza con las dos primeras en cada arranque con navegador y en cada arranque en macOS.
  • Un archivo de --env-from-file que es un symlink, que puede leer su grupo o todo el mundo, que pertenece a otra persona o que está dentro del proyecto.
  • Un BWRAP_BIN que apunta a un binario de bubblewrap que alguien distinto de root pudo haber reemplazado. Se ignora con una advertencia, y sin un bubblewrap de confianza el arranque falla.
  • Un overlay que no se puede montar: falta el origen, el destino se solapa con otro mapeo o falla el almacenamiento. Desde la 2.4 el arranque aborta en vez de caer a un bind simple de lectura y escritura sobre los archivos reales.

Cómo se revisa el proyecto

Un solo mantenedor lleva el proyecto de forma abierta. Abajo está lo que se revisa y lo que no.

23
tests de integración de escape del sandbox que intentan escribir en /usr, leer ~/.ssh, llamar a ptrace y bpf, y esperan fallar
959
tests unitarios en el código fuente en la versión 2.9.0
0
peticiones de red al arrancar. La comprobación de actualizaciones es opt-in con --update-check

Correcciones de seguridad recientes

  • 2.9.0: --x11 por sí solo deja pasar X11. Antes, sin --display no hacía nada, en silencio.
  • 2.9.0: el guardado automático ya no escribe en el archivo de proyecto opt-ins que la carga no confiable rechaza después, así que un archivo guardado nunca avisa en la siguiente ejecución.
  • 2.9.0: macOS: Codex vuelve a arrancar bajo Seatbelt con un ps shim privado en lugar del ps setuid del host.
  • 2.8.0: macOS: el perfil de seatbelt conserva el login de Claude Code en el Keychain y permite el socket de control de Codex, así que ambos arrancan con la sesión iniciada.
  • 2.8.0: las peticiones de posición del cursor de un lanzador las responde la terminal virtual, así que los lanzadores ya no se quedan colgados.
  • 2.6.2: --lockdown siempre aísla el namespace de red, incluso con --network. Antes, ese par contradictorio dejaba el namespace compartido.
  • 2.6.2: los valores de --env y --env-from-file ya no van en la línea de comandos del lanzador, donde cualquier proceso que corra como tú podía leerlos. Pasan por un archivo en memoria.
  • 2.4.0: los metadatos de worktree de un repositorio ya no pueden montar un directorio cualquiera del host en lectura y escritura.
  • 2.4.0: una entrada duplicada en el entorno ya no cuela el valor real de una clave --secret dentro del sandbox.
  • 2.4.0: un comando de navegador en un .ai-jail de proyecto no confiable ya no desactiva el lockdown.
  • 2.4.0: TIOCSTI se compara como lo lee el kernel, en 32 bits, así que una variante con el bit alto ya no pasa el seccomp.
  • 2.4.0: Landlock valla los sockets Unix abstractos y las señales en kernels 6.12 o más nuevos.
  • 2.4.0: macOS: el acceso al terminal se limita a los terminales de la propia ejecución, y no a todos los /dev/ttys*.
  • 2.4.0: macOS: las rutas con --mask se deniegan también para escritura, además de lectura.
  • 2.4.0: el filtro de salida ya no se descompone con un ESC doble, que podía colar una escritura en el portapapeles.
  • 2.4.0: los atajos de prueba del proxy quedan fuera de los builds de release.

Cómo se hace una versión

  • Los tags de versión están firmados, y CI verifica cada uno contra una huella de clave fijada en el repositorio.
  • Cada GitHub Action está fijada a un SHA de commit, y las actions están restringidas a una lista de permitidos.
  • Las compilaciones usan una toolchain de Rust fijada y dependencias con --locked.
  • Los binarios de macOS están firmados y notarizados por Apple.
  • Cada archivo comprimido viene con un checksum SHA-256, y el job de publicación los vuelve a comprobar.

Lo que el documento de versiones dice que todavía falta

  • Los secretos de firma y publicación todavía se guardan a nivel de repositorio y deberían pasar a los entornos de publicación.
  • Todavía ningún ruleset obliga a que cada tag v* esté firmado.
  • Las versiones inmutables (immutable releases) no están activadas.
  • La publicación en crates.io todavía usa un token. El trusted publishing está planeado.
  • Con un solo mantenedor no hay un segundo revisor para los cambios ni para las versiones.

Leer RELEASE_SECURITY.md

Reportar una vulnerabilidad

No abras un issue público. Usa el reporte privado de vulnerabilidades de GitHub, incluye los pasos para reproducirla y las versiones afectadas, y da tiempo para coordinar una corrección.

Preguntas frecuentes

¿El agente puede escaparse?
Los valores por defecto están hechos y probados para bloquear las rutas habituales de un agente que se equivoca: archivos, entorno, red e IPC del host. No están hechos para resistir a un atacante decidido: algo que intente escapar a propósito podría usar un bug del kernel, de un driver, de la terminal o del backend del sandbox, y por eso el código hostil va en una VM desechable.
¿Es seguro ejecutarlo con la red activada?
Es más seguro que ejecutar el agente sin jaula, porque tus claves y tu directorio home siguen sin estar ahí para enviarlos. Con --network, todo lo que el agente puede leer, lo puede enviar, y ai-jail no está hecho para impedir que un atacante decidido lo haga. El punto medio es --allow-host: el agente llega solo a los hosts que listas, y cada uno es de confianza por completo. Enmascara primero los secretos dentro del proyecto. Mira cómo enmascararlos.
¿Ha sido auditado?
A la vista de todos: el proyecto se auditó a sí mismo antes de la 1.0, y en septiembre de 2026 se publicaron en el repositorio dos auditorías de código independientes de la 2.3.0; la 2.4.0 cerró los dos advisories que produjeron. Ninguna empresa externa lo ha auditado. El código es abierto bajo GPL 3.0, y los reportes privados de vulnerabilidades son bienvenidos.

Pon a tu agente tras las rejas

ai-jail es un único binario que no necesita daemon ni root. Añades una palabra delante del comando que ya usas.

terminal
brew tap akitaonrails/tap && brew install ai-jailai-jail claude