⚠️ Por Que Segurança é Obrigatória
Um agente de IA com acesso a shell, sistema de arquivos e rede não é um chatbot inofensivo — é um programa que pode causar danos irreversíveis. O LLM pode alucinar um comando destrutivo, ser manipulado por prompt injection ou simplesmente interpretar mal uma instrução. Segurança não é feature opcional — é pré-requisito.
Os 5 Riscos Reais de um Agente Sem Proteção
rm -rf /: o agente pode executar comandos destrutivos que apagam dados ou o sistema inteiro
Exfiltração de dados: curl/wget podem enviar arquivos sensíveis para servidores externos
Instalação de malware: download e execução de scripts não verificados da internet
Exposição de credenciais: cat ~/.ssh/id_rsa, leitura de .env, tokens de API nos logs
Loop infinito: o agente pode entrar em loop consumindo CPU, disco e tokens sem limites
🚨 Alerta: Nunca Rode Sem Proteção
O Claude Code, mesmo com todas as suas camadas de segurança, já teve incidentes reportados. Um agente caseiro sem proteção é uma bomba-relógio. Implemente TODAS as camadas deste módulo antes de dar acesso real ao shell. Comece em sandbox isolada e vá liberando gradualmente.
🏰 Sandbox com subprocess
A primeira linha de defesa é isolar a execução. Em vez de rodar comandos no mesmo processo e ambiente do agente, usamos subprocess.run com ambiente limpo, diretório restrito, timeout e captura de output. Se o comando explodir, o agente sobrevive.
Execução Isolada com subprocess
def safe_shell(command, timeout=30, cwd='/tmp/agent-sandbox'):
env = {k: v for k, v in os.environ.items()
if k in ['PATH', 'HOME', 'LANG']}
result = subprocess.run(
command, shell=True,
capture_output=True, text=True,
timeout=timeout, cwd=cwd, env=env
)
output = result.stdout + result.stderr
return output[:10000] # truncate huge outputs
Ambiente limpo: só passa PATH, HOME e LANG — sem tokens, secrets ou configs sensíveis
Diretório isolado: roda em /tmp/agent-sandbox, não no diretório do usuário
Timeout: 30 segundos por padrão — mata processos que travam ou fazem loop
Truncamento: limita output a 10K chars — evita que logs enormes consumam toda a context window
💡 Docker para Sandbox Robusta
Para isolamento real, considere rodar comandos dentro de um container Docker descartável. O subprocess é a base, mas não impede acesso a rede ou filesystem fora do cwd. Com Docker, você controla CPU, memória, rede e filesystem. O Claude Code usa containerd internamente para suas operações mais sensíveis.
🔐 Sistema allow/deny/ask
Nem toda ferramenta precisa do mesmo nível de controle. Leitura de arquivos é segura — pode rodar sem perguntar. Escrita e execução de shell são perigosas — devem pedir confirmação. Algumas operações são proibidas sempre. O sistema allow/deny/ask do Claude Code implementa exatamente essa gradação.
Controller de Permissões
# permissions.json
{"read_file": "allow", "write_file": "ask",
"run_shell": "ask", "search_in_files": "allow"}
class PermissionController:
def check(self, tool_name: str) -> str:
rule = self.rules.get(tool_name, 'ask')
if rule == 'allow': return 'granted'
if rule == 'deny': return 'denied'
# ask = prompt user
answer = input(f"Allow {tool_name}? [y/n]: ")
return 'granted' if answer.lower() == 'y' else 'denied'
allow: executa sem perguntar — para operações seguras como leitura e busca
deny: bloqueia sempre — para operações proibidas por política
ask: pede confirmação ao usuário — o padrão para operações desconhecidas
Default = ask: se uma ferramenta não está na lista, assume que precisa de confirmação
📊 Como o Claude Code Implementa Permissões
settings.json: regras globais e por projeto definidas pelo usuário
Regex matching: regras podem usar padrões — ex: allow: Bash(git *) permite qualquer comando git
"Remember" option: quando o usuário aprova, pode salvar a decisão para não perguntar de novo
Hierarquia: deny > allow > ask — deny sempre vence, independente de outras regras
🔍 Validação de Comandos
Mesmo com permissão "ask", o usuário pode aprovar algo perigoso sem perceber. A validação de comandos é uma camada adicional que analisa o conteúdo do comando antes da execução e bloqueia padrões conhecidamente destrutivos — independente da permissão concedida.
Blocklist de Padrões Perigosos
DANGEROUS_PATTERNS = [
r'rm\s+-rf\s+/', r'dd\s+if=', r'mkfs', r':\(\)\{',
r'curl.*\|\s*sh', r'wget.*\|\s*bash', r'chmod\s+777',
r'>\s*/dev/sd', r'shutdown', r'reboot'
]
def validate_command(command):
for pattern in DANGEROUS_PATTERNS:
if re.search(pattern, command):
return False, f"BLOCKED: matches {pattern}"
return True, "OK"
Regex matching: cada padrão usa expressão regular para detectar variações do comando
Fork bomb: :(){ :|:& };: é detectado pelo padrão :\(\)\{
Pipe para shell: curl | sh e wget | bash são vetores clássicos de RCE
Extensível: adicione padrões específicos do seu contexto (ex: DROP TABLE, git push -f)
🚨 O Claude Code Tem 23+ Verificações
Os 10 padrões acima são apenas o começo. O Claude Code implementa mais de 23 verificações de segurança, incluindo detecção de escalação de privilégio, acesso a diretórios sensíveis (/etc, /root, ~/.ssh), manipulação de git history e muito mais. Trate essa lista como ponto de partida — seu agente precisará de verificações específicas para o domínio em que atua.
⏱️ Limites de Recursos
Segurança não é só sobre comandos perigosos — é também sobre consumo descontrolado. Um agente pode entrar em loop infinito, gerar outputs gigantes, ler arquivos enormes ou consumir todo o orçamento de tokens em uma sessão. Limites de recursos previnem esses cenários.
Constantes de Proteção
MAX_ITERATIONS = 30
TOOL_TIMEOUT = 60 # seconds
MAX_OUTPUT_SIZE = 10000 # chars
MAX_FILE_SIZE = 1_000_000 # 1MB
MAX_ITERATIONS: limite de iterações do loop principal — para o agente mesmo se o LLM nunca disser "pronto"
TOOL_TIMEOUT: cada ferramenta tem um tempo máximo — se exceder, é morta e o erro é reportado
MAX_OUTPUT_SIZE: trunca outputs longos para não poluir a context window
MAX_FILE_SIZE: recusa ler/escrever arquivos maiores que 1MB — evita binários e logs gigantes
💡 Ajuste Conforme o Uso
Esses valores são pontos de partida razoáveis. Para agentes de CI/CD, aumente o TOOL_TIMEOUT para 120s (builds demoram). Para agentes de análise de dados, aumente MAX_FILE_SIZE para 10MB. O importante é que os limites EXISTAM — os valores exatos dependem do seu caso de uso. Sem limites, qualquer bug vira catástrofe.
📝 Auditoria e Logging
A última camada de segurança é a visibilidade. Mesmo com todas as proteções, você precisa saber exatamente o que o agente fez, quando fez e quanto demorou. Logs estruturados permitem auditar sessões, detectar padrões suspeitos e debugar problemas em produção.
Logging Estruturado de Tool Calls
import logging
logger = logging.getLogger('agent')
def log_tool_call(tool_name, args, result, duration):
logger.info(json.dumps({
'timestamp': datetime.now().isoformat(),
'tool': tool_name,
'args': args,
'result_length': len(str(result)),
'duration_ms': int(duration * 1000),
}))
JSON estruturado: cada log é um JSON parseável — facilita busca e análise posterior
Timestamp ISO: permite reconstruir a timeline exata de cada sessão
result_length: loga o tamanho do resultado, não o conteúdo — evita logs gigantes
duration_ms: identifica ferramentas lentas e possíveis gargalos de performance
Fazer
- ✓ Implementar TODAS as camadas: sandbox, permissões, validação, limites e logs
- ✓ Logar toda tool call com timestamp, args e duração
- ✓ Testar com comandos maliciosos intencionalmente antes de liberar
- ✓ Revisar logs regularmente para detectar padrões anômalos
Evitar
- ✗ Confiar que o LLM "nunca faria algo perigoso" — alucinações acontecem
- ✗ Logar credenciais, tokens ou conteúdo de arquivos sensíveis
- ✗ Desabilitar segurança para "ir mais rápido" em desenvolvimento
- ✗ Rodar o agente com permissões de root ou admin
📋 Resumo do Módulo
Próxima Trilha:
Trilha 6 - 🏠 Rodando Local — LLMs no seu hardware com Ollama e modelos open-source