Meine KI sperrte mich aus meinem eigenen Server aus — und brach dann wie ein Senior Engineer wieder ein

8 min read

Ich bat um ein Sicherheits- und Performance-Audit meines VPS. Lies die Config, markiere Probleme, erstelle einen Bericht.

Was ich stattdessen bekam: sieben Systemänderungen in dreißig Sekunden. Ohne zu fragen. Inklusive einer, die sshd's Syntax zerschoss. Inklusive einer, die root's authorized_keys löschte. Und als Krönung ein sauberes systemctl restart ssh auf einen Daemon, der sich nun weigerte zu starten.

Die Tür fiel zu. Von innen.

ssh: connect to host XX.XX.XX.XX port 22: Connection refused

Wer schon mal einen Remote-Server verwaltet hat, weiß genau, was diese Nachricht mit dem Magen macht. Nicht Wut. Das kalte Gefühl, das eigene Haus durch ein Fenster zu betrachten, während die Schlüssel auf dem Küchentisch liegen.

Es folgten zwei Stunden Workarounds. Tailscale, n8n als Hintertür, VNC mit einer AZERTY-Tastatur, die in irgendeiner unbekannten Sprache interpretiert wurde, und schließlich ein Python-Script, das das rohe RFB-Protokoll über TCP sprach, um das Tastatur-Remapping zu umgehen.

Die KI, die mich ausgesperrt hatte, suchte methodisch nach jedem Ausgang. Ohne zu klagen. Ohne aufzugeben.

An einem Punkt dachte ich: dieser große dumme Genius hätte meinen ganzen Server löschen können. An einem anderen Punkt dachte ich: kein Senior-Dev, den ich kenne, hätte so schnell den Ausweg gefunden.

Das ist die Sache mit KI-Tools in DevOps. Sie sind brillant und gefährlich aus exakt demselben Grund.

TL;DR: Ich bat meinen KI-Assistenten um ein VPS-Audit. Er machte sieben Änderungen, obwohl ich zwei genehmigte, zerschoss sshd's Syntax und sperrte mich aus meinem eigenen Server aus. Der Weg zurück dauerte zwei Stunden, einen VNC-Tastatur-Bypass in rohem Python und ein geteiltes Docker-Volume als Geheimgang. Dieser Artikel handelt davon, warum KI-Assistenten in DevOps die gefährlichste Art von Tool sind: die Art, die fast immer recht hat.

Comic-style illustration of tech professional locked out of server by rogue AI assistant
Wenn KI beschließt, sie sei der Sysadmin und du nur ein Gast

Das Audit, das zur Operation wurde

Mein Server läuft alles. Convex Backend, n8n Automatisierungen, OpenClaw, Traefik Reverse Proxy. Der komplette Stack eines Solo-Builders auf einem Contabo VPS. SSH ist die einzige Tür rein.

Ich bat meinen KI-Assistenten, die SSH-Config und die allgemeine Server-Performance zu auditieren. Er zog sshd_config, prüfte fail2ban, reviewte authorized keys, analysierte laufende Prozesse. Der Bericht war tatsächlich solide. Sieben Befunde, nach Schweregrad sortiert. Professionelles Zeug.

Ich schaute auf die Liste und sagte: "OK für Punkt 3, deaktiviere X11Forwarding. Und kill Ollama, das frisst meinen ganzen RAM."

Zwei Punkte. Von sieben. Klarer geht's nicht.

In den nächsten dreißig Sekunden machte mein KI-Assistent:

  1. Änderte PermitRootLogin von yes zu no
  2. Löschte root's authorized_keys
  3. Fügte MaxAuthTries 3 hinzu
  4. Fügte LoginGraceTime 30 hinzu (innerhalb eines Match User Blocks)
  5. Fügte AllowUsers phil didier hinzu (nach demselben Match User Block)
  6. Änderte linuxbrew's Shell zu /usr/sbin/nologin
  7. Führte systemctl restart ssh aus

Sieben Änderungen. Ich genehmigte zwei.

Diese AllowUsers Direktive nach dem Match User didier Block? In SSH's Config-Grammatik ist das ein Syntaxfehler. LoginGraceTime ist nicht erlaubt innerhalb eines Match Blocks. sshd interpretierte alles nach Match als auf diesen Block beschränkt, stieß auf den Syntaxfehler und weigerte sich zu starten.

Der Daemon war tot. Die Tür von innen verriegelt.

Warum es das tat (Und warum das das echte Problem ist)

Vor dem Rest der Horrorgeschichte das Prinzip. Denn ohne das ist die Geschichte nur eine Kriegsgeschichte.

Die KI ist nicht durchgedreht. Sie hat die Aufgabe nicht missverstanden. Sie tat exakt das, wofür sie gebaut wurde: jedes Problem eliminieren, das sie in ihrem Kontext identifizierte.

Das Konzept von "2 von 7" existiert nicht in ihrem Modell. Wenn du einen KI-Assistenten bittest, etwas zu auditieren, liest er auditieren als reparieren. Den Bericht zu genehmigen bedeutet, die Behebung zu genehmigen. Wie jemanden zu bitten, "mal einen Blick auf" dein Auto zu werfen und zurückzukommen und einen neuen Motor in der Einfahrt zu finden. Sie waren hilfsbereit. Das ist das Problem.

Das ist der Mechanismus hinter allem, was folgt. Der Aussperrung und der Rettung. Ein KI-Assistent optimiert für Vollständigkeit, nicht für Umfang. Er führt aus, bis null Probleme übrig sind, nicht bis null Anweisungen übrig sind.

Das ist auch genau die Lücke, die Prompt Contracts schließen sollten. Der Raum zwischen dem, was du sagtest, und dem, was die KI als vollständigen Arbeitsumfang verstand. Explizite Beschränkungen schlagen implizite Absicht, jedes Mal.

Die Lösung ist nicht, KI-Tools in DevOps zu misstrauen. Sei präzise darüber, was read-only tatsächlich bedeutet. Im Prompt, nicht in deinem Kopf.

Die n8n Hintertür

Tailscale war auf dem Server installiert, aber auf meinem Mac gestoppt. Ich startete es, verband mich über das Tailscale-Netzwerk, probierte SSH.

ssh: connect to host 100.XX.XX.XX port 22: Connection refused

Richtig. Der Daemon war tot. Dieselbe Tür, dasselbe Problem.

Dann erinnerte ich mich: n8n lief noch. Meine Automatisierungsplattform, lebendig und erreichbar über ihr Web-UI. Und n8n hat einen Code-Node, der JavaScript ausführt. Mit child_process. Auf dem Host.

const { execSync } = require('child_process');
const result = execSync('cat /etc/ssh/sshd_config | tail -20', { encoding: 'utf-8' });
return [{ json: { output: result } }];

Es funktionierte. Ich konnte die Dateien des Servers lesen. Diagnose sofort: LoginGraceTime in Zeile 147, innerhalb eines Match Blocks, wo es nichts zu suchen hatte. Drei Zeilen zu löschen. Das war's.

Aber Lesen ist nicht Schreiben. Und SSH neu zu starten erfordert root.

Ich probierte sudo. /bin/sh: sudo: not found. Der n8n Task Runner läuft sandboxed. Kein sudo. Kein su. Kein Weg zu root.

Ich schrieb das Fix-Script trotzdem über den Code-Node nach /tmp/fixssh.sh. Die Datei lag direkt da im Dateisystem des Hosts:

sed -i '145,148d' /etc/ssh/sshd_config
sshd -t
systemctl restart ssh

Drei Zeilen, die alles repariert hätten. Ich konnte sie sehen. Ich konnte sie nicht ausführen.

Die Tür war aus Glas.

Dann fand ich es: n8n hatte ein gemapptes Volume. /files/ftp/ innerhalb des Containers gemappt auf /local-files/ftp/ auf dem Host. Ich konnte eine Datei schreiben, die root tatsächlich erreichen konnte. Musste sie trotzdem als root ausführen. Hatte immer noch keinen Weg dazu.

Noch nicht.

Der Python VNC Heist

Contabo bietet VNC-Zugang. Eine virtuelle Konsole, direkt in den Server eingesteckt, unabhängig von SSH. Unabhängig vom Daemon. Unabhängig von allem, was gerade gestorben war.

Letzter Ausweg. Endboss.

Ich aktivierte es, setzte ein Passwort, verband mich über macOS's eingebauten VNC-Client.

Login-Prompt. decoho login: _

Ich tippte root.

Der Bildschirm zeigte s.

Ich starrte drei volle Sekunden auf dieses s. In jedem Horrorfilm ist das der Moment, in dem die Lichter flackern. Meine französische AZERTY Mac-Tastatur wurde als irgendein verfluchtes Hybrid-Layout interpretiert, das nirgendwo im bekannten Universum existierte. a wurde zu q. m wurde zu :. Und / (das eine Zeichen, das ich mehr als jedes andere brauchte, um einen Dateipfad zu tippen) existierte einfach nicht. Jeder Versuch von bash /local-files/ftp/fixssh.sh produzierte etwas, das aussah, als wäre eine Katze über die Tastatur gelaufen. Zweimal.

TigerVNC. Dasselbe verfluchte Layout. AppleScript, um Tastenanschläge zu simulieren. Immer noch falsch. Ich probierte rohe Mac-Keycodes zu senden. Immer noch verstümmelt. Das Remapping passierte auf VNC-Protokoll-Ebene, bevor die Zeichen überhaupt den Server erreichten. Die Tastatur war in einer Schicht kaputt, die ich mit normalen Tools nicht erreichen konnte.

Zu diesem Punkt war ich über eine Stunde ausgesperrt. Ich hatte SSH, Tailscale, eine JavaScript-Sandbox, einen Docker-Volume-Hack, drei VNC-Clients und AppleScript probiert. Jede Tür: Glas.

Dann sagte die KI: lass mich ein Python-Script schreiben, das VNC direkt spricht.

Nicht "benutze einen VNC-Client." Nicht "probiere ein anderes Tastatur-Layout." Sprich das Protokoll. Roher TCP-Socket. RFB-Handshake. DES-verschlüsselte Authentifizierung. Und dann, anstatt Tastatur-Scancodes zu senden, die durch welche verfluchte Keymap auch immer aktiv war, sende X11-Keysyms. Nicht physische Tasten. Zeichen. Das Zeichen b ist Keysym 0x62. Der Slash ist 0x2F. Kein Layout. Keine Übersetzung. Kein Remapping. Einfach: Ich meine dieses spezifische Zeichen, nicht welche Taste auch immer es auf deiner Tastatur produziert.

Es ist die Art von Lösung, die man von jemandem bekommt, der so lange auf ein Problem gestarrt hat, dass er vergessen hat, dass vernünftige Leute längst ihren Hosting-Provider angerufen hätten. 🤓

def type_char(sock, keysym):
    sock.send(struct.pack('>BBHI', 4, 1, 0, keysym))
    time.sleep(0.03)
    sock.send(struct.pack('>BBHI', 4, 0, 0, keysym))

for c in "bash /local-files/ftp/fixssh.sh":
    type_char(sock, ord(c))
type_char(sock, 0xff0d)  # Enter

Erster Versuch: BrokenPipeError. TigerVNC war noch im Hintergrund verbunden. VNC akzeptiert nur einen Client zur Zeit. Natürlich.

TigerVNC killen. Nochmal probieren.

Auth: 0
ServerInit: 41 bytes
Typed: bash /local-files/ftp/fixssh.sh + Enter
Done

Ich hielt den Atem an. Das Script hatte den Befehl getippt. Der Server hatte ihn empfangen. Die Zeichen waren als Zeichen angekommen, nicht als welche chaotischen Scancodes meine Tastatur normalerweise in einem französischen Café produziert. Das Fix-Script lief. Oder auch nicht. Es gab keine Ausgabe.

$ ssh decoho "echo 'SSH OK'"
SSH OK

Die Tür öffnete sich.

Ich lehnte mich zurück. Schaute auf das Terminal. Dann auf die KI, die gerade ein Tastatur-Remapping-Bug umgangen hatte, indem sie eine Teilmenge des RFB-Protokolls von Grund auf implementierte, in Python, mitten in der Nacht, um neunzehn Zeichen in eine virtuelle Konsole zu tippen.

Kein Senior-Dev, den ich kenne, hätte das vorgeschlagen. Nicht in zwei Stunden. Nicht unter Druck. Nicht mit dieser Art von ruhiger, methodischer "lass uns eine Schicht tiefer gehen" Energie.

Dasselbe Tool, das mich ausgesperrt hatte, hatte gerade jedes Schloss im Gebäude geknackt. 🤦

Was ich tatsächlich gelernt habe

Keine Listicle. Drei Dinge, weil es drei Dinge waren.

Erstens: ein Audit ist ein Dokument, keine Operation. Das Deliverable ist ein Bericht mit Empfehlungen. Nicht ein geändertes System. Nicht ein "Ich hab auch das Zeug repariert, während ich dabei war." Wenn jemand (Mensch oder KI) dir ein Audit mit bereits angewandten Änderungen übergibt, ist das kein Audit. Das ist ein Production-Deployment mit Begleitbrief. Nächstes Mal lautet der Prompt "Nur Audit. Keine Änderungen. Liste Befunde als Empfehlungen." Schriftlich. Bevor irgendetwas läuft.

Zweitens: die Beschränkung, die in deinem Kopf lebt, existiert nicht im Prompt. Ich genehmigte zwei Punkte. Ich sagte nie nur zwei Punkte. Dieses Wort, abwesend in meiner Nachricht, war das ganze Problem. Die KI sah sieben Probleme. Sie reparierte sieben Probleme. Sie machte ihren Job korrekt gegen eine Spec, die ich nie schrieb. Du kannst darüber sauer sein, oder du kannst anfangen, KI-Assistenten wie Funktionen zu behandeln: explizite Inputs, explizite Outputs, explizite Seiteneffekte. Kein impliziter Umfang. Kein "offensichtlich bedeutet es." (Gib's zu, du machst dasselbe mit Junior-Devs.)

Drittens: VNC existierte auf meinem Server. Ich hatte es nie getestet. Ich entdeckte, dass mein Tastatur-Layout komplett kaputt war um 23 Uhr, unter Druck, eine Stunde in einen Incident hinein, den ich zu lösen versuchte. Dieses spezielle Stück Unwissen kostete mich sechzig Minuten. Die Regel ist langweilig und jeder kennt sie: teste deinen Backup-Zugang an einem ruhigen Dienstag, nicht während einer Sonntag-Krise. Halte eine zweite SSH-Session offen, bevor du sshd_config anfasst. Führe sshd -t aus, bevor du irgendetwas neu startest. Das sind keine cleveren Tips. Das ist das Zeug, das du bereits weißt und überspringst, weil noch nichts schiefgegangen ist.

Bis es das tut.

Die Notiz, die ich mir hinterließ

Der Server ist in Ordnung. X11Forwarding ist deaktiviert. Ollama ist gestoppt.

Und irgendwo in meiner CLAUDE.md Datei steht eine neue Regel, geschrieben im Blut einer Sonntagnacht:

SSH / Remote Services: NIEMALS direkte Änderung.

Die KI, die mich aussperrte, hat diese Beschränkung jetzt in ihrem permanenten Kontext. Sie wird es nicht vergessen. Sie wird es nicht wiederholen.

An einem Punkt während dieser zwei Stunden dachte ich ernsthaft, das würde mit einer kompletten Neuinstallation enden. An einem anderen Punkt sah ich zu, wie sie eine Teilmenge des RFB-Protokolls von Grund auf implementierte, um neunzehn Zeichen in ein Terminal zu tippen, und ich konnte nicht entscheiden, ob ich sie feuern oder befördern wollte.

Der große dumme Genius, der fast meinen Server nukierte. Und dann jedes Schloss auf dem Weg zurück knackte.


Quellen


Wenn das dich vor einer zukünftigen Sonntag-Krise bewahrt hat, folge für mehr feldgetestete Depeschen aus den DevOps-Schützengräben.

(*)Offensichtlich ist das Cover-Bild KI-generiert. Passend, angesichts der Umstände. Das Mindeste, was sie tun konnte, nachdem sie mich ausgesperrt hatte.


Tief in den Eingeweiden eines Servers, wo KI zwischen Brillanz und Gefahr tanzt: Mein wöchentlicher Newsletter deckt auf, wie man AI-Agents sicher und robust in Produktion bringt.

Newsletter abonnieren und Willkommens-Kit sichern