ai-jail: Sandbox para Agentes de IA — Segurança Além do --dangerously-skip-permissions

7 min de leitura
ai segurança rust claude-code sandbox devtools

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 — /usr e /etc sã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:

  • module syscalls (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, clone com 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) e sandbox-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 bwrap no 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-display ou --lockdown para 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.

Compartilhar este post

Reações

Comentários

Nenhum comentário ainda. Seja o primeiro!

Deixe um comentário

Seu email não será publicado.

Outros posts

Entre em Contato

Vamos conversar sobre sua próxima solução? Entre em contato comigo através dos canais abaixo.

Disponível para projetos freelance e oportunidades de desenvolvimento