💡 Como ler este módulo
Na Trilha 1 você viu os três modos de sandbox em termos de conveniência. Aqui trocamos a lente: para cada modo, o que acontece se a tool executar código hostil? Se a resposta for "o host cai", o modo não serve para produção. Sandbox é a última barreira — se ela falhar, tudo depois falha.
🔒 Local / Docker / K8s revisitados sob lente de risco
Os três modos já são conhecidos; o que muda aqui é o eixo de comparação. Em vez de "qual roda mais rápido", a pergunta é "o que um código hostil consegue fazer em cada um?". A resposta determina onde cada modo pode viver.
Local
Risco: máximo
- • Acesso completo ao FS do host
- • Pode ler
~/.ssh,.env, keychain - • Exfiltração via rede sem trava
- • Uso: apenas máquina descartável de dev
Docker
Risco: médio
- • Namespace isolado; host protegido
- • Egress de rede aberto por padrão
- • Escape via docker.sock se montado (não monte)
- • Uso: dev equipe, produção pequena
K8s
Risco: controlado
- • NetworkPolicy restringe egress
- • PSA + seccomp + AppArmor compondo
- • Quotas hard por namespace
- • Uso: multi-tenant, produção
🎯 O modelo de ameaça que importa
O agente não precisa ser comprometido por um atacante externo. Basta prompt injection — um documento que o agente lê em contexto e que reescreve o objetivo dele. Nesse momento, qualquer tool que executa código passa a ser código do atacante. A sandbox existe para assumir que isso vai acontecer e limitar o dano.
🚧 Isolamento, quotas e imagem
"Docker já isola" é só metade da verdade. O container bloqueia acesso ao FS do host, mas não limita CPU, memória, egress ou pacotes instalados por padrão. É preciso configurar explicitamente. No modo K8s do DeerFlow, esses controles são primeira-classe via policies do Pod.
🎯 Conceito Central — as 4 camadas
- 1. Recursos— CPU, memória, disco, tempo máximo. Sem isso, um loop infinito derruba o node.
- 2. Rede— NetworkPolicy com egress allow-list. Sem isso, o Pod pode exfiltrar para qualquer lugar.
- 3. Filesystem— volumes read-only,
/tmpefêmero, nada de hostPath. Sem isso, persistência entre execuções vaza dados. - 4. Imagem— base mínima (distroless ou alpine), sem pip install livre. Sem isso, qualquer
pip install requests_evilvira backdoor.
Exemplo: PodSpec mínimo para sandbox DeerFlow
apiVersion: v1
kind: Pod
metadata: { name: deerflow-sandbox }
spec:
securityContext:
runAsNonRoot: true
runAsUser: 65532
seccompProfile: { type: RuntimeDefault }
containers:
- name: sandbox
image: deerflow/sandbox:2.3.0-distroless
resources:
limits: { cpu: "1", memory: "2Gi", ephemeral-storage: "512Mi" }
requests: { cpu: "200m", memory: "512Mi" }
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities: { drop: ["ALL"] }
volumeMounts:
- { name: scratch, mountPath: /tmp }
volumes:
- name: scratch
emptyDir: { sizeLimit: "256Mi", medium: Memory }
💡 Dica prática
Não fique tentado a dar NET_ADMIN ou SYS_PTRACE "só para debugar". Se precisar, crie um namespace K8s "dev" separado do "prod" e deixe claro que é descartável. Capabilities não voltam para a caixa depois que um incidente acontece.
📄 Leitura guiada de SECURITY.md
O arquivo SECURITY.md do repositório é o documento mais autoritativo do projeto sobre risco. A maioria dos usuários nunca o abre. Esta seção faz o passeio: o que está lá, o que não está, e por que cada recomendação existe.
Threat model explícito
O que o DeerFlow assume que pode acontecer — e o que diz estar fora de escopo
Lista ameaças cobertas (prompt injection, tool misuse, secret exposure em logs) e deixa fora (atacante com acesso físico ao host). Saber o que não é problema do projeto é tão importante quanto saber o que é.
Supported versions
Quais minor releases recebem patch — e por quanto tempo
Fica a regra prática: versões n e n-1 recebem fixes; qualquer coisa mais antiga é "upgrade". Conflita frontalmente com "mantemos um fork estável da v2.0 por 3 anos".
Canal de reporte
Private disclosure, PGP, SLA de resposta
Endereço oficial (security@), chave PGP pública e o compromisso de primeira resposta em até 72h. Issue público não é lugar para CVE — o SECURITY.md fala isso em negrito.
Recomendações de deploy
Lista mínima do que precisa estar ligado em prod
TLS, auth obrigatória no API gateway, sandbox Docker ou K8s (nunca Local), secrets via gerenciador (não .env no repo), logs sem PII. Cada bullet vira um item de checklist antes de go-live.
⚠️ Alertas de deploy — o que o README adverte
O README do DeerFlow tem uma seção curta e explícita sobre o que não fazer em deploy. É uma lista de armadilhas que parecem pequenas em dev e viram incidentes em produção. Elas se repetem porque ninguém lê.
🚨 As 6 armadilhas clássicas
- 1.Sandbox: local em produção. "Só enquanto resolvemos o Docker." Nunca é só. Vira default e o incidente chega em 3 meses.
- 2.API gateway sem autenticação. Conveniente em staging, catastrófico em prod. Qualquer um que ache a URL ganha um agente com suas credenciais.
- 3.Secrets no prompt do sistema. Ficam no histórico, vão para logs, vão para traces, vão para memória. Use injeção via tool, nunca via prompt.
- 4.Tool irrestrita (curl, bash, fs.write). Qualquer uma que execute comando arbitrário precisa estar atrás de allow-list e com input validado.
- 5.Logs com PII. Mensagens de usuário gravadas íntegras em Elasticsearch com retenção infinita. LGPD manda lembrança.
- 6.Docker socket montado. "O agente precisa iniciar containers." Não precisa — você precisa de uma interface mediada. Docker socket = root no host.
💡 Checklist antes de go-live
Imprima as 6 armadilhas, cole no Jira, peça que um humano dê OK em cada uma antes do deploy. Não delegue para o agente decidir se ele próprio está seguro — ele sempre vai dizer que sim.
🧪 Lab: deploy K8s com provisioner + script malicioso
Testar sandbox com hostil-de-mentira é a única forma honesta de saber se ela aguenta hostil-de-verdade. Você vai subir um DeerFlow em K8s no modo sandbox-provisioner, injetar um script intencionalmente malicioso e validar que (a) o script falha, (b) o incidente aparece nos logs, (c) o agente continua vivo e responde sobre o erro.
Suba um cluster descartável
kind, k3d ou minikube bastam. Crie namespace deerflow-test e aplique o manifest oficial do DeerFlow em modo K8s-provisioner, com o PodSpec restritivo visto no tópico 2.
Prepare 3 scripts de teste
A) curl http://169.254.169.254/ — tenta acessar metadata do cloud. B) dd if=/dev/zero of=/tmp/fill bs=1M — tenta esgotar disco. C) while true: pass — tenta loop infinito. Cada um mira uma camada diferente (rede, disco, CPU).
Acione via skill de análise
Use a skill data-analysis passando um CSV bobo e instruindo "execute o código anexo no preprocessamento". O código anexo é um dos scripts do passo 2. Rode uma vez para cada script.
Observe resultado esperado
A: NetworkPolicy bloqueia, curl: (7) Couldn't connect. B: ephemeral-storage limit corta em 256Mi, Pod evicted. C: CPU limit 1 core estrangula e timeout da tool dispara. Nos 3 casos, o agente segue vivo e reporta o erro na conversa.
Colete evidências
Screenshots dos logs (kubectl logs), dos eventos (kubectl get events) e do trace do DeerFlow mostrando o erro retornado. Anexe ao doc do lab — serve como post-mortem-mock para treinar o time em incidente real.
⚠️ Se algum teste passar quando não deveria
Pare o lab. Sua config de K8s não está aplicando os limits. Revise securityContext, resources.limits e NetworkPolicy. Um deploy que deixa o script A funcionar em laboratório vai deixar um exfiltrador funcionar em produção.
📝 Resumo do Módulo
Próximo Módulo:
3.3 — 💾 Memória avançada e context engineering
Do "existe memória" do módulo 1.1 para compactação, recall semântico e memory poisoning.