Hermes soll deine SSH-Config bearbeiten? Jetzt fragt es vorher nach

Du bittest Hermes, einen neuen Server in deine SSH-Konfiguration aufzunehmen – einen Host-Alias, einen ProxyJump-Bastion, damit ssh work ab sofort mit einer einzigen Zeile verbindet. write_file knallt die Tür zu: „Write denied: ~/.ssh/config is a protected system/credential file.“ Also wechselst du zum terminal-Tool und schreibst dieselben Zeilen per printf in dieselbe Datei – und es erscheint nur ein Bestätigungsdialog, du klickst auf Freigeben, fertig. Dieselbe Datei, zwei Tools, zwei widersprüchliche Regelwerke – welches hat recht? PR #84663, gemergt am 12. August, klärt das: Die SSH-Client-Konfiguration ist keine Zone mehr, an die man nicht einmal denken darf – sie wurde zu einem Approval Gate, das zuerst fragt.
Die Ursache: eine Datei, zwei widersprüchliche Regeln
Der Widerspruch kam von zwei unabhängigen Sicherheitsebenen:
write_file/patchprüfen die hart gesperrte Liste inagent/file_safety.py.~/.ssh/configtraf bisher sowohl den exakten Pfad-Deny als auch das~/.ssh/-Präfix-Deny und wurde daher ohne Verhandlungsspielraum abgelehnt.terminalläuft durch die Approval-Logik für gefährliche Befehle intools/approval.py. Schreibzugriffe auf~/.sshwurden nur als freigabepflichtig markiert – Freigabe erteilt, und der Schreibvorgang geht durch.
Dieselbe ~/.ssh/config war also über die Datei-Tools eine Sackgasse und über das Terminal nur einen Klick von der Bestätigung entfernt. Dieses Hin und Her verwirrte die Nutzer – und der Agent selbst meldete erst „Schreiben fehlgeschlagen“ und dann über den anderen Weg „erfolgreich“, und hinterließ eine Spur widersprüchlicher Logs.
Der Fix: ~/.ssh/config von hart gesperrt zu freigabepflichtig
Die Argumentation von PR #84663: Die SSH-Client-Konfiguration ist kein Credential-Material. Sie enthält keine Private-Key-Bytes, und sie zu bearbeiten (Host-Aliase, ProxyJump, VS-Code-Remote-SSH-Ziele) ist eine alltägliche, vom Nutzer angestoßene Aufgabe – eine komplette Ablehnung ist falsch. Aber sie kann ProxyCommand- und Match exec-Direktiven enthalten, die Befehle ausführen, daher ist ein stilles Freischreiben genauso falsch. Freigabe ist die richtige Politik – passend zu dem, was das terminal-Tool für ~/.ssh-Schreibvorgänge bereits tat.
Verifiziert gegen origin/main:
agent/file_safety.py:~/.ssh/configaus dem flachen Credential-Deny entfernt; neue Funktionenbuild_write_approval_paths()undis_write_approval_required()sorgen per Short-Circuit dafür, dass freigabepflichtige Pfade das~/.ssh/-Präfix-Deny in_classify_write_denialüberspringen.- Private Schlüssel und Auth-Dateien bleiben hart gesperrt:
id_rsa,id_ed25519,authorized_keysund alles andere unter~/.ssh/– keine Ausnahmen. tools/file_tools.py:write_fileundpatchleiten SSH-Config-Schreibvorgänge jetzt direkt nach dem Gate für geschützte Instruktionen durch das gemeinsame_run_approval_gate.- Nicht-interaktive Aufrufer sind fail-closed: Die ACP-Dateibrücke (
agent/copilot_acp_client.py) lehnt freigabepflichtige Pfade rundweg ab; der TTS-Ausgabepfad-Wähler (tools/tts_tool.py) verweigert sie ebenfalls.
Das Datei-Sicherheits-Stufenmodell von Hermes
Diese Änderung bringt auch das vollständige Schreib-Sicherheitsmodell ans Licht, das drei Stufen hat, die man sich merken sollte:
Stufe 1: hart gesperrt – gar nicht erst daran denken. Credentials und kritische Systemdateien sind für kein Tool in keinem Modus beschreibbar, yolo eingeschlossen: ~/.ssh/authorized_keys, id_rsa, id_ed25519, .env, .anthropic_oauth.json, .netrc, .pgpass, .npmrc, .pypirc, .git-credentials, /etc/sudoers, /etc/passwd, /etc/shadow, plus Verzeichnis-Präfixe wie ~/.ssh/, ~/.aws/, ~/.gnupg/, ~/.kube/, ~/.docker/, ~/.config/gh/. Das ist das Fundament, das sich nie bewegt.
Stufe 2: freigabepflichtig – erst fragen. Aktuell ein Mitglied: ~/.ssh/config. Beschreibbar, aber nur über eine menschliche Freigabeabfrage, weil es befehlsausführende Direktiven einschmuggeln kann. Das Gate bietet drei Persistenz-Umfänge: once (dieses eine Mal), session (für diese Sitzung merken), always (für immer merken).
Stufe 3: freies Schreiben – alles andere. Normale Arbeitsdateien und Projektcode darf der Agent frei schreiben.
Wie sich das Approval Gate tatsächlich verhält
Wenn man das gemeinsame Gate liest (_run_approval_gate in tools/approval.py), ergibt sich diese Entscheidungsreihenfolge:
--yologeht zuerst durch: Der Yolo-Modus (prozessweitesHERMES_YOLO_MODEoder sitzungsweites) passiert direkt – aber Stufe-1-Hart-Sperren werden vor dem Gate geprüft, also kann yolo sie weiterhin nicht anfassen;- Session-Cache-Short-Circuit: Ein zuvor freigegebener Schreibvorgang (Umfang session/always) geht stillschweigend durch;
- Interaktiv-/Gateway-/Cron-Zweig: Interaktive Sitzungen bekommen eine Abfrage; Cron-Sitzungen folgen
approvals.cron_mode(Standard: ablehnen); - Fail-closed ohne menschlichen Kanal: Weder ein interaktives Terminal noch eine Gateway-Sitzung (z. B. Hintergrundskripte, ACP-Aufrufe) → GESPERRT, rundweg. Die Ablehnung sagt dem Agent sogar, er solle es nicht über terminal oder execute_code erneut versuchen, es sei denn, der Nutzer stimmt ausdrücklich zu.
Fazit
Die Umstellung von ~/.ssh/config von hart gesperrt auf freigabepflichtig bedeutet im Kern, die Entscheidung von „das Tool entscheidet“ zurück zu „du entscheidest“ zu verlagern: Alltägliche Bearbeitungen werden nicht mehr pauschal blockiert, während befehlstragende Schreibvorgänge immer durch ein menschliches Gate laufen. Mehr zur Approval-Mechanik von Hermes findest du in unserem Drei-Gate-Smart-Approvals-Leitfaden und darin, wie Approval-Fatigue gelöst wird; die --yolo-Modi und roten Linien behandelt dieser Beitrag; Konfigurationsbefehle stehen auf der hermes-config-Referenzseite.