Tips & Tricks

7 echte Produktionsausfälle mit Claude Code: Vollständige Wiederherstellung mit RCA & Prävention

7 echte Produktionsvorfälle mit Claude Code: API-Key-Leaks, DB-Löschungen, Kostenexplosionen und Serviceausfälle – mit Ursachenanalyse und Präventionsstrategien.

„Claude Code ist praktisch, aber ich habe Angst, es in der Produktion einzusetzen” – viele Entwickler teilen dieses Gefühl. Und dieser Instinkt ist berechtigt.

Claude Code operiert auf Ihrem Dateisystem und Ihrer Shell mit höheren Rechten als eine normale IDE. Gleichzeitig führt das wiederholte Klicken auf die Bestätigungsschaltfläche dazu, dass die Wachsamkeit nachlässt – eine bekannte menschliche Schwäche. Wenn diese beiden Faktoren zusammentreffen, kommt es zu Produktionsausfällen.

Dieser Artikel dokumentiert 7 echte Produktionsvorfälle mit Claude Code – komplett mit Ursachen, Schadensumfang, Wiederherstellungsverfahren, RCA (Root Cause Analysis) und Präventionsstrategien. Lesen Sie dies, bevor ein Unfall in Ihrer Organisation passiert.


Vorfall 1: API-Key-Leak → 2.800 € unberechtigte Gebühren

Zeitverlauf

09:12  Claude Code angewiesen: ".env committen, um Umgebungsvariablen an CI zu übergeben"
09:13  git add .env && git push wurde ohne Bestätigung ausgeführt (Allow-Liste zu permissiv)
09:14  GitHub Secret Scanning erkannte es, E-Mail-Benachrichtigung gesendet
09:31  AWS-Crawler erkannte den OpenAI-Key, unberechtigte Nutzung begann
11:00  Gebühr von 2.800 € im OpenAI-Dashboard bestätigt

Wiederherstellungsverfahren

# Schritt 1: API-Key sofort sperren (höchste Priorität – innerhalb von 5 Minuten)
# → Key im Dashboard von OpenAI / jeweiligem Dienst widerrufen

# Schritt 2: .env vollständig aus der Git-History entfernen
git filter-branch --force --index-filter \
  "git rm --cached --ignore-unmatch .env" \
  --prune-empty --tag-name-filter cat -- --all

# Schritt 3: Alle Branches force pushen
git push origin --force --all
git push origin --force --tags

# Schritt 4: Zu .gitignore hinzufügen, um Wiederholung zu verhindern
echo ".env" >> .gitignore
git add .gitignore && git commit -m "security: add .env to gitignore"

# Schritt 5: Neuen API-Key ausstellen und in .env eintragen

RCA

  • Direkte Ursache: settings.json hatte Bash(git add*) in der allow-Liste, was die Ausführung ohne Bestätigung ermöglichte
  • Grundursache: Sicherheitskonfiguration wurde zugunsten von Produktcode zurückgestellt

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 erkannt! Abbruch.' && exit 1 || exit 0"
      }]
    }]
  }
}

Vorfall 2: rm -rf löschte das gesamte Projekt

Zeitverlauf

14:33  Anweisung: "node_modules bereinigen und neu installieren"
14:33  Claude Code führte rm -rf node_modules aus (bis hier normal)
14:34  Folgebefehl "alte Build-Dateien auch löschen" → rm -rf dist/ ausgeführt
14:34  Pfad-Fehlinterpretation: rm -rf dist /src wurde ausgeführt (Leerzeichen als Trennzeichen)
14:35  src/-Verzeichnis vollständig gelöscht. Auch Konfigurationsdateien außerhalb von Git verschwunden
14:40  git checkout . stellte getrackte Dateien wieder her, aber .env und lokale Configs dauerhaft verloren

Wiederherstellungsverfahren

# Von Git getrackte Dateien können wiederhergestellt werden
git checkout .
git clean -fd   # Überflüssige Dateien entfernen

# Gelöschte Dateien in git stash oder reflog suchen
git stash list
git reflog

# Nicht von Git verwaltete Dateien (.env etc.) aus Backup wiederherstellen
# → Ohne Backup muss alles neu konfiguriert werden

RCA

  • Direkte Ursache: Pfad mit Leerzeichen wurde nicht korrekt in Anführungszeichen gesetzt, was zu rm -rf dist /src führte
  • Grundursache: rm -rf stand in allow statt ask

Prävention

{
  "permissions": {
    "deny": ["Bash(rm -rf ~*)", "Bash(rm -rf /*)"],
    "ask": ["Bash(rm*)"]
  },
  "hooks": {
    "PreToolUse": [{
      "matcher": "Bash(rm*)",
      "hooks": [{
        "type": "command",
        "command": "echo '⚠️ Löschbefehl erkannt. Ziel: $CLAUDE_TOOL_INPUT_COMMAND\nAusführung in 5 Sekunden. Abbruch mit Ctrl+C.' && sleep 5"
      }]
    }]
  }
}

Vorfall 3: git push --force löschte Commits von 3 Kollegen

Zeitverlauf

16:00  Anweisung: "Es gibt einen Konflikt mit Remote. Lokale Änderungen priorisieren und überschreiben"
16:01  git push --force origin main wurde ausgeführt
16:01  ~200 Codezeilen, die 3 Kollegen an diesem Tag committed hatten, wurden gelöscht
16:10  Kollege A im Slack: "Seltsam, meine Commits sind weg"
16:15  Ursache identifiziert. Kollegen A/B hatten lokale Kopien, aber Kollege C hatte bereits gelöscht – dauerhaft verloren

Wiederherstellungsverfahren

# Verlorene Commits im reflog suchen (auf der Maschine, die den Push ausgeführt hat)
git reflog | head -30
# → Beispiel: abc1234 HEAD@{3}: Commit vor dem --force-Push

# Verlorene Commits wiederherstellen
git checkout -b recovery abc1234
git push origin recovery

# In main mergen und aufräumen
git checkout main
git merge recovery --no-ff
git push origin main

RCA

  • Direkte Ursache: Die Absicht, einen Konflikt zu lösen, wurde als --force statt --force-with-lease interpretiert
  • Grundursache: Force Push auf den main-Branch war nicht in der deny-Liste

Prävention

{
  "permissions": {
    "deny": [
      "Bash(git push --force *main*)",
      "Bash(git push --force *master*)",
      "Bash(git push -f *main*)"
    ]
  }
}
<!-- CLAUDE.md -->
## Git-Regeln
- `git push --force` ist verboten
- Für Konfliktlösung `git push --force-with-lease` verwenden
- Push auf main/master immer erst nach Benutzerbestätigung

Vorfall 4: Fehlgeschlagene DB-Migration löschte 40.000 Produktionsdatensätze

Zeitverlauf

10:00  Anweisung: "Migration ausführen, um phone_number-Spalte zur users-Tabelle hinzuzufügen"
10:01  Claude Code generierte und führte das Migrationsskript aus
10:01  Ein Bug im Skript führte dazu, dass die Rückwärtsmigration (mit DROP COLUMN) ausgeführt wurde
10:02  users.email-Spalte (NOT NULL) wurde aus der Produktion gelöscht
10:02  Alle APIs gaben 500-Fehler zurück, Service vollständig ausgefallen
10:05  Vorfall erkannt, Ursachenermittlung begann
10:30  Wiederherstellung aus Snapshot vom Vortag (ein Tag Datenverlust)

Wiederherstellungsverfahren

# 1. Service sofort in den Wartungsmodus versetzen
# nginx: return 503;  oder  Vercel: Wartungsseite

# 2. Aktuellen DB-Zustand prüfen
psql $DATABASE_URL -c "\d users"

# 3. Aus Backup wiederherstellen (für 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. Falls Spalte noch vorhanden, manuell hinzufügen
ALTER TABLE users ADD COLUMN email VARCHAR(255);
UPDATE users SET email = '(Wiederherstellung erforderlich)' WHERE email IS NULL;

# 5. Service wiederherstellen

RCA

  • Direkte Ursache: Der Migrationsskript-Generator verwechselte Up- und Down-Migration
  • Grundursache: Die Migration wurde ohne Test in einer Staging-Umgebung direkt in der Produktion ausgeführt

Prävention

<!-- CLAUDE.md -->
## Pflichtregeln für DB-Migrationen
1. Immer in der Staging-Umgebung testen, bevor die Produktion betroffen wird
2. Immer manuelles Backup vor der Migration erstellen:
   pg_dump $DATABASE_URL > backup_$(date +%Y%m%d_%H%M%S).sql
3. Skripte mit DROP COLUMN / TRUNCATE / DELETE (ohne WHERE) müssen
   immer vom Benutzer bestätigt werden, bevor sie ausgeführt werden
4. Bei Verwendung der Produktions-DATABASE_URL vor der Ausführung anzeigen: 'Schreibe in PRODUKTIONS-DB. Fortfahren?'

Vorfall 5: Unendliche API-Aufrufe erzeugten über Nacht 750 € Kosten

Zeitverlauf

23:00  Anweisung: "Bei Fehlern automatisch wiederholen" und Stapelverarbeitung gestartet
23:01  Externe API begann, 503 zurückzugeben
23:01  Wiederholungslogik lief ohne Limit, traf die API jede Sekunde
07:00  Am nächsten Morgen Benachrichtigung von Anthropic: "Nutzung nähert sich dem Limit"
07:05  28.000 API-Aufrufe und 750 € Kosten festgestellt

Wiederherstellungsverfahren

# 1. Prozess sofort stoppen
pkill -f "node batch-process.js"

# 2. Kosten prüfen und Anthropic-Support kontaktieren
# → Aufrichtige Kommunikation kann zu teilweiser Rückerstattung führen

# 3. Nutzungswarnungen einrichten
# Anthropic-Konsole → Usage Limits → Monatliches Budget-Alert setzen

Prävention

// utils/retry.ts — immer dieses Utility verwenden
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 -->
## Regeln für API-Aufrufe
- Maximal 3 Wiederholungsversuche mit exponentiellem Backoff erforderlich
- while(true) + API-Aufrufe sind streng verboten
- Stapeljobs müssen explizite Mengenlimits haben
- Vor der Produktionsausführung --dry-run Smoke-Test durchführen

Vorfall 6: Defekte Abhängigkeiten nach Deployment legten den Service lahm

Zeitverlauf

15:00  Anweisung: "Pakete auf die neuesten Versionen aktualisieren"
15:01  npm update ausgeführt, package-lock.json änderte sich erheblich
15:05  Lokaler Build erfolgreich
15:10  In Produktion deployt
15:12  Major-Version-Inkompatibilität in Produktionsabhängigkeiten, Start fehlgeschlagen
15:12  503-Fehler, Service vollständig ausgefallen
15:30  Rollback auf vorherige Version abgeschlossen

Wiederherstellungsverfahren

# Bei Vercel / Cloudflare Pages: vorheriges Deployment sofort reaktivieren
# → Ein-Klick-Rollback über das Dashboard

# Code mit git revert zurücksetzen
git revert HEAD~1
git push

# package-lock.json auf vorherige Version zurücksetzen
git checkout HEAD~1 -- package-lock.json
npm ci  # Verwendet streng die package-lock.json

RCA

  • Direkte Ursache: npm update aktualisierte eine Major-Version, was zu einem Breaking Change führte
  • Grundursache: Deployment-Überprüfung in der Staging-Umgebung wurde übersprungen

Prävention

<!-- CLAUDE.md -->
## Paketverwaltungsregeln
- npm update ist verboten (npm update --save-dev bedingt erlaubt)
- Major-Version-Upgrades von Paketen erfordern Benutzerbestätigung
- Vor dem Deployment immer Verhalten in Staging überprüfen
- Nach dem Produktions-Deployment 5 Minuten lang Fehlerprotokolle überwachen

Vorfall 7: Fehlkonfigurierte Berechtigungen machten alle Nutzerdaten öffentlich zugänglich

Zeitverlauf

11:00  Anweisung: "Benutzerliste zum Admin-Panel-API-Endpunkt hinzufügen"
11:05  /api/admin/users ohne Authentifizierungsprüfung implementiert
11:10  In Produktion deployt
11:10  Personenbezogene Daten aller Benutzer für jeden zugänglich
13:30  Sicherheits-Audit-Tool erkannte nicht authentifizierten Endpunkt
13:35  Endpunkt sofort deaktiviert

Wiederherstellungsverfahren

# 1. Betroffenen Endpunkt sofort deaktivieren
# nginx: location /api/admin { return 403; }

# 2. Zugriffsprotokolle prüfen, um den Umfang der Exposition zu bestimmen
grep "/api/admin/users" /var/log/nginx/access.log | \
  awk '{print $1}' | sort | uniq -c | sort -rn

# 3. Betroffene Benutzer benachrichtigen (DSGVO-Anforderungen prüfen)

# 4. Authentifizierungs-Middleware hinzufügen und neu deployen

RCA

  • Direkte Ursache: Die Anweisung „zum Admin-Panel hinzufügen” vermittelte keine Authentifizierungsanforderungen
  • Grundursache: Sicherheitsanforderungen waren nicht in CLAUDE.md dokumentiert

Prävention

<!-- CLAUDE.md -->
## API-Sicherheitsanforderungen
- /api/admin/*-Endpunkte müssen immer Admin-Authentifizierung implementieren
- /api/user/*-Endpunkte müssen immer Login-Authentifizierung implementieren
- Nur /api/public/*-Endpunkte sind ohne Authentifizierung zugänglich
- Beim Hinzufügen einer neuen API die erforderliche Authentifizierungsebene kommentieren

Gemeinsamer Incident-Response-Ablauf (Postmortem-Vorlage)

# Postmortem: [Vorfallstitel]

## Zusammenfassung
- Eingetreten um: YYYY-MM-DD HH:MM
- Erkannt um: YYYY-MM-DD HH:MM
- Behoben um: YYYY-MM-DD HH:MM
- Auswirkung: (Anzahl der Benutzer / Funktionen / Dauer)
- Schweregrad: P0/P1/P2/P3

## Zeitverlauf
| Zeit  | Ereignis |
|-------|----------|
| HH:MM | Vorfall eingetreten |
| HH:MM | Erkannt |
| HH:MM | Reaktion begann |
| HH:MM | Grundursache identifiziert |
| HH:MM | Wiederherstellung abgeschlossen |

## Grundursache
- Direkte Ursache:
- Grundursache:
- Verschlimmernde Ursache:

## Präventionsmaßnahmen
| Maßnahme | Verantwortlicher | Frist |
|----------|-----------------|-------|
|          |                 |       |

## Erkenntnisse

Zusammenfassung: Mindestkonfiguration zur Vorfalleprävention

// Jetzt kopieren und in .claude/settings.json einfügen
{
  "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 erkannt! Abbruch.' && exit 1 || exit 0" }]
      },
      {
        "matcher": "Bash(rm*)",
        "hooks": [{ "type": "command",
          "command": "echo '⚠️ Löschbefehl erkannt. Ausführung in 5 Sekunden. Abbruch mit Ctrl+C.' && sleep 5" }]
      }
    ]
  }
}

Produktionsausfälle entstehen, wenn man die 30 Minuten für die Konfiguration einspart. Alle 7 Vorfälle in diesem Artikel hätten mit einer ordentlichen settings.json und CLAUDE.md verhindert werden können.

Verwandte Artikel

Referenzen

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

Bring deinen Claude-Code-Workflow aufs nächste Level

50 in der Praxis erprobte Prompt-Vorlagen zum direkten Copy-and-paste in Claude Code.

Kostenlos

Kostenloses PDF: Claude-Code-Spickzettel in 5 Minuten

Trag einfach deine E-Mail-Adresse ein – wir senden dir den A4-Spickzettel als PDF sofort zu.

Wir behandeln deine Daten sorgfältig und senden niemals Spam.

Masa

Über den Autor

Masa

Ingenieur, der Claude Code intensiv nutzt. Betreibt claudecode-lab.com, ein Tech-Medium in 10 Sprachen mit über 2.000 Seiten.