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.jsontinhaBash(git add*)na listaallow, 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 -rfestava emallowem vez deask
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
--forceem 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 updateatualizou 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
- Guia Completo de Melhores Práticas de Segurança do Claude Code
- 7 Casos de Falha de Segurança do Claude Code
- Guia Completo de Permissões do Claude Code
Referências
Leve seu fluxo no Claude Code a outro nível
50 modelos de prompt testados em campo, prontos para colar direto no Claude Code.
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.
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.
Artigos relacionados
Domine os custos da API do Claude Code: 5 técnicas para cair de $450 para $45/mês
Os números reais por trás dos preços da API do Claude Code. Veja como o prompt caching, a otimização de modelos e o processamento em lotes alcançaram 90% de redução—de $450 para $45 por mês.
10 Padrões de Prompts Perigosos no Claude Code | O Que Evitar e Alternativas Seguras
Descubra 10 padrões de prompts perigosos que você nunca deve dar ao Claude Code. Saiba como instruções vagas causam perda de código, destruição de BD, contas absurdas e vazamento de chaves.
Guia Completo de Segurança do Claude Code: Chaves API, Permissões e Proteção da Produção
Um guia prático de segurança para usar o Claude Code com segurança. Do gerenciamento de chaves API às configurações de permissões, automação baseada em Hooks e proteção do ambiente de produção — com exemplos de código funcionais.