← Zurück zu allen Beiträgen
Veröffentlicht am · von Renaud Deraison

Die Allow-Regel behielt das Passwort

Am 6. November berichtete Apiiro, dass der Button „Yes, and don't ask again“ in Claude Code den freigegebenen Befehl samt Secrets in .claude/settings.local.json speichert und dass 1.122 öffentliche GitHub-Repositories diese Datei mit echt aussehenden Passwörtern, Tokens und Schlüsseln committet hatten. Zwei verbreitete Secret-Scanner übersahen 215 davon. In Bromure Agentic Coding ist jedes Secret, das der Agent tippen kann, ein Platzhalter: Eine gespeicherte Regel enthält einen Wert, der nirgends funktioniert, und jeder Push wartet auf dem Mac auf Sie.

Sie klicken auf „Yes, and don't ask again“, damit eine Abfrage nicht wiederkommt. Claude Code speichert den ganzen Befehl, um ihn beim nächsten Mal wiederzuerkennen, samt Passwort, in einer Datei in Ihrem Projekt.

Am 6. November veröffentlichte Apiiro eine Untersuchung zu Coding-Agenten, die über „don't ask again“ Secrets preisgeben. The Hacker News berichtete am nächsten Morgen darüber.

Der Mechanismus ist unspektakulär. Wenn Claude Code einen Shell-Befehl ausführen möchte und Sie Yes, and don't ask again wählen, schreibt es eine Allow-Regel in .claude/settings.local.json im Projekt. Manchmal ist die Regel ein Muster wie npm test *. Manchmal ist es der exakte Befehl, und wenn dieser ein Passwort nach PGPASSWORD=, sshpass -p oder mysql -p enthielt, steht das Passwort jetzt in einer JSON-Datei neben Ihrem Code.

Apiiro durchsuchte das öffentliche GitHub nach dieser Datei und fand:

  • 104.185 Kopien in 103.617 Repositories;
  • 1.122 Kopien mit mindestens einem Secret, insgesamt 1.379 verschiedene Secrets;
  • 379 Datenbankpasswörter, 43 SSH-Logins für öffentliche Server, 42 GitHub-, GitLab- und npm-Tokens und 23 AWS-Schlüssel;
  • Secrets von 63 Organisationen, darunter ein Cloud-Schlüssel mit Admin-Rechten eines Datenbankanbieters und das Owner-Passwort einer Datenbank mit Patientenakten.

Jede dieser Dateien lag noch auf dem Default-Branch, als Apiiro nachsah. In der Hälfte der Repositories lag sie dort seit mindestens 217 Tagen. Ältere Commits enthielten 734 weitere Secrets in 509 Repositories, und 211 Forks von 74 Repositories trugen Kopien. Rechnet man die geteilte .claude/settings.json, die History und gespeicherte Agenten-Chatlogs dazu, kam Apiiro auf 2.539 Secrets in 1.994 Repositories.

Ein Klick, vier Schritte zum öffentlichen SecretFreigabeabfragePGPASSWORD=s3cr3t psql-h db.example.com …"Yes, and don't ask again"Allow-Regel gespeichert.claude/settings.local.jsonder ganze Befehl, im KlartextCommittet539 / 1.105verfolgte Repos, in denen einCommit von Claude sie änderteÖffentlich auf GitHub1.122Kopien mit Secrets; Hälfteseit 217 Tagen oder mehrDie Datei zu löschen löscht nicht das Secret734 weitere Secrets in älteren Commits von 509 Repositories; 211 Forks von 74 Repositories tragen dieselben Werte
Wie ein Passwort von einer Freigabeabfrage in ein öffentliches Repository gelangt. Die Allow-Regel speichert den exakten Befehl. Der Agent committet den Projektordner, die Datei geht mit, und jeder Fork und jeder alte Commit behält eine Kopie, nachdem der Default-Branch bereinigt ist.

Warum es an allem vorbeikam

Claude Code versucht durchaus, die Datei aus git herauszuhalten. Wenn es settings.local.json zum ersten Mal schreibt, trägt es die Datei in Ihre globalen git-Excludes ein. Diese Regel lebt auf einem einzigen Rechner. Der Laptop eines Kollegen, ein CI-Runner oder ein frischer Clone kennen sie nicht, und für eine bereits committete Datei bewirkt sie nichts. In die eigene .gitignore des Projekts trägt Claude Code die Datei nie ein. Von 16 Coding-Agenten, die Apiiro verglichen hat, speichert nachweislich nur Claude Code standardmäßig den vollständigen freigegebenen Befehl in einer Projektdatei.

Die Secret-Scanner schnitten nicht besser ab. Apiiro ließ gitleaks und TruffleHog über jede Kopie laufen. Gitleaks meldete 564 der 1.122 Dateien, TruffleHog 643, und 215 entgingen beiden. Die meisten dieser 215 waren Passwörter, die in Befehle getippt worden waren. Scanner suchen nach bekannten Schlüsselformaten wie AKIA… oder ghp_…, und sshpass -p hunter2 passt auf keines davon.

Nutzer haben das Problem vor über einem Jahr gemeldet. Ein Issue vom August 2025, anthropics/claude-code#5544, beschrieb, dass Claude Code freigegebene Befehle mit API-Schlüsseln wörtlich in dieser Datei speicherte. Ein Bot schloss es nach 60 Tagen ohne Aktivität als „not planned“. Vier verwandten Meldungen erging es mit demselben Bot genauso, die jüngste einen Tag vor dem Artikel von The Hacker News.

Das Secret stand im Befehl, weil der Agent es in der Hand hatte

Jedes dieser 1.379 Secrets war ein Wert, den der Agent tippen konnte. Ein Entwickler hatte ihn in den Chat kopiert oder in einer .env-Datei liegen lassen, oder der Agent las ihn aus ~/.aws/credentials oder ~/.pgpass und setzte ihn direkt in den Befehl ein, den er ausführen wollte. Die Allow-Regel schrieb nur auf, was der Agent schon hatte.

Apiiros Rat für die Zukunft geht in dieselbe Richtung: Secrets aus Befehlen heraushalten und auf eine Variable aus einem Secrets-Manager verweisen, damit die gespeicherte Regel nur $DB_URL enthält. Das hilft, wenn sich jeder Entwickler und jeder Agent jedes Mal daran hält. Ein Agent, der einen fehlschlagenden Befehl zum Laufen bringen will, wird die Variable expandieren. Bromure geht den anderen Weg und hält den echten Wert ganz aus der Umgebung des Agenten heraus.

Derselbe Klick in Bromure Agentic Coding

Bromure Agentic Coding betreibt Claude Code, Codex, Grok, Kimi und omp in Ubuntu-VMs auf Ihrem Mac. Der Agent erhält Zugangsdaten über das, was wir die Grenze auf der Leitung nennen: In der VM ist jedes Secret ein Platzhalter, und der echte Wert liegt verschlüsselt auf dem Mac, mit seinem Hauptschlüssel im macOS-Schlüsselbund. Ein Proxy auf dem Mac tauscht den Platzhalter auf der Leitung gegen den echten Wert, und zwar nur bei einer Anfrage an den Host, zu dem diese Zugangsdaten gehören.

Wenn der Agent also einen Befehl mit einem Token darin ausführen will und Sie Yes, and don't ask again wählen, speichert Claude Code den Befehl genau wie zuvor. Das Token darin ist der Platzhalter.

Jedes Secret, das der Agent tippen kann, ist ein Platzhalter

Platzhalter behalten die Form, die Werkzeuge erwarten, also ändert sich im Projekt nichts:

Was laut Apiiro geleakt wurdeWas der Agent in einer Bromure-Maschine hat
GitHub- und GitLab-Tokensghp_ + 36 Zeichen, glpat- + 20, in GH_TOKEN, GITLAB_TOKEN und ~/.git-credentials
npm-Tokenseinen brm_…-Wert in NPM_TOKEN, aus einem Other API key-Eintrag für registry.npmjs.org
AWS-Schlüsseldie echte Access-Key-ID mit einem falschen Secret Key; der Mac signiert jede Anfrage mit dem echten neu
Datenbankpasswörtereinen brm-db-…-Wert in der Variable Ihrer Wahl, für ClickHouse, die Mongo Data API und Elasticsearch
SSH-Loginsüberhaupt kein Passwort: Signaturen von Schlüsseln, die auf dem Mac bleiben

Nehmen wir einen Befehl, den ein Agent gegen einen ClickHouse-Endpunkt ausführen könnte:

curl -u default:brm-db-7Qk2…Xw9 \
  'https://analytics.example.com:8443/?query=SELECT+count()+FROM+events'

Geben Sie ihn dauerhaft frei, und die Allow-Regel enthält brm-db-7Qk2…Xw9. Der Proxy tauscht den Platzhalter bei Anfragen an analytics.example.com aus, im Basic-Auth-Header und im Request-Body, denn Datenbank-Secrets reisen oft in SQL und JSON mit. Überall sonst ist die Zeichenkette nutzlos.

Bei AWS erreicht das Secret die VM nie. Die ~/.aws/config des Agenten verweist auf ein Hilfsprogramm, das die echte Access-Key-ID mit einem falschen Secret von 40 Zeichen ausgibt. AWS CLI, boto3 und terraform signieren mit dem falschen, und der Mac entfernt diese Signatur und signiert mit dem echten Secret neu, bevor die Anfrage hinausgeht. Der echte Secret Key existiert in der VM nie, also kann kein Befehl, den der Agent schreibt, ihn enthalten.

SSH deckt die 43 Server-Logins in Apiiros Zählung ab. Der SSH_AUTH_SOCK einer Bromure-Maschine ist eine Brücke zum Mac: Die VM kann Signaturen anfordern, und die Bytes des privaten Schlüssels gelangen nie hinüber. Schlüssel hinter einem YubiKey, Secretive oder 1Password lassen sich einzeln freigeben, mit der Berührungsabfrage auf Ihrem Mac. Der Agent braucht nie sshpass -p, also gibt es kein Passwort, das eine Allow-Regel speichern könnte.

VM der MaschineFreigegebener BefehlGH_TOKEN=ghp_Xk3…a7Q gh api …"Yes, and don't ask again"settings.local.jsonenthält den Platzhalter, der nurüber den Proxy dieses Macs gehtgit pushder Commit enthält die DateiIhr MacProxy tauscht auf der LeitungPlatzhalter → echtes Token, nurbei Anfragen an github.comEchte Werte, im SchlüsselbundTokens, AWS-Secrets, SSH-Keys:nie in der VM, in keiner FormPrompt before writeder Push wartet auf Ihre AntwortDas Internetapi.github.comerhält das echte Token, derBefehl läuft wie gewohntJemand kopiert die Dateiaus Repo, Fork oder altemCommit und probiert das Token:401 Bad credentials
Derselbe Klick in einer Bromure-Maschine. Die Allow-Regel speichert weiterhin den Befehl, aber das Token darin ist ein Platzhalter. Der Push, der es veröffentlichen würde, wartet auf einen Dialog auf dem Mac, und ein von GitHub kopierter Platzhalter scheitert überall, weil nur der Proxy auf Ihrem Mac ihn in den echten Wert verwandeln kann.

Ein Platzhalter auf GitHub öffnet nichts

Angenommen, die Datei landet doch in einem öffentlichen Repository, einem Fork und einem Dutzend alter Commits. Wer sie abgreift, bekommt ghp_ und 36 Zeichen, die GitHub nie ausgestellt hat. Von seinem Laptop aus gesendet, scheitert er an der Authentifizierung. Nur der Proxy auf Ihrem Mac weiß, auf welches echte Token er abbildet, und dieser Proxy bedient nur die VM Ihrer Maschine.

Geht ein Platzhalter aus der Maschine heraus jemals an den falschen Host, behandelt der Proxy das als Exfiltrationsversuch. Er blockiert die Anfrage mit HTTP 451, pausiert die VM und öffnet eine Warnung mit dem Titel This environment may have been compromised, die die Zugangsdaten nennt, den Host, zu dem sie gehören, und den Host, an den sie gingen. So ist jeder Platzhalter zugleich ein Stolperdraht.

Rotiert wird an einer Stelle

Apiiros erste Anweisung lautet, jedes Passwort, jedes Token und jeden Schlüssel zu rotieren, den die Datei je enthielt, bevor man irgendetwas aufräumt. Mit echten Secrets verstreut über .env-Dateien, Shell-History und Agenten-Konfiguration ist das eine Suche. In Bromure liegen die echten Werte an einer Stelle: im Credentials-Bereich der Maschine auf dem Mac. Fügen Sie dort das neue Token ein, und der Platzhalter in der VM bleibt derselbe, sodass Allow-Regeln, Skripte und Konfigurationen in der Maschine weiter funktionieren.

Ein Other API key kann auch eine 1Password-Referenz wie op://Engineering/npm/token sein. Bromure löst sie auf dem Mac auf und löst sie alle 2 Minuten neu auf, sodass ein in 1Password rotierter Schlüssel binnen weniger Minuten greift, ohne Neustart und ohne etwas in der VM zu ändern.

Secrets in diesen Bereich zu verschieben ist ein Schritt. Import env file… liest eine vorhandene .env oder ~/.bashrc, zeigt die Variablen mit maskierten Werten und macht daraus Zugangsdaten. Der Projektordner braucht die .env-Datei nicht mehr, aus der der Agent Passwörter las.

Der Push wartet auf Sie

In 539 der von Apiiro zurückverfolgten Repositories änderte ein Commit, der Claude als Co-Autor nennt, die Datei. Agenten committen und pushen, wenn sie eine Aufgabe abschließen.

Auf neuen Bromure-Maschinen startet jeder Forge-Dienst im Bereich Guardrails auf Prompt before write. Lesezugriffe gehen durch. Ein git push über HTTPS wartet auf einen Dialog auf dem Mac, der den Vorgang zeigt, und nichts verlässt die Maschine, bevor Sie antworten. Die Richtlinie läuft im Proxy, also kann nichts in der VM sie abschalten.

Ein Reviewer, der die Zeile liest

Die 215 Secrets, die kein Scanner fand, waren Passwörter in Befehlen. Ein Modell, das PGPASSWORD=… psql -h db.example.com in einer committeten JSON-Datei liest, weiß, was es vor sich hat.

Ein Bromure-Code-Review überwacht ein GitHub-Repository mit einem Agenten auf einer Ihrer Maschinen, bei Every new commit, Every new pull request oder nach Wochenplan, und Bromure dedupliziert die Befunde über alle Scans hinweg. Für Apiiros Schritt „durchsuchen Sie Ihre Organisation, samt History“ startet Run Baseline Now ein einmaliges Review des gesamten Repositorys. GitHub wird vom Mac aus abgefragt, und der Review-Agent arbeitet mit denselben Platzhaltern wie jeder andere.

Auch das Transkript enthält den Platzhalter

Apiiros Zählung umfasste gespeicherte Agenten-Chatlogs. Die Sitzungsdateien von Claude Code in der VM halten fest, was der Agent gesehen hat, und in einer Bromure-Maschine ist das der Platzhalter. Bromures Traces auf dem Mac speichern Token-Tausche als kurze Vorschau wie sk-a…f9q3, und die Bytes des echten Secrets gelangen nie in einen Trace-Eintrag. Taucht doch ein echt aussehendes Secret im Verkehr auf, weil jemand eines von Hand in die VM kopiert hat, markiert der Trace es als mögliches Leck, und bromure-cli trace leaks listet alle auf. Schalten Sie Only allow credentials Bromure injects in Guardrails ein, und eine Anfrage mit Zugangsdaten, die Bromure nicht eingesetzt hat, wird blockiert und löst die Kompromittierungswarnung aus.

Platzhalter in jedem Befehl

Tokens, Datenbank-Secrets und AWS-Schlüssel sind in der VM Platzhalter. Eine Allow-Regel speichert einen Wert, der nur über Ihren Mac funktioniert.

Kein Passwort für SSH

Die VM bittet den Mac um Signaturen. Der private Schlüssel gelangt nie hinüber, und sshpass -p wird nie gebraucht.

Pushes warten auf dem Mac

Prompt before write ist der Standard für neue Maschinen. Ein Push wartet auf Ihre Antwort, durchgesetzt im Proxy.

Einmal rotieren

Echte Werte liegen in einem Bereich oder in 1Password. Ändern Sie sie dort, und jeder Platzhalter funktioniert weiter.

Was diese Woche zu tun ist

Aus Apiiros Liste, für jedes Team, das Coding-Agenten einsetzt:

  • Durchsuchen Sie Ihre GitHub-Organisation nach .claude/settings.local.json und .claude/settings.json, History eingeschlossen.
  • Rotieren Sie jedes Secret, das diese Dateien je enthielten, und räumen Sie dann auf.
  • Führen Sie git rm --cached .claude/settings.local.json aus und tragen Sie die Datei in die .gitignore des Projekts und in die Vorlagen Ihrer Organisation ein.
  • Behandeln Sie .claude/, .cursor/, .gemini/ und .specstory/ beim Pre-Commit- und CI-Scanning wie .env-Dateien, und stellen Sie sicher, dass der Scanner Passwörter in Befehlen erkennt.

Nehmen Sie dann die echten Secrets aus der Reichweite des Agenten. In einer Bromure-Maschine speichert das nächste „don't ask again“ einen Platzhalter, ob sich der Entwickler an diesem Tag an Apiiros Regeln erinnert hat oder nicht.

Zum größeren Muster von Agenten, die Secrets in History und Logs kopieren, siehe Das Transkript behielt das Token. Wie der Tausch im Detail funktioniert, lesen Sie im Kapitel Credentials des Handbuchs.