MÓDULO 5.4

🛡️ Segurança e Permissões

Um agente com acesso ao terminal pode causar danos reais. Implemente sandbox, validação de comandos, sistema de permissões e auditoria para manter seu agente seguro e controlável.

6
Tópicos
30
Minutos
Intermediário
Nível
Prática
Tipo
1

⚠️ 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.

Diagrama do sistema de segurança em camadas
O sistema de segurança atua em múltiplas camadas — da validação de input à auditoria de output.

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.

2

🏰 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.

3

🔐 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

4

🔍 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.

5

⏱️ 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.

6

📝 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

Segurança é obrigatória — um agente sem proteção pode causar danos irreversíveis
Sandbox com subprocess isola execução com ambiente limpo, timeout e diretório restrito
Sistema allow/deny/ask gradua o controle por ferramenta — default é "ask"
Validação de comandos bloqueia padrões perigosos via regex antes da execução
Limites de recursos previnem loops infinitos, outputs gigantes e consumo descontrolado
Auditoria com logging estruturado permite reconstruir e analisar cada sessão

Próxima Trilha:

Trilha 6 - 🏠 Rodando Local — LLMs no seu hardware com Ollama e modelos open-source