ai-jail: Sandbox para Agentes de IA — Segurança Além do --dangerously-skip-permissions
Agentes de IA como Claude Code, OpenCode e Crush trouxeram uma nova forma de programar: você descreve o que quer, e o agente executa comandos no terminal, edita arquivos, instala dependências, roda testes. Mas isso também abre um vetor de risco óbvio — você está dando acesso ao seu sistema para um modelo de linguagem que pode cometer erros ou, em cenários extremos, ser manipulado por prompts maliciosos.
O ai-jail é uma ferramenta que ataca esse problema de frente: um sandbox multi-plataforma (Linux e macOS) que envolve o agente em camadas de isolamento, controlando exatamente o que ele pode ver, ler, escrever e executar.
O Problema
Quando você roda claude ou opencode no terminal, o agente tem acesso a:
- Todo o seu sistema de arquivos (
/home,/etc,/usr) - Suas chaves SSH, tokens de API, credenciais
- Variáveis de ambiente com secrets
- Rede (acesso a servidores internos e externos)
- GPU, Docker socket, display server
Por padrão, o Claude Code tem um sistema de permissões embutido — ele pergunta antes de executar comandos ou editar arquivos. Mas é um sistema opt-in que depende do usuário dizer "sim" ou "não" para cada ação. Cansaço, distração ou pressa transformam esse "sim" em automático.
O ai-jail resolve isso na camada do sistema operacional: em vez de pedir permissão, ele simplesmente impede o acesso. Se o agente tentar ler ~/.ssh/id_rsa, o sandbox retorna um arquivo vazio. Se tentar fazer bind numa porta, o seccomp bloqueia a syscall.
Como Funciona
O ai-jail é um wrapper em Rust. Você o usa no lugar do comando original:
ai-jail claude # Roda Claude Code no sandbox
ai-jail opencode # Roda OpenCode no sandbox
ai-jail bash # Apenas um shell restrito (debug)
Na primeira execução, ele cria um arquivo .ai-jail no diretório do projeto com a configuração. Esse arquivo pode ser commitado no repositório para que todo mundo use as mesmas regras.
Por baixo dos panos, o ai-jail usa:
- Linux:
bubblewrap(bwrap) — isolamento por namespaces (mount, PID, UTS, IPC) em userspace - macOS:
sandbox-exec— interface legada de políticas seatbelt da Apple
E sobrepõe camadas adicionais de segurança independentes do backend.
Camadas de Defesa (Linux)
O isolamento no Linux é construído em múltiplas camadas independentes. Cada uma pode ser desabilitada individualmente se causar problemas com alguma ferramenta específica.
1. Namespace Isolation (bwrap)
O bwrap cria namespaces separados para o processo do agente:
- Mount namespace: o sistema de arquivos visto pelo agente é uma composição controlada —
/usre/etcsão read-only,/tmpé tmpfs fresco,$HOMEé tmpfs com dotdirs selecionados montados por cima - PID namespace: o agente não vê outros processos do host
- UTS namespace: hostname isolado (
ai-sandbox) - IPC namespace: sem acesso a semáforos/shared memory do host
- Network namespace: no lockdown, a rede é completamente isolada (
--unshare-net)
2. Landlock LSM
Landlock é um módulo de segurança Linux (disponível desde 5.13) que permite a processos em userspace definirem políticas de acesso a arquivos e rede no nível VFS. É uma camada de defesa adicional independente dos namespaces de mount:
- ABI V3 (Linux 6.2+): regras de sistema de arquivos com best-effort para V1 em kernels mais antigos
- ABI V4 (Linux 6.5+): restrições de rede — em lockdown, nega TCP bind/connect em portas não explicitamente permitidas via
--allow-tcp-port - Age como seguro contra bugs de namespace e ataques de symlink dentro de mounts permitidos
- Desabilitável com
--no-landlock
3. Seccomp-bpf
O filtro de syscalls bloqueia aproximadamente 30 chamadas de sistema perigosas:
modulesyscalls (insmod, init_module — impedem carregamento de kernel modules)ptrace(impede depuração e injeção em outros processos)bpf(impede manipulação de eBPF)- Syscalls de escape de namespace (
setns,unshare,clonecom flags específicas) reboot,swapon,mount(em lockdown)
Em lockdown, bloqueios adicionais atingem syscalls NUMA e de hostname.
4. Resource Limits
Limites de recursos previnem ataques de negação de serviço dentro do sandbox:
RLIMIT_NPROC: 4096 processos (1024 em lockdown)RLIMIT_NOFILE: 65536 file descriptors (4096 em lockdown)RLIMIT_CORE: 0 (sem core dumps)
5. Sensitive /sys Masking
O diretório /sys do host expõe informações sensíveis sobre hardware e kernel. O ai-jail monta tmpfs sobre:
/sys/firmware/sys/kernel/security/sys/kernel/debug/sys/fs/fuse
Em lockdown, também mascara /sys/module, /sys/devices/virtual/dmi e /sys/class/net.
Gerenciamento de $HOME
Uma das decisões de design mais interessantes do ai-jail é como ele trata o diretório home. Em vez de montar o $HOME real do usuário, ele cria um tmpfs e monta seletivamente dotdirs específicos:
Nunca montados (dados sensíveis):
.gnupg, .aws, .ssh, .mozilla
Montados read-write (ferramentas e caches):
.claude, .crush, .codex, .opencode, .cargo, .cache, .config
Montados read-only:
~/.gitconfig
O resto do $HOME fica simplesmente invisível para o agente.
Para workloads onde você não quer expor nenhum dotdir do host, use --private-home. O projeto fica writable, mas o home é tmpfs limpo — útil para experimentos onde você não quer compartilhar histórico do Claude ou configurações pessoais.
Lockdown Mode
Para workloads potencialmente hostis ou não-confiáveis, o modo --lockdown ativa restrições máximas:
ai-jail --lockdown claude
O que muda:
- Projeto montado read-only
- GPU, Docker, display desabilitados
- $HOME é tmpfs limpo (sem dotdirs do host)
- --clearenv com allowlist mínima de variáveis
- Rede isolada (--unshare-net) — a menos que --allow-tcp-port seja usado com Landlock V4
- --new-session para isolamento de sessão
- Ignora --rw-map e --map (nada de mounts adicionais)
É o equivalente a "se esse agente for comprometido, o dano máximo é perder os arquivos do projeto — e olhe lá".
Browser Profiles
Uma funcionalidade inesperada mas muito útil: o ai-jail consegue rodar navegadores em perfis isolados. Isso é útil quando o agente precisa testar algo no browser ou quando você quer navegar num site suspeito sem expor seu perfil real.
ai-jail chromium # Perfil hard (efêmero)
ai-jail --browser=soft firefox # Perfil soft (persistente entre sessões)
- Hard: cache, cookies, histórico, extensões — tudo em tmpfs, desaparece quando o browser fecha
- Soft: estado salvo em
~/.local/share/ai-jail/browsers/<browser>, sem tocar no perfil real do Firefox/Chromium
O perfil hard é ativado automaticamente para Chrome, Chromium, Brave, Firefox e LibreWolf. Dá para desabilitar com --no-browser.
ai-jail vs Claude Code Sandbox Nativo
O Claude Code tem um sistema de permissões próprio (--dangerously-skip-permissions existe porque o padrão é com permissões). Mas ele opera no nível da aplicação: o Claude Code pergunta "posso executar esse comando?" e o usuário decide.
O ai-jail opera no nível do kernel. Não importa o que o Claude Code "acha" que vai fazer — o sistema operacional simplesmente não deixa. É uma diferença fundamental:
- Claude Code sandbox: permissão por ação, depende do usuário
- ai-jail: política declarativa, independe do agente
Os dois são complementares. O ideal é usar o Claude Code dentro do ai-jail: você tem a camada de perguntas do Claude Code mais o isolamento de SO do ai-jail.
ai-jail vs Dev Containers
Dev Containers (VSCode + Docker) também isolam o ambiente de desenvolvimento, mas com propósitos diferentes:
- Dev Containers: reproduzibilidade de ambiente (todo mundo usa a mesma imagem)
- ai-jail: contenção de danos (limitar o que um agente de IA pode fazer)
Dá para usar os dois juntos: rode o Dev Container normalmente, e dentro dele execute o agente com ai-jail. O container isola do host, o ai-jail isola o agente dentro do container.
Exemplos de Uso
Instalação
# Via Homebrew
brew tap akitaonrails/tap && brew install ai-jail
# Via cargo
cargo install ai-jail
# Pré-compilado (Linux x86_64)
curl -fsSL https://github.com/akitaonrails/ai-jail/releases/latest/download/ai-jail-linux-x86_64.tar.gz | tar xz
sudo mv ai-jail /usr/local/bin/
Dependência: bubblewrap no Linux (apt install bubblewrap).
Uso Básico
# Rodar Claude Code no sandbox
cd ~/projetos/meu-app
ai-jail claude
# Ver o que seria executado (dry-run)
ai-jail --dry-run claude
# Compartilhar diretório adicional read-only
ai-jail --map /opt/datasets claude
# Esconder arquivos sensíveis do agente
ai-jail --mask .env --mask credentials.json claude
# Rodar com perfil SSH (forward de agent + chaves read-only)
ai-jail --ssh claude
# Isolamento completo para código não-confiável
ai-jail --lockdown claude
# Manter estado do browser entre sessões
ai-jail --browser=soft firefox
Configuração Persistente (.ai-jail)
command = ["claude"]
rw_maps = ["/home/user/Projects/shared-lib"]
mask = [".env", "credentials.json"]
no_gpu = true
ssh = true
Commit o .ai-jail no repositório e todo mundo que rodar ai-jail ali dentro usa as mesmas regras.
Limitações
O próprio autor é transparente sobre o que o ai-jail não é:
- Não é isolamento de hardware. Depende de
bwrap(Linux) esandbox-exec(macOS), que operam no nível de processo. Um exploit no kernel pode escapar. Para isolamento total, use uma VM. - No macOS,
sandbox-execé uma interface legada e pode ser removida pela Apple no futuro. - Windows não é suportado (e provavelmente nunca será, pelos mesmos motivos — não há equivalente userspace ao
bwrapno Windows). Use WSL 2. - Por padrão, o modo normal prioriza usabilidade sobre lockdown máximo. Docker socket, GPU e display são passados automaticamente se detectados. Use
--no-docker,--no-gpu,--no-displayou--lockdownpara restringir.
O Ecossistema
O ai-jail foi criado por Fabio Akita e o post original detalha a evolução de um shell script de algumas linhas para uma ferramenta Rust com 4k+ linhas, testes, CI/CD e distribuição em múltiplos formatos (Homebrew, cargo, mise, Nix, GitHub Releases).
Ele nasceu da necessidade prática de rodar agentes de IA em projetos reais sem sustos. O código é aberto (GPL-3.0) e está no GitHub.
Conclusão
Agentes de IA são ferramentas poderosas, mas o modelo de "dê acesso total ao terminal e confie no modelo" é insustentável em produção. O ai-jail oferece uma abordagem pragmática: em vez de pedir permissão para cada ação, criar políticas declarativas de acesso que o sistema operacional impõe.
As camadas múltiplas de defesa — namespaces, Landlock, seccomp, resource limits — significam que mesmo que uma camada falhe, as outras ainda estão ativas. É segurança em profundidade para uma era onde o código não é mais escrito apenas por humanos.