Tips & Tricks

7 Incidentes Reais em Produção com Claude Code: Recuperação Completa com RCA e Prevenção

7 incidentes reais em produção com Claude Code: vazamento de chaves API, exclusão de BD, explosão de cobrança e quedas de serviço — com análise de causa raiz e estratégias de prevenção.

“Claude Code é prático, mas tenho medo de usá-lo em produção” — muitos desenvolvedores sentem isso. E esse instinto é correto.

Claude Code opera em seu sistema de arquivos e shell com privilégios mais elevados do que uma IDE convencional. Ao mesmo tempo, clicar repetidamente no botão de aprovação reduz a vigilância — uma vulnerabilidade psicológica humana bem conhecida. Quando esses dois fatores se combinam, incidentes em produção acontecem.

Este artigo documenta 7 incidentes reais em produção envolvendo Claude Code, com causas, escopo de impacto, procedimentos de recuperação, RCA (análise de causa raiz) e estratégias de prevenção. Leia isto antes que um acidente aconteça na sua organização.


Incidente 1: Vazamento de Chave API → R$ 15.000 em Cobranças Não Autorizadas

Linha do Tempo

09:12  Claude Code instruído: "commitar .env para passar variáveis de ambiente para o CI"
09:13  git add .env && git push executado sem aprovação (lista allow muito permissiva)
09:14  GitHub Secret Scanning detectou, notificação por email enviada
09:31  Crawler da AWS detectou a chave OpenAI, uso não autorizado começou
11:00  R$ 15.000 em cobranças confirmados no painel da OpenAI

Procedimento de Recuperação

# Passo 1: Revogar imediatamente a chave API (prioridade máxima — em 5 minutos)
# → Revogar a chave no painel da OpenAI / de cada serviço

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

# Passo 3: Force push de todas as branches
git push origin --force --all
git push origin --force --tags

# Passo 4: Adicionar ao .gitignore para prevenir recorrência
echo ".env" >> .gitignore
git add .gitignore && git commit -m "security: add .env to gitignore"

# Passo 5: Emitir nova chave API e configurar no .env

RCA

  • Causa direta: settings.json tinha Bash(git add*) na lista allow, permitindo execução sem confirmação
  • Causa raiz: Configuração de segurança foi adiada em favor do código de produto

Prevenção

// .claude/settings.json
{
  "hooks": {
    "PreToolUse": [{
      "matcher": "Bash(git add*)",
      "hooks": [{
        "type": "command",
        "command": "git diff --cached --name-only | grep -E '\\.env' && echo '🚨 .env detectado! Cancelando.' && exit 1 || exit 0"
      }]
    }]
  }
}

Incidente 2: rm -rf Apagou o Projeto Inteiro

Linha do Tempo

14:33  Instrução: "limpar node_modules e reinstalar"
14:33  Claude Code executou rm -rf node_modules (normal até aqui)
14:34  Instrução de seguimento "apagar arquivos de build antigos também" → rm -rf dist/ executado
14:34  Interpretação incorreta do caminho: rm -rf dist /src foi executado (espaço como separador)
14:35  Diretório src/ completamente apagado. Arquivos de config fora do git também removidos
14:40  git checkout . restaurou arquivos rastreados, mas .env e configs locais perdidos permanentemente

Procedimento de Recuperação

# Arquivos rastreados pelo git podem ser restaurados
git checkout .
git clean -fd   # Remover arquivos extras

# Procurar arquivos deletados no git stash ou reflog
git stash list
git reflog

# Arquivos fora do git (.env etc.) devem ser restaurados do backup
# → Sem backup, reconfigure do zero

RCA

  • Causa direta: Caminho com espaço não foi corretamente entre aspas, resultando em rm -rf dist /src
  • Causa raiz: rm -rf estava em allow em vez de ask

Prevenção

{
  "permissions": {
    "deny": ["Bash(rm -rf ~*)", "Bash(rm -rf /*)"],
    "ask": ["Bash(rm*)"]
  },
  "hooks": {
    "PreToolUse": [{
      "matcher": "Bash(rm*)",
      "hooks": [{
        "type": "command",
        "command": "echo '⚠️ Comando de exclusão detectado. Alvo: $CLAUDE_TOOL_INPUT_COMMAND\nExecutando em 5 segundos. Ctrl+C para cancelar.' && sleep 5"
      }]
    }]
  }
}

Incidente 3: git push --force Apagou os Commits de 3 Colegas

Linha do Tempo

16:00  Instrução: "há um conflito com o remoto. Priorizar local e sobrescrever"
16:01  git push --force origin main foi executado
16:01  ~200 linhas de código commitadas por 3 colegas naquele dia foram apagadas
16:10  Colega A no Slack: "Ei, meus commits desapareceram"
16:15  Causa identificada. A e B tinham cópias locais, mas C já havia deletado as suas — perda permanente

Procedimento de Recuperação

# Procurar commits perdidos no reflog (na máquina que fez o push)
git reflog | head -30
# → Exemplo: abc1234 HEAD@{3}: commit antes do --force push

# Restaurar os commits perdidos
git checkout -b recovery abc1234
git push origin recovery

# Fazer merge na main e limpar
git checkout main
git merge recovery --no-ff
git push origin main

RCA

  • Causa direta: A intenção de resolver um conflito foi interpretada como --force em vez de --force-with-lease
  • Causa raiz: Force push na branch main não estava na lista deny

Prevenção

{
  "permissions": {
    "deny": [
      "Bash(git push --force *main*)",
      "Bash(git push --force *master*)",
      "Bash(git push -f *main*)"
    ]
  }
}
<!-- CLAUDE.md -->
## Regras do Git
- `git push --force` é proibido
- Usar `git push --force-with-lease` para resolução de conflitos
- Sempre obter confirmação do usuário antes de fazer push na main/master

Incidente 4: Migração de BD Falhou e Apagou 40.000 Registros em Produção

Linha do Tempo

10:00  Instrução: "executar migração para adicionar coluna phone_number à tabela users"
10:01  Claude Code gerou e executou o script de migração
10:01  Um bug no script fez a migração reversa (com DROP COLUMN) ser executada
10:02  Coluna users.email (NOT NULL) foi removida da produção
10:02  Todas as APIs retornaram erros 500, serviço completamente fora do ar
10:05  Incidente reconhecido, investigação de causa raiz iniciada
10:30  Restauração a partir do snapshot do dia anterior (um dia de dados perdido)

Procedimento de Recuperação

# 1. Colocar o serviço em modo de manutenção imediatamente
# nginx: return 503;  ou  Vercel: página de manutenção

# 2. Verificar o estado atual do BD
psql $DATABASE_URL -c "\d users"

# 3. Restaurar a partir do backup (para RDS)
aws rds restore-db-instance-to-point-in-time \
  --source-db-instance-identifier mydb \
  --target-db-instance-identifier mydb-restored \
  --restore-time 2026-04-17T23:00:00Z

# 4. Se a coluna ainda existir, adicioná-la manualmente
ALTER TABLE users ADD COLUMN email VARCHAR(255);
UPDATE users SET email = '(recuperação necessária)' WHERE email IS NULL;

# 5. Restaurar o serviço

RCA

  • Causa direta: O gerador de script de migração confundiu as migrações up/down
  • Causa raiz: A migração foi executada em produção sem testá-la em ambiente de staging

Prevenção

<!-- CLAUDE.md -->
## Regras Obrigatórias para Migrações de BD
1. Sempre testar no ambiente de staging antes de aplicar em produção
2. Sempre criar backup manual antes da migração:
   pg_dump $DATABASE_URL > backup_$(date +%Y%m%d_%H%M%S).sql
3. Scripts com DROP COLUMN / TRUNCATE / DELETE (sem WHERE) devem
   sempre ser confirmados pelo usuário antes da execução
4. Se usar DATABASE_URL de produção, exibir 'Escrevendo no BD de PRODUÇÃO. Continuar?' antes de executar

Incidente 5: Chamadas API Infinitas Geraram R$ 4.000 em Uma Noite

Linha do Tempo

23:00  Instrução: "tentar novamente automaticamente em caso de erros" e processamento em lote iniciado
23:01  API externa começou a retornar 503
23:01  Lógica de retry rodou sem limite, batendo na API a cada segundo
07:00  Manhã seguinte, notificação da Anthropic: "Uso se aproximando do limite"
07:05  Encontradas 28.000 chamadas API e R$ 4.000 em cobranças

Procedimento de Recuperação

# 1. Parar o processo imediatamente
pkill -f "node batch-process.js"

# 2. Revisar cobranças e contatar o suporte da Anthropic
# → Comunicação sincera pode resultar em reembolso parcial

# 3. Configurar alertas de uso
# Console da Anthropic → Usage Limits → Definir alerta de orçamento mensal

Prevenção

// utils/retry.ts — sempre use este utilitário
export async function withRetry<T>(
  fn: () => Promise<T>,
  { maxAttempts = 3, baseDelayMs = 1000, maxDelayMs = 30000 } = {}
): Promise<T> {
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    try {
      return await fn();
    } catch (err) {
      if (attempt === maxAttempts) throw err;
      const delay = Math.min(
        baseDelayMs * 2 ** (attempt - 1) + Math.random() * 500,
        maxDelayMs
      );
      console.warn(`Retry ${attempt}/${maxAttempts} in ${Math.round(delay)}ms`);
      await new Promise(r => setTimeout(r, delay));
    }
  }
  throw new Error("unreachable");
}
<!-- CLAUDE.md -->
## Regras para Chamadas API
- Máximo 3 tentativas com backoff exponencial obrigatório
- while(true) + chamadas API são estritamente proibidos
- Jobs em lote devem ter limites de contagem explícitos
- Executar smoke test --dry-run antes da execução em produção

Incidente 6: Dependências Quebradas Após Deploy Derrubaram o Serviço

Linha do Tempo

15:00  Instrução: "atualizar pacotes para as versões mais recentes"
15:01  npm update executado, package-lock.json mudou significativamente
15:05  Build local bem-sucedido
15:10  Deploy em produção
15:12  Incompatibilidade de versão maior nas dependências de produção, falha na inicialização
15:12  Erros 503, serviço completamente fora do ar
15:30  Rollback para a versão anterior concluído

Procedimento de Recuperação

# Para Vercel / Cloudflare Pages: reativar o deploy anterior imediatamente
# → Rollback com um clique pelo painel

# Reverter código com git revert
git revert HEAD~1
git push

# Restaurar package-lock.json para a versão anterior
git checkout HEAD~1 -- package-lock.json
npm ci  # Usa package-lock.json rigorosamente

RCA

  • Causa direta: npm update atualizou uma versão maior, causando breaking change
  • Causa raiz: Verificação do deploy no ambiente de staging foi ignorada

Prevenção

<!-- CLAUDE.md -->
## Regras de Gerenciamento de Pacotes
- npm update é proibido (npm update --save-dev condicionalmente permitido)
- Upgrades de versão maior de pacotes requerem confirmação do usuário
- Sempre verificar comportamento no staging antes de fazer deploy
- Monitorar logs de erro por 5 minutos após o deploy em produção

Incidente 7: Permissões Mal Configuradas Expuseram Dados de Todos os Usuários

Linha do Tempo

11:00  Instrução: "adicionar lista de usuários ao endpoint de API do painel de administração"
11:05  /api/admin/users implementado sem verificação de autenticação
11:10  Deploy em produção
11:10  Informações pessoais de todos os usuários acessíveis para qualquer pessoa
13:30  Ferramenta de auditoria de segurança detectou endpoint não autenticado
13:35  Endpoint imediatamente desativado

Procedimento de Recuperação

# 1. Desativar imediatamente o endpoint afetado
# nginx: location /api/admin { return 403; }

# 2. Revisar logs de acesso para determinar o escopo da exposição
grep "/api/admin/users" /var/log/nginx/access.log | \
  awk '{print $1}' | sort | uniq -c | sort -rn

# 3. Notificar usuários afetados (verificar requisitos da LGPD)

# 4. Adicionar middleware de autenticação e fazer redeploy

RCA

  • Causa direta: A instrução “adicionar ao painel de administração” não comunicou os requisitos de autenticação
  • Causa raiz: Requisitos de segurança não estavam documentados no CLAUDE.md

Prevenção

<!-- CLAUDE.md -->
## Requisitos de Segurança de API
- Endpoints /api/admin/* devem sempre implementar autenticação de administrador
- Endpoints /api/user/* devem sempre implementar autenticação de login
- Apenas endpoints /api/public/* são acessíveis sem autenticação
- Ao adicionar uma nova API, comentar explicitamente o nível de autenticação necessário

Fluxo Comum de Resposta a Incidentes (Template de Postmortem)

# Postmortem: [Título do Incidente]

## Resumo
- Ocorreu em: YYYY-MM-DD HH:MM
- Detectado em: YYYY-MM-DD HH:MM
- Resolvido em: YYYY-MM-DD HH:MM
- Impacto: (número de usuários / funcionalidades / duração)
- Severidade: P0/P1/P2/P3

## Linha do Tempo
| Hora  | Evento |
|-------|--------|
| HH:MM | Incidente ocorreu |
| HH:MM | Detectado |
| HH:MM | Resposta iniciada |
| HH:MM | Causa raiz identificada |
| HH:MM | Recuperação concluída |

## Causa Raiz
- Causa direta:
- Causa raiz:
- Causa agravante:

## Ações de Prevenção
| Ação | Responsável | Prazo |
|------|-------------|-------|
|      |             |       |

## Lições Aprendidas

Resumo: Configuração Mínima para Prevenir Incidentes

// Copie isto agora e cole em .claude/settings.json
{
  "permissions": {
    "deny": [
      "Bash(rm -rf ~*)",
      "Bash(rm -rf /*)",
      "Bash(git push --force *main*)",
      "Bash(git push --force *master*)",
      "Bash(git push -f *main*)",
      "Bash(DROP TABLE*)",
      "Bash(TRUNCATE *)",
      "Bash(curl * | bash)",
      "Bash(wget * | sh)"
    ],
    "ask": [
      "Write(**)", "Edit(**)",
      "Bash(rm*)", "Bash(git commit*)",
      "Bash(git push*)", "Bash(*deploy*)",
      "Bash(npm install*)", "Bash(*migrate*)"
    ]
  },
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash(git add*)",
        "hooks": [{ "type": "command",
          "command": "git diff --cached --name-only | grep '\\.env' && echo '🚨 .env detectado! Cancelando.' && exit 1 || exit 0" }]
      },
      {
        "matcher": "Bash(rm*)",
        "hooks": [{ "type": "command",
          "command": "echo '⚠️ Comando de exclusão detectado. Executando em 5 segundos. Ctrl+C para cancelar.' && sleep 5" }]
      }
    ]
  }
}

Incidentes em produção acontecem quando você pula os 30 minutos necessários para configurar. Todos os 7 incidentes deste artigo poderiam ter sido evitados com um settings.json e CLAUDE.md adequados.

Artigos Relacionados

Referências

#claude-code #incident #production #sre #security #postmortem

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.