Irgendwo in einem öffentlichen GitHub-Repository liegt ein Produktions-Passwort für eine Datenbank in einer JSON-Datei. Es liegt dort seit 217 Tagen. Niemand hat es absichtlich hingeschrieben. Es kam dorthin, weil ein Entwickler einen KI-Coding-Agenten gefragt hat, warum der Staging-Login fehlschlägt, der Agent den naheliegenden Befehl vorgeschlagen hat und der Entwickler auf "Ja, und nicht mehr fragen" geklickt hat.
Dieser Klick ist die ganze Geschichte.
Am 6. November veröffentlichte das Sicherheitsunternehmen Apiiro eine Untersuchung, die zeigt: Genau dieses Muster hat 2.539 echte Secrets in 1.994 öffentlichen GitHub-Repositories hinterlassen. Darunter der Admin-Cloud-Schlüssel eines Datenbankherstellers ohne Ablaufdatum, ein Produktions-Postgres-Passwort in Azure, ein Square-Produktionstoken und das Eigentümer-Passwort einer Datenbank für Patientenakten. Dreiundsechzig Organisationen, überwiegend Softwarefirmen, haben mindestens eine lebende Zugangsdaten in einer öffentlichen Allowlist. Eine Firma bestätigte, dass ihr Schlüssel noch funktionierte, als die Forscher anriefen.
Das ist kein Modellproblem. Es ist ein Produktverhalten, und es trifft Teams, die dachten, sie seien vorsichtig.
Der Mechanismus ist drei Wörter lang
Claude Code fragt nach, bevor es einen Shell-Befehl ausführt. Das ist die Schutzplanke, und sie ist vernünftig. Aber die Abfrage bietet eine Option: "Ja, und nicht mehr fragen". Wählst du sie, schreibt Claude Code eine Berechtigungsregel in .claude/settings.local.json im Projektordner. Die Regel ist der Befehl, Wort für Wort.
Lautete der Befehl PGPASSWORD=hunter2 psql -h prod-db.internal -U admin, dann lautet die Regel PGPASSWORD=hunter2 psql -h prod-db.internal -U admin. Der Agent hat nicht beschlossen, dein Passwort zu speichern. Er hat deinen Befehl gespeichert, und dein Befehl enthielt dein Passwort.
Apiiro hat das mit Anthropics neuesten Modellen reproduziert, Opus 5.5 und Fable 5.1. Es ist das umgebende Werkzeug, nicht die Reasoning-Schicht. Von sechzehn Coding-Agenten, deren Dokumentation die Forscher verglichen haben, ist Claude Code der einzige, bei dem bestätigt ist, dass er den vollständigen genehmigten Befehl standardmäßig in einer Projektdatei ablegt.
Der Schutz existiert, aber er reist nicht mit
Hier wird es interessant — und hier hören die meisten Analysen einen Schritt zu früh auf.
Claude Code versucht durchaus, diese Datei aus git herauszuhalten. Beim ersten Schreiben innerhalb eines Repositories trägt es sie in deine globale git-Exclude-Liste ein. Auf deiner Maschine, in deiner git-Konfiguration, ignoriert git diesen Pfad danach in jedem Repository, das du anfasst. Das ist ehrlich durchdachte Technik.
Es ist auch Technik, die den Kontakt mit der Realität nicht übersteht.
Globale Excludes liegen in der Konfiguration eines Nutzers auf einem Laptop. Sobald die Datei bereits committet ist, bewirkt der Exclude nichts. Er schützt keinen Klon auf dem Rechner einer Kollegin, keinen Ordner, der erst später zum Repo wird, und keinen Fork. Und Claude Code trägt den Pfad nie in die .gitignore des Projekts selbst ein. Der Schutz ist also kein Teil des Repositories. Er reist nie mit dem Code.
Schlimmer: In 539 der 1.105 Repositories mit bestätigtem Secret war es ein von Claude mitverfasster Commit, der die Datei verändert hat. Der Agent hat, wie Agenten das tun, die Arbeit committet. Zur Arbeit gehörte seine eigene Berechtigungsliste.
Was die Zahlen wirklich sagen
Apiiro hat 104.185 öffentliche Kopien von .claude/settings.local.json in 103.617 Repositories gescannt. 1.122 davon (etwa 1,1 %) enthalten ein echtes Secret: insgesamt 1.379 verschiedene Zugangsdaten. Die Aufschlüsselung lohnt sich:
- 379 Datenbank-Passwörter und 122 Supabase-Service-Role-Keys, die eine Datenbank direkt öffnen
- 103 Supabase-Account-Tokens, die jedes Projekt in diesem Account kontrollieren
- 43 SSH-Zugänge zu öffentlichen Servern, mehrere davon root per
sshpass - 42 GitHub-, GitLab- und npm-Tokens, 23 AWS-Keys, 6 private Schlüssel
Mehr als ein Drittel der exponierten Zugangsdaten öffnet eine Datenbank. Das sind keine Tokens, die du quartalsweise rotierst. Das sind die Kronjuwelen, in einer Datei mit einem freundlichen Namen.
Die Größe korreliert brutal mit dem Risiko: Eine von zehn Dateien über 8 KB enthält ein echtes Secret, gegenüber weniger als einer von fünfhundert unter 500 Byte. Je länger jemand "nicht mehr fragen" klickt, desto schwerer wird die Datei. Die mittlere exponierte Datei wurde 217 Tage vor der Entdeckung zum ersten Mal committet. In 118 Repositories liegt sie seit über einem Jahr.
Löschen hilft auch nicht. Frühere Versionen enthalten weitere 734 Secrets in 509 Repositories, die in keiner aktuellen Kopie auftauchen — meistens, weil jemand die Datei irgendwann doch gelöscht hat. Forks verschlimmern es: 211 Forks von 74 Repositories tragen dieselben Secrets wie das Original. Das ist die klassische git-Eigenschaft, die alle beim ersten Mal überrascht: Ein committetes Secret ist ein dauerhaftes Secret, und ein dauerhaftes Secret in einem öffentlichen Repo ist ein veröffentlichtes Secret.
Dein Secret-Scanner hat es wahrscheinlich übersehen
Das ist der Teil, den Sicherheitsteams hören müssen. Apiiro hat gitleaks und TruffleHog über alle 104.185 Dateien laufen lassen. Von den 1.122 mit einem echten Secret markierte gitleaks 564 und TruffleHog 643. 215 wurden von keinem der beiden markiert.
Der blinde Fleck sind Passwörter in Befehlen. Scanner sind auf Schlüsselformate geeicht: ein Provider-Präfix, eine lange Zufallszeichenfolge, eine Entropieschwelle. Ein Passwort nach PGPASSWORD=, sshpass -p, mysql -p oder in einem Bearer-Header in einem curl-Aufruf ist einfach ein gewöhnliches Wort in einer gewöhnlichen Kommandozeile. Es sieht aus wie Shell, weil es Shell ist.
Und das Muster bleibt nicht bei einer Datei. Dieselbe Untersuchung fand Secrets in:
- der geteilten
.claude/settings.json, die Teams absichtlich committen (298 von 76.011 Dateien) - Agent-Chat-Transkripten aus
.specstory, Aider und Cursor-Exporten (120 Dateien in 87 Repositories) - Agent-Memory-Dateien wie
MEMORY.md(9 Repositories) - Übergabe- und Deploy-Notizen (33 Dateien, ein Drittel davon vom Agenten selbst geschrieben)
- VS-Code-Copilot-Auto-Approve-Einstellungen (9 Repositories)
Die Gewohnheit, die leckt, ist überall dieselbe: Ein Mensch tippt ein Secret in einen Befehl, und ein Agent protokolliert den Befehl treu und brav.
Was zu tun ist, in dieser Reihenfolge
Erst rotieren. Dann aufräumen. Diese Reihenfolge ist keine Vorliebe, sondern die einzige, die funktioniert: Sobald eine Zugangsdaten einen öffentlichen Commit berührt, gehört sie jedem, der ihn gelesen hat, und die Historie erinnert sich.
- Suche die Datei in deiner Organisation. Durchsuche GitHub nach
.claude/settings.local.jsonund.claude/settings.jsonin allen Repositories und prüfe die git-Historie auch dort, wo die Datei heute fehlt. - Rottiere alles, was die Datei je enthalten hat — Passwörter, Tokens, Keys, Connection Strings — bevor du mit dem Löschen anfängst.
- Untracken und ignorieren.
git rm --cached .claude/settings.local.jsonund dann in die.gitignoredes Repositories selbst eintragen, nicht nur in die globale. - Öffne die Datei auf deinem eigenen Laptop, committet oder nicht, und lösche jede Regel, die ein Secret enthält. Die meisten dieser Dateien haben GitHub nie berührt und liegen weiterhin als Klartext auf der Platte.
- Keine Secrets mehr in Befehle schreiben. Verweise auf
$DB_URLaus einem Secrets Manager, damit die gespeicherte Regel einen Variablennamen enthält und keine Zugangsdaten. - Muster genehmigen, keine Befehle.
Bash(npm run:*)ist eine Regel.npm run deploy --token abc123ist ein Leck.
Für Sicherheitsteams vier Ergänzungen: Behandle .claude/, .cursor/, .gemini/, .specstory/ und Agent-Memory-Dateien wie .env — als Pfade, die Secrets tragen, auf Laptops wie in Repositories. Nimm sie in Pre-Commit- und CI-Scans auf, Historie inklusive. Setze .claude/settings.local.json in die .gitignore-Vorlage deiner Organisation. Und priorisiere Zugangsdaten, die mit der Adresse eines öffentlichen Hosts gepaart sind — die geben Zugriff von überall.
Das Fazit, das wir immer wieder sagen
Die Lehre ist nicht "KI-Agenten sind gefährlich". Anthropics Berechtigungsmodell ist vernünftig, und der globale Exclude von Claude Code zeigt, dass jemand an genau diesen Fehler gedacht hat. Die Lehre ist: Bequemlichkeitseinstellungen werden stillschweigend zu Speicher. Jedes "nicht mehr fragen" ist ein Datensatz. Jeder Datensatz hat einen Pfad. Und jeder Pfad landet irgendwann in einem Repository, einem Archiv, einer Docker-Schicht oder einem synchronisierten Ordner.
Wenn dein Team seit einem Jahr mit Coding-Agenten arbeitet, hast du fast sicher ein .claude/-Verzeichnis, das älter ist als jede Policy, die du seither geschrieben hast. Lies es. Nicht die Repository-Version — die auf dem Laptop vor dir. Und dann schau nach, was die Scanner dazu gesagt haben, und geh davon aus, dass sie nichts gesagt haben.
Der Befehl, den du einmal bestätigt hast, hält dein Passwort noch. Er hält es, bis du es rotierst.