7 incidents de production réels avec Claude Code : récupération complète avec RCA et prévention
7 incidents de production réels avec Claude Code : fuites de clés API, suppressions de BD, explosions de facturation et pannes de service — avec analyse des causes racines et stratégies de prévention.
« Claude Code est pratique, mais j’ai peur de l’utiliser en production » — de nombreux développeurs ressentent cela. Et cet instinct est juste.
Claude Code opère sur votre système de fichiers et votre shell avec des privilèges plus élevés qu’un IDE classique. Parallèlement, cliquer répétitivement sur le bouton d’approbation émousse la vigilance — une vulnérabilité psychologique humaine bien connue. Quand ces deux facteurs se combinent, les incidents de production surviennent.
Cet article documente 7 incidents de production réels impliquant Claude Code, avec les causes, l’étendue de l’impact, les procédures de récupération, l’analyse des causes racines (RCA) et les stratégies de prévention. Lisez-le avant qu’un accident ne se produise dans votre organisation.
Incident 1 : Fuite de clé API → 2 800 € de charges non autorisées
Chronologie
09:12 Claude Code a été instruit : "committer .env pour passer des variables d'environnement à la CI"
09:13 git add .env && git push exécuté sans approbation (liste allow trop permissive)
09:14 GitHub Secret Scanning l'a détecté, notification par e-mail envoyée
09:31 Le crawler AWS a détecté la clé OpenAI, utilisation non autorisée commencée
11:00 Charge de 2 800 € confirmée dans le tableau de bord OpenAI
Procédure de récupération
# Étape 1 : Révoquer la clé API immédiatement (priorité absolue — dans les 5 minutes)
# → Révoquer la clé dans le tableau de bord OpenAI / de chaque service
# Étape 2 : Supprimer complètement .env de l'historique git
git filter-branch --force --index-filter \
"git rm --cached --ignore-unmatch .env" \
--prune-empty --tag-name-filter cat -- --all
# Étape 3 : Force push de toutes les branches
git push origin --force --all
git push origin --force --tags
# Étape 4 : Ajouter à .gitignore pour prévenir la récidive
echo ".env" >> .gitignore
git add .gitignore && git commit -m "security: add .env to gitignore"
# Étape 5 : Émettre une nouvelle clé API et la configurer dans .env
RCA
- Cause directe :
settings.jsonavaitBash(git add*)dans la listeallow, permettant l’exécution sans confirmation - Cause racine : La configuration de sécurité a été déprioritisée au profit du code produit
Prévention
// .claude/settings.json
{
"hooks": {
"PreToolUse": [{
"matcher": "Bash(git add*)",
"hooks": [{
"type": "command",
"command": "git diff --cached --name-only | grep -E '\\.env' && echo '🚨 .env détecté ! Annulation.' && exit 1 || exit 0"
}]
}]
}
}
Incident 2 : rm -rf a effacé tout le projet
Chronologie
14:33 Instruction : "nettoyer node_modules et réinstaller"
14:33 Claude Code a exécuté rm -rf node_modules (normal jusque-là)
14:34 Instruction de suivi "supprimer aussi les anciens fichiers de build" → rm -rf dist/
14:34 Mauvaise interprétation du chemin : rm -rf dist /src s'est exécuté (espace comme séparateur)
14:35 Répertoire src/ entièrement supprimé. Fichiers de config hors git également effacés
14:40 git checkout . a restauré les fichiers trackés, mais .env et configs locaux perdus définitivement
Procédure de récupération
# Les fichiers trackés par git peuvent être restaurés
git checkout .
git clean -fd # Supprimer les fichiers en trop
# Chercher les fichiers supprimés dans git stash ou reflog
git stash list
git reflog
# Les fichiers hors git (.env etc.) doivent être restaurés depuis une sauvegarde
# → Sans sauvegarde, reconfigurer depuis zéro
RCA
- Cause directe : Le chemin contenant un espace n’a pas été correctement mis entre guillemets, résultant en
rm -rf dist /src - Cause racine :
rm -rfétait dansallowau lieu deask
Prévention
{
"permissions": {
"deny": ["Bash(rm -rf ~*)", "Bash(rm -rf /*)"],
"ask": ["Bash(rm*)"]
},
"hooks": {
"PreToolUse": [{
"matcher": "Bash(rm*)",
"hooks": [{
"type": "command",
"command": "echo '⚠️ Commande de suppression détectée. Cible : $CLAUDE_TOOL_INPUT_COMMAND\nExécution dans 5 secondes. Ctrl+C pour annuler.' && sleep 5"
}]
}]
}
}
Incident 3 : git push --force a effacé les commits de 3 collègues
Chronologie
16:00 Instruction : "il y a un conflit avec le distant. Prioriser le local et écraser"
16:01 git push --force origin main exécuté
16:01 ~200 lignes de code committées par 3 collègues ce jour-là ont été effacées
16:10 Collègue A sur Slack : "Bizarre, mes commits ont disparu"
16:15 Cause identifiée. A et B avaient des copies locales, mais C avait déjà supprimé les siennes — perte définitive
Procédure de récupération
# Chercher les commits perdus dans le reflog (sur la machine qui a fait le push)
git reflog | head -30
# → Exemple : abc1234 HEAD@{3}: commit avant le --force push
# Restaurer les commits perdus
git checkout -b recovery abc1234
git push origin recovery
# Fusionner dans main et nettoyer
git checkout main
git merge recovery --no-ff
git push origin main
RCA
- Cause directe : L’intention de résoudre un conflit a été interprétée comme
--forceau lieu de--force-with-lease - Cause racine : Le force push sur la branche main n’était pas dans la liste
deny
Prévention
{
"permissions": {
"deny": [
"Bash(git push --force *main*)",
"Bash(git push --force *master*)",
"Bash(git push -f *main*)"
]
}
}
<!-- CLAUDE.md -->
## Règles Git
- `git push --force` est interdit
- Utiliser `git push --force-with-lease` pour la résolution de conflits
- Toujours obtenir la confirmation de l'utilisateur avant de pousser sur main/master
Incident 4 : Migration BD échouée a effacé 40 000 enregistrements en production
Chronologie
10:00 Instruction : "exécuter la migration pour ajouter la colonne phone_number à la table users"
10:01 Claude Code a généré et exécuté le script de migration
10:01 Un bug dans le script a causé l'exécution de la migration inverse (avec DROP COLUMN)
10:02 La colonne users.email (NOT NULL) a été supprimée de la production
10:02 Toutes les API ont retourné des erreurs 500, service complètement arrêté
10:05 Incident reconnu, enquête sur la cause racine commencée
10:30 Restauration depuis le snapshot de la veille (une journée de données perdue)
Procédure de récupération
# 1. Mettre le service en mode maintenance immédiatement
# nginx: return 503; ou Vercel: page de maintenance
# 2. Vérifier l'état actuel de la BD
psql $DATABASE_URL -c "\d users"
# 3. Restaurer depuis la sauvegarde (pour 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. Si la colonne existe encore, l'ajouter manuellement
ALTER TABLE users ADD COLUMN email VARCHAR(255);
UPDATE users SET email = '(récupération requise)' WHERE email IS NULL;
# 5. Restaurer le service
RCA
- Cause directe : Le générateur de script de migration a confondu les migrations up/down
- Cause racine : La migration a été exécutée en production sans la tester dans un environnement de staging
Prévention
<!-- CLAUDE.md -->
## Règles obligatoires pour les migrations BD
1. Toujours tester dans l'environnement de staging avant d'appliquer en production
2. Toujours créer une sauvegarde manuelle avant la migration :
pg_dump $DATABASE_URL > backup_$(date +%Y%m%d_%H%M%S).sql
3. Les scripts contenant DROP COLUMN / TRUNCATE / DELETE (sans WHERE) doivent
toujours être confirmés par l'utilisateur avant exécution
4. En cas d'utilisation de DATABASE_URL de production, afficher 'Écriture dans la BD de PRODUCTION. Continuer ?' avant exécution
Incident 5 : Appels API infinis ont généré 750 € en une nuit
Chronologie
23:00 Instruction : "réessayer automatiquement en cas d'erreurs" et traitement par lots démarré
23:01 L'API externe a commencé à retourner des 503
23:01 La logique de réessai a tourné sans limite, frappant l'API chaque seconde
07:00 Lendemain matin, notification d'Anthropic : "L'utilisation approche la limite"
07:05 28 000 appels API et 750 € de charges constatés
Procédure de récupération
# 1. Arrêter le processus immédiatement
pkill -f "node batch-process.js"
# 2. Vérifier les charges et contacter le support Anthropic
# → Une communication sincère peut aboutir à un remboursement partiel
# 3. Configurer des alertes d'utilisation
# Console Anthropic → Usage Limits → Définir une alerte de budget mensuel
Prévention
// utils/retry.ts — toujours utiliser cet utilitaire
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 -->
## Règles pour les appels API
- Maximum 3 tentatives avec backoff exponentiel obligatoire
- while(true) + appels API sont strictement interdits
- Les traitements par lots doivent avoir des limites de comptage explicites
- Exécuter un smoke test --dry-run avant l'exécution en production
Incident 6 : Des dépendances cassées après déploiement ont arrêté le service
Chronologie
15:00 Instruction : "mettre à jour les packages vers les dernières versions"
15:01 npm update exécuté, package-lock.json a changé significativement
15:05 Build local réussi
15:10 Déployé en production
15:12 Incompatibilité de version majeure dans les dépendances de production, échec au démarrage
15:12 Erreurs 503, service complètement arrêté
15:30 Rollback vers la version précédente terminé
Procédure de récupération
# Pour Vercel / Cloudflare Pages : réactiver immédiatement le déploiement précédent
# → Rollback en un clic depuis le tableau de bord
# Annuler le code avec git revert
git revert HEAD~1
git push
# Restaurer package-lock.json à la version précédente
git checkout HEAD~1 -- package-lock.json
npm ci # Utilise strictement package-lock.json
RCA
- Cause directe :
npm updatea mis à jour une version majeure, causant un breaking change - Cause racine : La vérification du déploiement dans l’environnement de staging a été sautée
Prévention
<!-- CLAUDE.md -->
## Règles de gestion des packages
- npm update est interdit (npm update --save-dev conditionnellement autorisé)
- Les mises à jour de version majeure des packages nécessitent la confirmation de l'utilisateur
- Toujours vérifier le comportement en staging avant de déployer
- Surveiller les journaux d'erreurs pendant 5 minutes après le déploiement en production
Incident 7 : Des permissions mal configurées ont exposé les données de tous les utilisateurs
Chronologie
11:00 Instruction : "ajouter la liste des utilisateurs au endpoint API du panneau d'administration"
11:05 /api/admin/users implémenté sans vérification d'authentification
11:10 Déployé en production
11:10 Les données personnelles de tous les utilisateurs accessibles à n'importe qui
13:30 L'outil d'audit de sécurité a détecté le endpoint non authentifié
13:35 Endpoint immédiatement désactivé
Procédure de récupération
# 1. Désactiver immédiatement le endpoint affecté
# nginx: location /api/admin { return 403; }
# 2. Examiner les journaux d'accès pour déterminer l'étendue de l'exposition
grep "/api/admin/users" /var/log/nginx/access.log | \
awk '{print $1}' | sort | uniq -c | sort -rn
# 3. Notifier les utilisateurs affectés (vérifier les exigences du RGPD)
# 4. Ajouter le middleware d'authentification et redéployer
RCA
- Cause directe : L’instruction “ajouter au panneau d’administration” n’a pas communiqué les exigences d’authentification
- Cause racine : Les exigences de sécurité n’étaient pas documentées dans CLAUDE.md
Prévention
<!-- CLAUDE.md -->
## Exigences de sécurité API
- Les endpoints /api/admin/* doivent toujours implémenter l'authentification administrateur
- Les endpoints /api/user/* doivent toujours implémenter l'authentification de connexion
- Seuls les endpoints /api/public/* sont accessibles sans authentification
- Lors de l'ajout d'une nouvelle API, commenter explicitement le niveau d'authentification requis
Flux commun de réponse aux incidents (Modèle de postmortem)
# Postmortem : [Titre de l'incident]
## Résumé
- Survenu à : YYYY-MM-DD HH:MM
- Détecté à : YYYY-MM-DD HH:MM
- Résolu à : YYYY-MM-DD HH:MM
- Impact : (nombre d'utilisateurs / fonctionnalités / durée)
- Sévérité : P0/P1/P2/P3
## Chronologie
| Heure | Événement |
|-------|-----------|
| HH:MM | Incident survenu |
| HH:MM | Détecté |
| HH:MM | Réponse commencée |
| HH:MM | Cause racine identifiée |
| HH:MM | Récupération terminée |
## Cause racine
- Cause directe :
- Cause racine :
- Cause aggravante :
## Actions de prévention
| Action | Responsable | Échéance |
|--------|-------------|----------|
| | | |
## Leçons apprises
Résumé : Configuration minimale pour prévenir les incidents
// Copiez ceci maintenant et collez-le dans .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 détecté ! Annulation.' && exit 1 || exit 0" }]
},
{
"matcher": "Bash(rm*)",
"hooks": [{ "type": "command",
"command": "echo '⚠️ Commande de suppression détectée. Exécution dans 5 secondes. Ctrl+C pour annuler.' && sleep 5" }]
}
]
}
}
Les incidents de production surviennent quand on économise les 30 minutes nécessaires à la configuration. Les 7 incidents de cet article auraient tous pu être évités avec un settings.json et un CLAUDE.md appropriés.
Articles connexes
- Guide complet des meilleures pratiques de sécurité Claude Code
- 7 cas d’échec de sécurité avec Claude Code
- Guide complet des permissions Claude Code
Références
Passez votre flux Claude Code au niveau supérieur
50 modèles de prompts éprouvés, prêts à être copiés-collés dans Claude Code.
PDF gratuit : aide-mémoire Claude Code en 5 minutes
Laissez simplement votre e-mail et nous vous enverrons immédiatement l'aide-mémoire A4 en PDF.
Nous traitons vos données avec soin et n'envoyons jamais de spam.
À propos de l'auteur
Masa
Ingénieur passionné par Claude Code. Il gère claudecode-lab.com, un média tech en 10 langues avec plus de 2 000 pages.
Articles similaires
Maîtrisez les coûts API de Claude Code : 5 techniques pour passer de $450 à $45/mois
Les vrais chiffres derrière la tarification de l'API Claude Code. Découvrez comment le prompt caching, l'optimisation des modèles et le traitement par lots ont permis une réduction de 90 %, de $450 à $45 par mois.
10 patterns de prompts dangereux dans Claude Code | Ce qu'il ne faut pas faire et les alternatives sûres
Découvrez 10 patterns de prompts dangereux à ne jamais donner à Claude Code. Apprenez comment des instructions vagues mènent à la perte de code, la destruction de BD, des factures explosives et des fuites de clés.
Guide Complet de Sécurité pour Claude Code : Clés API, Permissions et Protection de la Production
Guide pratique de sécurité pour utiliser Claude Code en toute sécurité. De la gestion des clés API aux paramètres de permissions, automatisation via Hooks et protection de l'environnement de production — avec des exemples de code fonctionnels.