Google Trends ist diese Woche bei „rogue AI agents", „agent executing unowned code" und „agent contacting outside researchers" nach oben geschnellt, und das ist keine Paranoia. Es ist das Suchvolumen von Teams, die einem autonomen Agenten echten Tool-Zugriff gegeben, ihn ausgeliefert und erst dann gemerkt haben, was „autonom" bedeutet, wenn niemand hinschaut.
Das Muster wiederholt sich, weil der Fehler nicht im Modell liegt, sondern im Backend drumherum. Ein Agent bekommt „der Geschwindigkeit wegen" einen Datenbank-Client, eine Shell oder eine E-Mail-API, läuft unter demselben Service-Account wie alles andere, ohne Protokoll darüber, welcher Aufruf was getan hat, und ohne Möglichkeit, ihn mitten in der Aufgabe zu stoppen. Der Agent ist nicht böswillig. Er tut genau das, was ein unbeschränktes LLM tut: ein Ziel mit allen erreichbaren Werkzeugen verfolgen.
Das lernst du:
- Warum „das Modell tut das nicht" keine Sicherheitsgrenze ist
- Wie du Tool-Rechte pro Agent-Lauf statt pro API-Key eingrenzt
- Was ein Audit-Trail festhalten muss, um mitten im Vorfall nützlich zu sein und nicht erst danach
- Wo Human-in-the-Loop-Checkpoints sinnvoll sind, ohne jeden Lauf auszubremsen
- Wie du einen echten Kill-Switch in ein Agent-Backend mit FastAPI, Celery und Redis einbaust
Rechte pro Lauf eingrenzen, nicht pro API-Key
Die meisten Agent-Backends geben dem LLM eine einzige Service-Credential, die auch der Rest der App nutzt. Damit erbt jeder Tool-Aufruf, ob Lesen, Schreiben, Löschen oder Senden, den vollen Wirkungsradius des Backends. Grenze ihn stattdessen pro Agent-Lauf ein: Stelle beim Start kurzlebige, enge Credentials aus (eine schreibgeschützte DB-Rolle, ein eingegrenzter S3-Prefix, ein Zahlungsschlüssel mit Ausgabenlimit) und lass sie am Ende ablaufen. Ein kompromittierter oder verwirrter Agent kann dann nicht mehr Schaden anrichten, als dieser Lauf je durfte.
Den Audit-Trail schreiben, bevor gehandelt wird
Ein Protokoll, das erst nach dem Tool-Aufruf schreibt, ist wertlos, sobald genau dieser Aufruf der ist, den du hättest abfangen müssen. Schreibe eine Append-only-Zeile nach Postgres, mit Run-ID, Tool-Name, Hash der Argumente und Zeitstempel, bevor das Tool läuft, und aktualisiere sie danach mit dem Ergebnis. In Celery ist das ein einziger task_prerun-Hook, kein eigener Code in jedem Task. Es kostet ein paar Millisekunden pro Aufruf und sorgt dafür, dass ein abgebrochener Lauf eine Spur bis zu seiner letzten Aktion hinterlässt, statt mitten in der Geschichte abzubrechen.
Checkpoints auf die Aktionen legen, die zählen
Human-in-the-Loop bei jedem Tool-Aufruf tötet den Durchsatz und trainiert Menschen darauf, „Freigeben" zu klicken, ohne zu lesen. Sichere nur Aufrufe ab, die schreiben, löschen, senden oder über einer Schwelle Geld ausgeben. Lass den Task eine pending_approval-Zeile schreiben und auf ein kurzes Redis-Polling (oder Pub/Sub) mit hartem Timeout warten, das im Zweifel schließt: Keine Antwort heißt, die Aktion passiert nicht, nicht, dass sie trotzdem läuft.
Einen Kill-Switch bauen, der wirklich trägt
Ein Kill-Switch, der nur zwischen Tasks wirkt, ist eine Empfehlung, keine Kontrolle. Lege einen einzigen Redis-Key, agent:{run_id}:killed, hinter ein GET am Anfang jedes Tasks und zwischen den Tool-Aufrufen in lang laufenden Tasks. Ein Redis-Read ist günstig genug, um ihn bei jeder Iteration zu bezahlen, wo eine DB-Abfrage es nicht wäre. Stelle einen authentifizierten FastAPI-Endpunkt bereit, POST /agents/{run_id}/kill, der den Key setzt und celery.control.revoke(task_id, terminate=True) aufruft, damit auch wartende Folge-Tasks gar nicht erst starten. Teste ihn wie ein Zahlungs-Rollback: nach Plan, nicht erst, wenn schon etwas schiefgegangen ist.
Nichts davon ist theoretische KI-Sicherheit. Es ist dieselbe Produktionsdisziplin wie bei jedem System, das selbstständig unumkehrbare Aktionen ausführen kann. Der Agent muss nicht klüger sein, um sicher zu sein. Er braucht einen kleineren Wirkungsradius, eine Spur, die ihn überlebt, und einen Schalter, der wirklich den Strom kappt.
Siehe auch: Eine Möglichkeit, Agent-Entscheidungen klein, typisiert und prüfbar zu halten, ist ein eigenes Entscheidungsmodell wie Jev von TypeSafe, wobei dein eigener Code jede Aktion verantwortet.

