12. Nov. 2025·2 Min. Lesezeit

Geheimnisse aus der Git-Historie entfernen nach Leak eines KI-Prototyps

Lerne, wie du Secrets mit git filter-repo oder BFG aus der Git-Historie entfernst, geleakte Keys rotierst und prüfst, dass dein Repo sauber ist, bevor du auslieferst.

Geheimnisse aus der Git-Historie entfernen nach Leak eines KI-Prototyps

Was ein geleaktes Secret in Git wirklich bedeutet

Ein „Secret“ ist alles, das Zugang gewährt, wenn jemand anderes es bekommt: API-Schlüssel, Zugriffstoken, Passwörter, Datenbank-Verbindungsstrings, Signier-Zertifikate und private Schlüssel. Wenn etwas damit angemeldet, eine Karte belastet, Daten gelesen oder Code deployed werden kann, behandle es als Secret.

Wenn ein Secret in Git committed wird, gehört es zur Repository-Historie. Die Datei später zu löschen (oder in .gitignore aufzunehmen) entfernt nicht den früheren Commit, der den Wert noch enthält. Jeder mit Zugriff auf das Repo, ein Fork, einen alten Clone oder eine zwischengespeicherte Kopie kann es noch finden. Darum ist das Entfernen von Secrets aus der Historie eine andere Aufgabe als das Löschen der Datei.

KI-erstellte Prototypen leaken Secrets oft auf vorhersehbare Weise. Ein häufiges Muster ist, während der ersten Einrichtung eine .env-Datei zu committen und sie dann zu vergessen. Ein anderes ist, ein funktionierendes Snippet aus dem Dashboard eines Anbieters ins Quellcodefenster zu kopieren „nur zum Testen“. Debug-Logs können ebenso gefährlich sein, wenn sie Tokens ausgeben und dann zusammen mit allem anderen committed werden.

Was auf dem Spiel steht, ist mehr als bloße Peinlichkeit: unautorisierter Zugang zu Diensten (Datenbanken, Storage, Auth-Anbieter), unerwartete Kosten durch missbrauchte APIs, Offenlegung oder Änderung von Kundendaten und verlorenes Vertrauen, wenn Nutzer oder Partner davon erfahren.

Ein konkretes Beispiel: Ein Prototyp verwendet einen echten Stripe-Key, committet ihn einmal und wechselt später zu einem neuen Key. Selbst wenn der aktuelle Code sauber aussieht, sitzt der erste Key noch in der Historie und wartet darauf, kopiert zu werden.

Erstmal Blut stoppen

Sobald ein Secret in die Git-Historie gelangt, behandle es wie exponiert. Selbst bei einem privaten Repo könnte es bereits von einem Teammitglied geklont, von einem CI-Runner gezogen, im Build-Cache oder von einem KI-Tool gespeichert worden sein. Warte nicht auf Bestätigung — handle, als hätte ein Angreifer es.

Das erste Ziel: mache den geleakten Key nutzlos. Widerrufe, deaktiviere oder lösche ihn so schnell wie möglich. Wenn der Anbieter Scoped-Tokens unterstützt, kannst du die Berechtigungen sofort einschränken als temporären Schritt, plane aber eine vollständige Rotation nach der Bereinigung.

Als Nächstes halte alles an, was den Secret weiter verwenden oder verbreiten könnte. Pausiere CI-Jobs, geplante Workflows, Preview-Umgebungen und Auto-Deploys. Diese holen oft Umgebungsvariablen und erzeugen Logs, die Werte erneut leaken können.

Bevor du die Git-Historie anfasst, bringe das Team auf denselben Stand:

  • Widerrufe oder deaktiviere die exponierte Zugangsdaten.
  • Pausiere CI/Deploys und sage allen, nichts zu pushen, zu mergen oder zu taggen, bis der Plan klar ist.
  • Erfasse den genauen Wert und wo er auftauchte (Dateiname und Commit-Hash), damit du genau das Richtige entfernst.
  • Führe eine private Incident-Notiz: was rotiert wurde, wann, und welche Dienste betroffen sein könnten.

Beispiel: Wenn dein Prototyp einen Stripe-Key committed hat und CI bei jedem Push Tests ausführt, kann die Pipeline weiter mit dem geleakten Key auf Stripe zugreifen und Spuren in Logs hinterlassen. Pausiere die Pipeline, widerrufe den Key und fahre dann mit der Historienumschreibung fort.

Inventar: was bereinigt werden muss

Bevor du die Historie umschreibst, kläre genau, was geleakt wurde und wo es auftaucht. So vermeidest du eine „Bereinigung“, die das eigentliche Problem verfehlt.

Schreibe jeden bekannten geleakten Wert auf: API-Keys, Datenbank-URLs, JWT-Secrets, OAuth-Client-Secrets, Webhook-Tokens. Wenn du nur einen Screenshot oder ein Error-Log hast, extrahiere den genauen Text, wenn möglich.

Ordne dann jedes Secret seinen Fundorten im Repo zu. Schau nicht nur im aktuellen Branch nach. Secrets leben oft in alten Commits, Testdateien, Debug-Output, exportierten Daten und sogar Screenshots.

Gängige Orte sind Varianten von .env, Konfigurationsdateien (wie settings.json oder docker-compose.yml), Logs- und tmp-Ordner, Seed-/Sample-Daten und Docs/Assets, die Screenshots enthalten könnten.

Eine schnelle Suche nach einem bekannten String in deinem Arbeitsverzeichnis:

git grep -n "PASTE_PART_OF_KEY_HERE" -- .

Entscheide, was du entfernen musst:

  • Exakte Strings (am besten, wenn ein Token an mehreren Stellen vorkommt)
  • Ganze Dateien (ideal für .env oder exportierte Daten, die nie in Git gehört haben)
  • Ganze Ordner (z. B. logs/, tmp/, versehentliche Backups)

Beispiel: Ein KI-generierter Prototyp hat möglicherweise .env committed und außerdem eine Produktionsdatenbank-URL in config.ts eingefügt. Das sind zwei Ziele: .env` aus der gesamten Historie entfernen und die genaue URL überall ersetzen.

Erstelle abschließend ein sicheres Backup des Repos, bevor du die Historie umschreibst. Kopiere den gesamten Ordner oder erstelle einen Mirror-Clone, damit du bei Problemen wiederherstellen kannst.

Schritt für Schritt: Bereinigen mit git filter-repo

Wenn du flexible, verlässliche Umschreibungen brauchst (mehrere Branches, Tags, verworrene Historie oder mehr als ein Secret), ist git filter-repo meist die beste Wahl.

Beginne mit einem frischen Clone und mach eine Sicherheitskopie. Schließe offene PRs, die alte Commits wieder einführen könnten.

1) Eine Datei überall entfernen (Beispiel: eine env-Datei)

Wenn ein Prototyp versehentlich .env (oder eine Credentials-JSON) committed hat, purge sie nach Pfad:

git filter-repo --force --invert-paths --path .env

Das schreibt jeden Commit neu und entfernt die Datei überall, wo sie vorkam.

2) Secret-Strings nach Inhalt entfernen oder ersetzen

Wenn Secrets im Code eingebettet sind, nutze eine Replace-Datei. Erstelle replacements.txt so (links ist, was gematcht wird, rechts ist, womit es ersetzt wird):

AKIAIOSFODNN7EXAMPLE==>REMOVED
"api_key": "sk-live-123"==>"api_key": "REMOVED"

Dann ausführen:

git filter-repo --force --replace-text replacements.txt

Bevor du umschreibst, entscheide, welche Branches und Tags du einschließen wirst. Standardmäßig schreibt filter-repo das um, was in deinem lokalen Clone ist, also fetch alles, was du behalten willst (einschließlich Tags) und lösche Branches, die du nicht veröffentlichen willst.

Nach der Umschreibung überprüfe lokal, ob nichts kaputtgegangen ist. Führe Build und Tests aus, starte den Server und mache einen kurzen End-to-End-Check (z. B. einen einfachen Login-Flow). Suche dann erneut nach alten Key-Mustern.

Schritt für Schritt: Bereinigen mit BFG Repo-Cleaner

BFG Repo-Cleaner ist eine gute Wahl, wenn du eine schnelle Bereinigung möchtest, besonders zum Löschen ganzer Dateien wie .env oder creds.json oder zum Ersetzen bekannter Key-Strings.

Vor dem Start erstelle einen Mirror-Clone, damit du alle Refs (Branches und Tags) sicher umschreibst:

# 1) Mirror clone (funktioniert am besten für History-Rewrites)
git clone --mirror <your-repo-url> repo.git
cd repo.git

# 2) Ganze Dateien überall in der Historie entfernen
bfg --delete-files .env
bfg --delete-files creds.json

# 3) Oder geleakten Text ersetzen (mit einer Rules-Datei)
# Zeilen wie: OLD_SECRET==>REMOVED
bfg --replace-text replacements.txt

# 4) Alte Objekte, die BFG unerreichbar gemacht hat, bereinigen
git reflog expire --expire=now --all
git gc --prune=now --aggressive

BFG schreibt Commits um, die das Secret enthielten, und erstellt eine neue Historie, in der diese Blobs oder Strings weg sind. Es rotiert keine Zugangsdaten und kann dich nicht vor Kopien des Repos schützen, die bereits jemand geklont hat.

Validiere das Ergebnis, bevor du etwas pushst. Suche nach exakten Tokens, die verschwinden sollten, prüfe, dass sensible Dateien in keinem Commit mehr existieren, und inspiziere auch Tags.

Die umgeschriebene Historie pushen, ohne Chaos zu verursachen

Ohne Überraschungen deployen
Wir refaktorieren unordentlichen Code und machen ihn bereit für saubere Builds und verlässliche Releases.

Viele Teams werden beim Push überrascht. Das Ziel ist einfach: die bereinigte Historie veröffentlichen und dann verhindern, dass jemand versehentlich die alten Commits wieder einführt.

Koordiniere eine kurze Freeze-Phase (15–60 Minuten), in der niemand pusht, merged oder neue Branches öffnet. Entscheide, was du wirklich umschreiben musst: meist main plus alle langlebigen Branches, die aktiv genutzt werden. Alte Feature-Branches können oft gelöscht statt umgeschrieben werden.

Eine sichere Abfolge:

  • Verkünde die Freeze-Phase und bestätige, dass alle pausiert sind.
  • Lockere vorübergehend Branch-Protection-Regeln, falls sie Force-Pushes blockieren.
  • Force-pushe die umgeschriebenen Branches (und Tags, falls nötig).
  • Aktiviere Branch-Protections sofort wieder.
  • Sage allen genau, wie sie ihre lokalen Klone synchronisieren sollen.

Weil sich Commit-IDs geändert haben, ist in der Regel ein Force-Push nötig. Gib Mitarbeitenden zwei Optionen: neu klonen (einfachste Methode) oder einen Hard-Reset durchführen (schneller, aber leicht fehleranfällig). Beispiel:

git fetch --all --prune
git checkout main
git reset --hard origin/main

Bereinige auch Orte, an denen Secrets gerne hängen bleiben: alte lokale Klone, CI-Caches, Build-Artefakte und gespiegelte Repos.

Zugangsdaten sicher rotieren

Sobald ein Secret committed wurde, behandle es als kompromittiert. Rotieren jede kompromittierte Zugangsdaten, nicht nur diejenige, die den Alarm ausgelöst hat.

Liste alles auf, was Zugang gewähren könnte: API-Keys, Datenbank-Passwörter, Service-Account-Dateien, OAuth-Client-Secrets, JWT-Signatur-Keys, SMTP-Zugangsdaten, Webhook-Signing-Secrets und alle „Test“-Keys, die auf echte Systeme zeigen. Wenn der Prototyp irgendwann Produktion berührt hat, nimm Produktion in den Rotationsplan auf.

Erstelle neue Zugangsdaten mit dem geringstmöglichen Rechtssatz. Bevorzuge gescopedete Tokens und kurze Lebenszeiten, wenn der Anbieter das unterstützt.

Eine sichere Reihenfolge:

  • Erstelle zuerst neue Secrets und deploye sie zu Apps und CI.
  • Aktualisiere Produktion, Staging und lokale Dev-Konfigurationen.
  • Bestätige, dass die App End-to-End funktioniert.
  • Widerrufe alte Secrets zuletzt und überwache Fehler.

Nach der Rotation: halte Secrets dauerhaft aus dem Repo. Nutze die Variablen der Hosting-Plattform oder einen echten Secret-Store und bewahre lokale Secrets in einer nicht committeten env-Datei auf. Füge Schutzmaßnahmen wie einen Pre-Commit-Secret-Scan und CI-Prüfungen hinzu.

Führe eine einfache Dokumentation, was geändert wurde, wann, wo der neue Wert gespeichert ist und wer dafür verantwortlich ist.

Verifiziere, dass das Repo wirklich sauber ist

Schnelle Incident-Triage
Nicht sicher, was geleakt wurde oder wie weit es sich ausgebreitet hat? Wir helfen beim Triage und Planen der nächsten Schritte.

Geh davon aus, dass du nicht fertig bist, bis du nachgewiesen hast, dass das Leak überall verschwunden ist, wo ein Entwickler es fetchen könnte.

Suche nach dem genauen geleakten Wert, nicht nur nach dem Dateinamen. Führe die Suche über alle Refs (Branches und Tags) aus, nicht nur über den aktuellen Branch.

git fetch --all --tags --prune

git grep -n "PASTE_LEAKED_VALUE_HERE" $(git rev-list --all)

Mache anschließend einen breiteren Scan nach typischen Secret-Formaten. Achte auf private Keys (BEGIN PRIVATE KEY), lange base64-ähnliche Strings, JWTs (drei durch Punkte getrennte Abschnitte) und Anbieter-spezifische Präfixe, die du kennst.

Vergiss nicht CI-Logs und Build-Artefakte. Selbst wenn das Repository sauber ist, kann ein geleaktes Secret noch in CI-Logs, gecachten Docker-Layern oder hochgeladenen Artefakten liegen. Führe nach der Rotation die letzte Pipeline erneut aus, um sicherzustellen, dass Logs keine sensiblen Werte mehr ausgeben.

Mach schließlich einen Frisch-Clone-Test von der Remote in einen neuen Ordner oder auf einer sauberen Maschine. Ein Repo kann lokal sauber aussehen, während ein alter Remote-Ref das Secret noch exponiert.

mkdir /tmp/clean-test && cd /tmp/clean-test
git clone <your-remote>
cd <repo>
git log --all -S "PASTE_LEAKED_VALUE_HERE" --oneline

Wenn du nach einer Umschreibung noch Spuren findest, liegt das meist daran, dass ein Tag, ein Remote-Branch oder ein CI-Artefakt weiterhin den alten Inhalt hält.

Häufige Fehler, die Secrets zurückbringen

Die meisten Leaks kehren zurück, weil die Bereinigung nur halbherzig durchgeführt wurde. Eine Datei im neuesten Commit zu löschen ist nicht dasselbe wie sie aus der Historie zu entfernen. Wenn jemand noch einen alten Commit auschecken kann, ist das Secret weiterhin exponiert.

Zwei häufige Versäumnisse:

  • Tags und alte Branches vergessen. Ein Secret kann auf main weg sein, aber noch in einem Release-Tag oder einem veralteten Branch existieren.
  • Die Datei entfernen, aber nicht den Wert. KI-Prototypen kopieren oft denselben Key an mehreren Stellen: Konfigurationsdateien, Testfixtures, Build-Skripte und Logs.

Eine weitere häufige Ursache ist, dass ein Teammitglied aus einem alten Clone pusht, nachdem die Historie umgeschrieben wurde. Koordiniere einen Zeitpunkt, an dem alle neu klonen oder zurücksetzen, und blockiere Merges bis dahin.

Beispiel: Leak in einem KI-Prototyp und ein realistischer Bereinigungsplan

Eine typische Geschichte: Eine Gründerperson baut schnell einen Prototyp in Lovable oder Replit und committet alles, ohne zu merken, dass eine .env-Datei mitgerutscht ist. Die Demo funktioniert, und dann fällt etwas auf.

Das Erste, was sich zeigt, sind oft reale Folgen: eine nächtliche Cloud-Kostenexplosion, merkwürdige Login-Warnungen vom Mail-Anbieter oder ein API-Dashboard, das Traffic aus Ländern zeigt, die man nicht bedient.

Ist das Repo öffentlich, gehe davon aus, dass die Keys bereits kopiert wurden. Rotieren die Zugangsdaten sofort, dann schreibe die Git-Historie um, um die Datei und alle eingefügten Tokens zu entfernen. Ist das Repo privat, mache dasselbe und prüfe zusätzlich, wer Zugriff hatte (ehemalige Auftragnehmer, geteilte Maschinen, CI-Logs).

Weißt du nicht, welcher Key geleakt wurde, handle so, als wären alle betroffen. Liste jedes System auf, das der Prototyp berührt hat (Datenbank, Auth-Anbieter, Zahlungsanbieter, E-Mail, Storage) und rotiere in einer Reihenfolge, die dich nicht aussperrt.

Ein realistischer Plan:

  • Freeze Deploys und CI pausieren, damit sich der Wert nicht weiter verbreitet.
  • Rotieren der gefährlichsten Zugangsdaten zuerst (Cloud-Admins, Datenbank, Payment-Keys).
  • Historie umschreiben, .env und alle committeten Tokens entfernen, dann force-push.
  • App so umstellen, dass sie Secrets nur noch aus sicheren Konfigurationen liest (Env-Variablen oder ein Secret-Manager).
  • Ergebnis mit einem frischen Clone und Voll-Historien-Scans verifizieren.

Kommunikation ist wichtig. Informiere Stakeholder in klaren Worten, was passiert ist, was exponiert wurde, was rotiert wurde und was du verifiziert hast. Gib eine kurze Timeline und eine klare Anweisung, was sich für sie ändert.

Schnelle Checkliste, bevor du wieder entwickelst

Spaghetti-Codebase entwirren
Wenn das Repo verheddert ist, entwirren wir es und bringen dein Team wieder in Fahrt.

Nach einem Leak ist das Ziel eindeutig: mache das gestohlene Secret nutzlos, lösche es aus der Historie und beweise, dass es weg ist, bevor neue Arbeit passiert.

  • Widerrufe zuerst, dann pausieren. Deaktiviere den geleakten Key/Token sofort und stoppe Pushes während der Bereinigung.
  • Inventar erstellen. Liste jeden Dateinamen und jedes Muster, das Zugangsdaten enthalten könnte.
  • Ein Werkzeug wählen und einmalig die Historie umschreiben. Nutze git filter-repo oder BFG auf einem frischen Clone.
  • Neue Historie pushen und Mitarbeitende zurücksetzen. Force-pushe umgeschriebene Branches/Tags, dann neu klonen (oder hard reset).
  • Rotieren und umziehen. Erstelle neue Zugangsdaten, entferne Secrets aus dem Repo und füge Prüfungen hinzu, um Wiederholungen zu verhindern.

Mache eine letzte Bestätigung: klone in einen brandneuen Ordner und scanne diesen frischen Clone. Wenn der Scan sauber ist und die App mit den neuen Zugangsdaten läuft, bist du wieder auf einem sicheren Basislevel.

Nächste Schritte, wenn das Repo chaotisch ist oder die App schon kaputt

Manchmal ist das Problem größer als ein History-Replace. Wenn das Repo verworren ist, der Build nach der Umschreibung fehlschlägt oder du gar nicht weißt, was geleakt wurde, kann man Tage mit Git-Operationen verschwenden, während die App instabil bleibt.

Zeichen, dass es Zeit für Hilfe ist: mehrere Repos und Forks, die du nicht nachverfolgen kannst, Secrets, die in vielen generierten Dateien dupliziert sind, Deploys, die nach der Umschreibung fehlschlagen, vermutete Mehrfach-Leaks oder ein Codebase, das sich schwer sicher verändern lässt (Spaghetti-Struktur, keine Tests, zufällige KI-Änderungen).

Wenn du einen KI-generierten Prototyp geerbt hast, ist das genau das, wofür FixMyMess (fixmymess.ai) gebaut wurde: das Codebase und die Historie diagnostizieren, Logik- und Sicherheitsprobleme (wie kaputte Auth oder exponierte Secrets) reparieren und die App bereit machen, sauber zu deployen. Sie bieten ein kostenloses Code-Audit an, um die Expositionen zu kartieren, bevor du dich zu Änderungen verpflichtest; die meisten Reinigungsarbeiten sind innerhalb von 48–72 Stunden erledigt.

Häufige Fragen

Wenn ich die `.env`-Datei gelöscht habe, warum ist das Secret immer noch „geleakt“?

Das bedeutet, dass das Secret jetzt in der Historie des Repositories liegt, nicht nur in den aktuellen Dateien. Selbst wenn du die Datei löschst oder sie zu .gitignore hinzufügst, kann jede Person, die einen alten Commit, ein Fork oder einen früheren Clone hat, den Wert noch abrufen.

Was sollte ich zuerst tun, wenn ich ein Secret in der Git-Historie entdecke?

Deaktiviere oder widerrufe die exponierte Zugangsdaten sofort, damit der geleakte Wert nicht mehr funktioniert. Pausiere dann CI/Deploys, die es weiterverwenden oder protokollieren könnten, und schreibe erst danach die Git-Historie um, um das Secret aus vergangenen Commits zu entfernen.

Ist es immer noch gefährlich, wenn das Repo privat war?

Ja. Private Repositories werden trotzdem kopiert: durch Klone von Teammitgliedern, CI-Runner, Build-Caches, gespiegelte Repos und gemeinsam genutzte Maschinen. Behandle jedes in Git committete Secret als kompromittiert und rotiere es, auch wenn du denkst, der Zugriff war begrenzt.

Soll ich `git filter-repo` oder BFG Repo-Cleaner verwenden?

Für die meisten Fälle ist git filter-repo die sicherere Standardwahl, weil es bei mehreren Branches, Tags und komplizierten Historien flexibel ist. BFG ist schneller und einfacher, wenn du ganze Dateien löschen oder bekannte Textstrings ersetzen willst. In beiden Fällen musst du Tags validieren und anschließende Aufräumschritte durchführen.

Warum muss ich nach der Bereinigung einen Force-Push machen?

Weil das Umschreiben der Historie die Commit-IDs ändert, ist ein Force-Push notwendig, um die bereinigten Commits zu veröffentlichen. Plane eine kurze Freeze-Phase, pushe die umgeschriebenen Branches/Tags einmalig per Force-Push und sorge dafür, dass alle danach neu klonen oder ihre lokalen Kopien zurücksetzen, damit niemand versehentlich die alten Commits zurückschiebt.

Wie kann ich bestätigen, dass das Secret nach dem Umschreiben wirklich weg ist?

Suche über alle Refs, nicht nur im aktuellen Branch, und suche nach dem genauen geleakten Wert sowie nach typischen Secret-Formaten. Mache dann einen frischen Clone in einen neuen Ordner und suche noch einmal — ein frischer Clone ist die einfachste Methode, um entfernte Branches oder Tags zu entdecken, die das Secret noch enthalten können.

Wenn ich den Key rotiere, muss ich ihn trotzdem aus der Git-Historie entfernen?

Ja. Rotation macht den gestohlenen Wert nutzlos; das Bereinigen der Git-Historie verhindert, dass er später wiedergefunden oder versehentlich wiederverwendet wird. Beide Schritte gehören zusammen: Rotation für die Sofortmaßnahme, Historienbereinigung, um künftige Entdeckung zu verhindern.

Was bringt Secrets nach einer Bereinigung meist zurück?

Das passiert oft, wenn nur main bereinigt wurde und Tags oder veraltete Branches übersehen wurden. Ebenso häufig ist, dass ein Teammitglied aus einem alten Clone pusht und so das Secret wieder einführt. Koordiniere einen Moment, in dem alle neu klonen oder ihre Kopien zurücksetzen.

Wie verhindere ich, dass KI-generierte Prototypen wieder Secrets leaken?

Commitiere keine .env-Dateien und lade Secrets aus Umgebungsvariablen oder einem Secret-Store deiner Hosting-Plattform. Füge Pre-Commit-Scans auf Secrets und CI-Checks hinzu, damit ein eingefügtes Token oder Debug-Log nicht in einen Commit rutscht.

Kann FixMyMess helfen, wenn das Repo verheddert ist oder ich befürchte, etwas kaputt zu machen?

Ja. Wenn das Codebase unordentlich ist, Builds nach dem Umschreiben fehlschlagen oder Secrets in vielen generierten Dateien dupliziert sind, kann ein History-Rewrite riskant und zeitaufwändig werden. FixMyMess (fixmymess.ai) kann das Repository auditieren, herausfinden, wo Secrets exponiert wurden, die Historie sicher bereinigen, Zugangsdaten rotieren ohne Deploys zu brechen und die App schnell wieder bereit für Deploys machen.