Tips & Tricks

7 Casos de Falha de Segurança no Claude Code | Incidentes Reais e Prevenção

Sete incidentes de segurança reais com Claude Code: vazamentos de .env, exclusão de BD em produção, explosão de fatura e mais — com análise de causa raiz e código de prevenção.

“Claude Code é prático, mas dá um certo medo” — esse instinto está correto. Ferramentas poderosas causam acidentes poderosos.

Este artigo cobre sete incidentes de segurança reais que podem acontecer ao desenvolver com Claude Code, explicando por que aconteceram e como preveni-los com código e configurações concretos. Aprenda com os erros dos outros antes que se tornem os seus.

Caso 1: Arquivo .env Enviado para o GitHub

O que aconteceu

Um desenvolvedor deu ao Claude Code a seguinte instrução: “Quero passar variáveis de ambiente para o CI, por favor faça commit do arquivo .env também.” O Claude Code executou fielmente git add .env && git commit. Minutos após o push para o GitHub, um crawler detectou a chave de API. Uma notificação chegou no Slack: “Your API key has been exposed.”

Causa raiz

  • .env não estava no .gitignore
  • Claude Code executa instruções de “faça commit disso” literalmente
  • O usuário aprovou o diálogo de confirmação sem pensar

Código de prevenção

1. Automatizar a configuração de segurança na criação do projeto

# scripts/init-security.sh — executar a cada criação de projeto
#!/bin/bash
cat >> .gitignore << 'EOF'

# === Segurança: Nunca faça commit destes ===
.env
.env.*
.env.local
!.env.example
*.pem
*.key
*-service-account.json
credentials.json
EOF

echo "✓ Padrões de exclusão de segurança adicionados ao .gitignore"
git add .gitignore && git commit -m "security: add .gitignore patterns"

2. Verificar antes do commit com um Hook

.claude/settings.json:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash(git add*)",
        "hooks": [{
          "type": "command",
          "command": "git diff --cached --name-only | grep -E '^\\.env' && echo '🚨 Você está prestes a adicionar um arquivo .env ao stage! Cancele!' && exit 1 || exit 0"
        }]
      }
    ]
  }
}

3. Recuperação se já foi enviado

# Passo 1: Rotacionar a chave de API imediatamente (prioridade máxima)

# Passo 2: Remover completamente do histórico git
git filter-branch --force --index-filter \
  "git rm --cached --ignore-unmatch .env" \
  --prune-empty --tag-name-filter cat -- --all

# Passo 3: Force push para o remoto
git push origin --force --all

# Passo 4: Limpar o cache do GitHub (também entre em contato com o suporte do GitHub)

Caso 2: DROP TABLE Executado no BD de Produção

O que aconteceu

“Esta tabela não é mais usada, por favor delete-a.” O Claude Code gerou e executou DROP TABLE old_users;. O problema: estava conectado à DATABASE_URL de produção. O backup mais recente tinha três dias. Três dias de dados foram perdidos.

Causa raiz

  • O mesmo .env era compartilhado entre desenvolvimento e produção
  • Claude Code não consegue distinguir entre ambientes
  • O usuário estava no modo ask mas clicou “OK” por reflexo

Código de prevenção

1. Separar completamente os arquivos .env por ambiente

.env.development   # ← desenvolvimento local, BD de teste
.env.staging       # ← staging, cópia da produção
.env.production    # ← produção, gerenciado manualmente, nunca compartilhar

2. Incorporar verificação de ambiente nos scripts

// scripts/db-migrate.mjs
const env = process.env.APP_ENV ?? "development";
const dbUrl = process.env.DATABASE_URL ?? "";

if (env === "production") {
  const readline = require("readline").createInterface({
    input: process.stdin, output: process.stdout
  });
  await new Promise((resolve) => {
    readline.question(
      `⚠️  Conectando ao BD de produção (${dbUrl.split("@")[1]}).\nTem certeza que deseja continuar? (digite yes): `,
      (answer) => {
        readline.close();
        if (answer !== "yes") { console.log("Cancelado."); process.exit(0); }
        resolve(undefined);
      }
    );
  });
}

3. Proibir operações em produção no CLAUDE.md

## 🚨 Restrições do Ambiente de Produção

Se DATABASE_URL contiver `prod`, `production` ou `live`:
- Nunca executar DROP / TRUNCATE / DELETE (sem cláusula WHERE)
- Sempre obter confirmação do usuário antes de migrações
- Apresentar comando de backup antes de qualquer operação destrutiva

Caso 3: Arquivos Críticos Deletados com rm -rf

O que aconteceu

“Limpe o diretório build/” — um erro de digitação no caminho resultou em rm -rf ./, deletando o projeto inteiro. Arquivos fora do git (configuração local, código experimental sem commit) foram perdidos para sempre.

Causa raiz

  • rm -rf é um dos comandos mais perigosos para o Claude Code executar
  • Falta de aspas duplas ao redor dos caminhos → mau funcionamento com caminhos contendo espaços
  • O usuário aprovou descuidadamente

Código de prevenção

// .claude/settings.json
{
  "permissions": {
    "deny": [
      "Bash(rm -rf /)",
      "Bash(rm -rf ~*)",
      "Bash(rm -rf .*)"
    ],
    "ask": [
      "Bash(rm -rf*)"
    ]
  }
}

Hook para mostrar o que será deletado antes de executar:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash(rm*)",
        "hooks": [{
          "type": "command",
          "command": "echo '⚠️ Comando de exclusão detectado. Executando em 5 segundos. Ctrl+C para cancelar.' && sleep 5"
        }]
      }
    ]
  }
}

Caso 4: Chave de API Escrita Diretamente no Prompt e Passada ao Subagente

O que aconteceu

“Por favor publique no Qiita usando QIITA_TOKEN=abc123def456” — escrito diretamente no prompt e delegado a um subagente. Subagentes podem escrever conteúdo em logs e memória, e o token acabou persistido em um arquivo de log em .claude/.

Causa raiz

  • Prompts são mantidos como histórico de conversa
  • Prompts de subagentes são igualmente registrados
  • Mesmo em ambientes locais, outros processos ou backups podem expor segredos

Código de prevenção

Nunca escreva segredos em prompts — passe-os através de variáveis de ambiente

# ❌ Perigoso
claude -p "Use QIITA_TOKEN=abc123 para executar qiita-publish.mjs"

# ✅ Seguro: o script lê de process.env
# Escreva QIITA_TOKEN=abc123 no .env, então
claude -p "Execute scripts/qiita-publish.mjs (o token é lido automaticamente do .env)"

O mesmo princípio para instruções ao subagente

// ❌ Perigoso
Agent({ prompt: `Use a chave de API ${process.env.SECRET_KEY} para...` });

// ✅ Seguro: passe apenas o nome da chave, o script lê o valor
Agent({ prompt: "Use a variável de ambiente SECRET_KEY para..." });

Caso 5: Loop Infinito de Retry de API Explodiu a Fatura

O que aconteceu

“Tente novamente automaticamente em caso de erro” — um script com tratamento de erros foi gerado. Quando um erro era irresolvível, as tentativas nunca pararam: 3.000 chamadas à API da Anthropic em uma hora resultaram em uma fatura de US$ 200.

Causa raiz

  • Nenhum limite de retry foi definido
  • Sem exponential backoff — loop infinito em intervalos de 1 segundo
  • Nenhum alerta de faturamento configurado

Código de prevenção

// utils/retry.ts — utilitário de retry seguro
export async function withRetry<T>(
  fn: () => Promise<T>,
  options = { maxAttempts: 3, baseDelayMs: 1000, maxDelayMs: 30000 }
): Promise<T> {
  let lastError: Error;

  for (let attempt = 1; attempt <= options.maxAttempts; attempt++) {
    try {
      return await fn();
    } catch (err) {
      lastError = err as Error;
      if (attempt === options.maxAttempts) break;

      // Exponential backoff + jitter
      const delay = Math.min(
        options.baseDelayMs * Math.pow(2, attempt - 1) + Math.random() * 1000,
        options.maxDelayMs
      );
      console.warn(`Attempt ${attempt}/${options.maxAttempts} failed: ${err.message}`);
      console.warn(`Retrying in ${Math.round(delay / 1000)}s...`);
      await new Promise((r) => setTimeout(r, delay));
    }
  }

  throw new Error(`Falhou após ${options.maxAttempts} tentativas: ${lastError!.message}`);
}

Especificar no CLAUDE.md:

## Regras Obrigatórias para Chamadas de API
- Máximo de 3 retries
- Sempre implementar exponential backoff (1s → 2s → 4s)
- Nunca criar loops infinitos: while(true) + chamadas de API são proibidos

Caso 6: git push --force Apagou Commits de um Colega

O que aconteceu

“Sobrescreva o remoto com o estado local” — git push --force foi executado. Três commits que um membro da equipe acabara de enviar desapareceram. Esse membro também não tinha cópia local das alterações — o código foi perdido permanentemente.

Causa raiz

  • --force tende a ser executado sem compreender o perigo
  • Claude Code executa fielmente instruções de “sobrescrever o remoto”
  • O desenvolvedor desconhecia a alternativa mais segura git push --force-with-lease

Código de prevenção

// .claude/settings.json
{
  "permissions": {
    "deny": [
      "Bash(git push --force *master*)",
      "Bash(git push --force *main*)",
      "Bash(git push -f *master*)",
      "Bash(git push -f *main*)"
    ]
  }
}

Especificar a alternativa segura no CLAUDE.md:

## Regras Git Seguras
- `git push --force` é **proibido**
- Use `git push --force-with-lease` em vez disso
  (rejeitado automaticamente se outros enviaram alterações)
- Sempre obter confirmação do usuário antes de fazer push diretamente no main/master

Caso 7: Conta de Serviço com Privilégios Excessivos Acessou Todos os Recursos

O que aconteceu

“Use esta chave de conta de serviço do GCP para operar o Cloud Storage.” A conta de serviço tinha permissões de Owner. O Claude Code se conectou não apenas ao Cloud Storage, mas também ao BigQuery, Cloud SQL e clusters GKE “para investigar” — gerando cobranças inesperadas.

Causa raiz

  • A conta de serviço tinha permissões excessivas (violação do princípio do menor privilégio)
  • O Claude Code tem uma tendência agressiva de usar as ferramentas disponíveis
  • Mesmo “para investigar” soa como uma razão legítima para acesso amplo

Código de prevenção

Criar uma conta de serviço com privilégios mínimos:

# ❌ Evitar: permissão Owner
gcloud projects add-iam-policy-binding PROJECT_ID \
  --member="serviceAccount:[email protected]" \
  --role="roles/owner"

# ✅ Apenas as permissões mínimas necessárias
gcloud projects add-iam-policy-binding PROJECT_ID \
  --member="serviceAccount:[email protected]" \
  --role="roles/storage.objectAdmin"
  # ← Somente leitura/escrita no Cloud Storage

Definir explicitamente o escopo de acesso no CLAUDE.md:

## Restrições de Acesso ao GCP
Permissões para a conta de serviço usada neste projeto:
- Cloud Storage: Leitura/Escrita OK (bucket: my-project-assets apenas)
- BigQuery: Proibido
- Cloud SQL: Proibido
- Outros recursos GCP: Proibido

Recusar qualquer instrução que tente acessar recursos fora dessas permissões.

Lista de Verificação Abrangente para Prevenir Incidentes

Uma lista de verificação final destilada dos padrões comuns nos sete casos.

### Configurações a Aplicar Hoje (30 minutos)
- [ ] Adicionar padrão .env ao .gitignore
- [ ] Adicionar lista de deny ao .claude/settings.json (rm -rf, git push --force, DROP TABLE)
- [ ] Documentar restrições no CLAUDE.md

### Verificações Semanais
- [ ] Revisar git log em busca de commits de arquivos não intencionais
- [ ] Verificar se .env está excluído pelo .gitignore: `git check-ignore -v .env`
- [ ] Verificar prazos de rotação de chaves de API

### Primeira Resposta a um Incidente
1. Revogar e rotacionar imediatamente a chave de API afetada
2. Remover do histórico git (filter-branch ou BFG)
3. Revisar logs de acesso para determinar o escopo da violação
4. Reportar a situação aos interessados

Resumo

Incidentes com Claude Code raramente são causados por “IA ficando louca” — quase todos surgem de pessoas adiando a configuração de segurança.

CasoCausa RaizPrevenção
Vazamento .envSem gitignoreScript init + Hook
Exclusão BD produçãoSem separação de ambientes.env separado + fluxo de confirmação
Acidente rm -rfSem lista de denyConfigurar settings.json
Vazamento de chaveEscrita no promptPadronizar em variáveis de ambiente
Explosão de faturaSem limite de retryUtilitário withRetry
Force pushSem configuração de proibiçãodeny + force-with-lease
Acesso com privilégios excessivosViolação do menor privilégioRestringir roles IAM

Seu primeiro passo hoje: Adicionar "deny": ["Bash(rm -rf*)"] ao .claude/settings.json por si só pode prevenir um dos acidentes mais destrutivos possíveis.

Artigos Relacionados

Referências

#claude-code #security #incident #best-practices #devops

Leve seu fluxo no Claude Code a outro nível

50 modelos de prompt testados em campo, prontos para colar direto no Claude Code.

Grátis

PDF gratuito: Cheatsheet do Claude Code em 5 minutos

Basta informar seu e-mail e enviamos na hora o cheatsheet em uma página A4.

Cuidamos dos seus dados pessoais e nunca enviamos spam.

Masa

Sobre o autor

Masa

Engenheiro apaixonado por Claude Code. Mantém o claudecode-lab.com, uma mídia tech em 10 idiomas com mais de 2.000 páginas.