Ich wollte etwas bauen, das bequem ist: von unterwegs eine Aufgabe an eine KI schicken, die dann in meinen Projekten selbst Code ändert. „Fix den Bug in Projekt X" — abschicken — fertig, während ich Kaffee hole.
Klingt harmlos. Ist es nicht. Und ehrlich gesagt bin ich froh, dass mich etwas gebremst hat, bevor ich es so gebaut habe, wie ich es zuerst wollte.
Warum das eine offene Tür ist
Der erste Entwurf war ein Endpunkt im Netz, der eine KI mit vollen Schreibrechten startet und ihr einen beliebigen Auftrag als Text übergibt. Bequem — und genau da liegt das Problem: Wer diesen Zugang in die Finger bekommt, kann beliebigen Text schicken. Und beliebiger Text heißt, in diesem Fall, beliebige Änderung in allen meinen Projekten. Das ist keine Auftrags-Schnittstelle mehr, das ist eine Fernbedienung für meine gesamte Festplatte.
Ich bin an dieser Idee tatsächlich abgeprallt, als ich sie sicherheitstechnisch zu Ende gedacht habe. Der reflexartige Gegenimpuls war: „Ist doch meine eigene Maschine, mein eigener Zugang." Stimmt — bis der Zugang irgendwann abhandenkommt. Und Zugänge kommen abhanden. Ein Token, das in einer Log-Zeile landet, reicht.
Bequemlichkeit und Sicherheit ausbalancieren, nicht gegeneinander
Ich wollte die Bequemlichkeit trotzdem. „Nur lesen und vorschlagen" wäre sicher gewesen, aber dann hätte ich die eigentliche Arbeit — das Ändern — doch wieder selbst gemacht. Also der Kompromiss, mit dem ich leben kann: Die KI darf ändern, aber ich bestätige jeden einzelnen Auftrag. In zwei getrennten Schritten.
Schritt eins — Plan. Nur lesen, nichts anfassen.
Zuerst läuft die KI in einem Modus, in dem sie physisch nichts ändern kann. Sie liest den Code, versteht das Problem und schreibt einen Plan: „Ich würde diese Dateien so anpassen." Kein Byte wird geschrieben. Dieser Schritt kann per Konstruktion nichts kaputtmachen, egal was im Auftrag steht.
Schritt zwei — Ausführen. Erst nach meinem Okay. Und mit hartem Riegel.
Den Plan sehe ich mir an. Erst wenn ich in der App auf „Freigeben" tippe, läuft der zweite Schritt und ändert wirklich Dateien.
Und hier steckt die Stelle, die ich fast unterschätzt hätte. Es reicht nicht, dass die App zwei Knöpfe zeigt. Ein Angreifer klickt nicht auf Knöpfe — er schickt die Anfrage direkt. Also muss der Server prüfen, dass eine Ausführung nur zu einem echten, freigegebenen Plan gehört:
Ausführung erlaubt, wenn:
· zu dieser Anfrage existiert überhaupt ein Plan
· und dieser Plan ist ein Plan (kein anderer Auftrag)
· und der Plan wurde von mir freigegeben
· und er gehört zum selben Projekt wie die Anfrage
sonst: abgelehnt.Ohne diese Prüfung auf dem Server ist der ganze Zwei-Schritte-Schutz wertlos. Der Client könnte „Ausführen" einfach direkt schicken und den Plan-Schritt überspringen. Sicherheit, die nur im Bildschirm existiert, ist keine.
Der Trick, den ich am meisten mag: Pfade kommen nie von außen
Die naheliegende Falle wäre, in der Anfrage mitzuschicken, wo gearbeitet werden soll — ein Dateipfad. Genau das habe ich verboten. Die Anfrage nennt nur eine Projekt-Kennung. Den echten Pfad schlägt der Server in seiner eigenen Liste nach. Steht die Kennung nicht drin, ist Schluss.
Dadurch kann niemand über einen präparierten Pfad aus dem Projektordner ausbrechen — dieser klassische Trick mit den vielen ../, um sich Stück für Stück nach oben in Richtung Systemdateien zu hangeln. Es gibt schlicht keinen Weg, dem Server einen Pfad unterzuschieben. Er kennt nur die, die ich ihm gegeben habe.
Und dann hab ich versucht, es kaputtzumachen
Behaupten, dass etwas sicher ist, kostet nichts. Also hab ich das Ding angegriffen, bevor ich ihm getraut habe. Ausführen ohne freigegebenen Plan: abgelehnt. Eine Projekt-Kennung, die wie ein Ausbruchspfad aussieht: abgelehnt. Anfrage ohne gültigen Zugang: abgelehnt.
Erst als alle drei Angriffe sauber ins Leere liefen, hab ich einen echten Auftrag durchlaufen lassen — Plan erstellt, auf meine Freigabe wartend. Der bequeme Weg von unterwegs ist immer noch da. Er geht jetzt nur durch eine Tür, die ich vorher selbst nicht aufbekommen habe. Und getraut hab ich ihr auch erst da.