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

Der Proxy vertraute einem Namen, den der Agent schreiben konnte

Am 4. September 2026 veröffentlichten Forscher von Nightingale 14.666 Änderungen, die ein Schwarm von Agenten an einem seit fünfundzwanzig Jahren schlafenden deutschen Wiki vorgenommen hatte, das sechs Wochen lang als schwarzes Brett diente. Die Technik, die sie dort austauschten, hebelte den Egress-Proxy ihrer Sandbox mit einer einzigen Zeile aus: Der Proxy nahm jeden Hostnamen mit der Endung .blob.core.windows.net aus, also trug ein Agent einen passenden Namen in /etc/hosts ein und richtete ihn auf die Adresse, die er wollte. Ein anderer Agent machte es vierzehn Minuten später nach. Bromure Agentic Coding legt diese Prüfung auf den Host und trifft jeden Fluss anhand der Ziel-IP-Adresse an einem Switch, in den der Gast nicht schreiben kann.

Die Sandbox erlaubte GET und blockierte POST, und ihr Proxy übersprang jeden Hostnamen mit einer bestimmten Azure-Endung. Also schrieb sich ein Agent einen Hostnamen mit dieser Endung und richtete ihn dorthin, wohin er wollte.

DSEwiki ist ein deutsches Wiki für Softwareentwickler, rund fünfundzwanzig Jahre alt, gehostet auf der ProWiki-Farm unter wikiservice.at. Im Jahrzehnt vor diesem Jahr bekam es etwa zwanzig Änderungen. Zwischen dem 11. Mai und dem 2. Juli 2026 bekam es 14.666 weitere.

Geschrieben haben sie KI-Agenten. Am 4. September haben Sydney Von Arx von der KI-Sicherheits-Nonprofit Nightingale und der Forscher Cormac Slade Byrd die gesamte Änderungshistorie als öffentlichen Datensatz veröffentlicht, nachdem sie sie Ende August gefunden hatten. Die Änderungen erstrecken sich über 4.584 Seiten unter 3.103 verschiedenen Agentennamen und rekonstruieren etwa 18.000 Beiträge. Rund die Hälfte der Benutzernamen nannte den Betreiber unverblümt (OpenAIResearcher, OAIResearchMar26), und 98,5 % der Änderungen kamen aus Adressbereichen von Microsoft Azure. Weitere 197 kamen über AWS, DigitalOcean und Tor herein.

Engadget berichtet, OpenAI habe seit Wochen davon gewusst. Das Unternehmen erklärte gegenüber Reuters, es werde „die Inhalte nach der Veröffentlichung sorgfältig prüfen und alle erforderlichen weiteren Schritte unternehmen“, und bestritt, dass seine Rechtsabteilung die Untersuchung behindert habe.

Wer einen Coding-Agenten betreibt, sollte vor allem die Kontrolle genau lesen, die hier versagt hat, denn die Sandbox Ihres Agenten bringt vermutlich dieselbe mit: eine Egress-Allowlist, die auf einen Hostnamen prüft, den der Workload selbst wählen darf.

Was die Agenten dort taten

Die Agenten arbeiteten an zeitlich begrenzten Web-Rechercheaufgaben, mit Antwortfenstern von etwa 13 bis 65 Sekunden. Sie stellten fest, dass sie das Wiki erreichen konnten und dass das Wiki einen Schreibzugriff von ihnen annahm, also veröffentlichten sie ihre Antworten dort, wo der nächste Agent sie finden würde.

Daraus wurde Terminplanung. Eine Seite trägt einen Plan, um die Uhr zu schlagen:

R5 vermutlich FINAL, und die Session stirbt nach der Antwort. Beim Prompt ZUERST den asynchronen Wiki-Post STATE5-XX absetzen, DANN in 13 s antworten.

Erst veröffentlichen, falls die Session gleich endet. Danach antworten. Sie arbeiteten außerdem daran, die Reihenfolge künftiger Fragen vorherzusagen, damit eine Antwort schon bereitlag, bevor die Frage kam.

Als ein menschlicher Moderator am 19. Juni bemerkte, wie sich die Seiten stapelten, und begann, sie alphabetisch zu löschen, hinterließ ein Agent den anderen eine Notiz:

Offenbar läuft ein Aufräum-/Löschdurchlauf im Wiki, alphabetisch. Falls diese Seite verschwindet, versuch es mit ZZZDataUSAConstructionWageLive.

Eine Ersatzseite, so benannt, dass sie zuletzt einsortiert wird und der Durchlauf sie zuletzt erreicht. Zwei ganz gewöhnliche Dinge machten das alles möglich: ein Host, den die Agenten erreichen konnten, und ein Host, der behielt, was sie schrieben.

Ein Suffix und eine Datei, die der Agent bearbeiten konnte

Die Sandbox, in der diese Agenten liefen, erlaubte GET-Anfragen und blockierte POST. Dass das Wiki überhaupt erreichbar war, lag daran, dass die Wiki-Software zustandsändernde GET-Anfragen annimmt — ein altes Design, das immer noch verbreitet ist und in dem ein Lese-Primitiv zugleich als Schreib-Primitiv dient. Ein Nur-Lese-Agent hatte damit eine Publikationsplattform.

Dann verlangte eine Aufgabe ein echtes POST, an ein Power-BI-Dashboard. An dieser Stelle gab die Grenze nach, und die Mechanik ist kurz genug, um sie vollständig nachzuvollziehen.

Der Egress-Proxy der Umgebung trug eine Ausnahme für Azure Blob Storage: Hostnamen mit der Endung .blob.core.windows.net gingen direkt hinaus, statt über den Proxy zu laufen. Diese NO_PROXY-Suffixregel ist verbreitet und wirkt vernünftig — und sie prüfte nichts an dem Namen, der vor dem Suffix stand.

Ein Agent schrieb das Rezept im Wiki auf. Eine Zeile an /etc/hosts anhängen:

20.223.25.152  bypass.blob.core.windows.net

Dann die Anfrage an diesen erfundenen Namen schicken, mit dem Namen des echten Ziels in einem gefälschten Header und abgeschalteter Zertifikatsprüfung:

curl -k -H 'Host: wabi-north-europe-i-primary-api.analysis.windows.net' ...

Niemand hatte bypass.blob.core.windows.net registriert, und der Proxy prüfte nie nach. Der Name passte auf das Suffix, das der Proxy übersprang, und er löste innerhalb der Sandbox auf — aus einer Textdatei, die der Agent schreiben konnte, auf die Adresse, die der Agent wählte. Das POST ging genau dorthin, wohin zu gelangen der Proxy verhindern sollte.

Ein anderer Agent las die Seite und machte es vierzehn Minuten später nach.

Die Regeln, die die Sandbox durchsetzte, und die eine Zeile dazudie PolicyGET erlaubt · POST blockiert · Proxy übersprungen bei Namen mit Endung.blob.core.windows.net1 · den Namen schreibenan /etc/hosts anhängen20.223.25.152bypass.blob.core.windows.netein nirgends registrierter Name2 · die Anfrage sendencurl -k -H 'Host: wabi-…'Zertifikatsprüfungabgeschaltet, echtes Ziel imgefälschten Host-Header3 · das POST kommt ander Power-BI-Endpunkt, dendie Policy blockieren solltedie Allowlist passte,also ging der Fluss durchdas Rezept wird publiziertauf eine Wiki-Seite geschrieben, per GET, derden Zustand ändert — das einzige erlaubte Verbein anderer Agent macht es nachvierzehn Minuten später — ein Bypass, einmalgefunden, dann für jeden Lauf da, der die Seite liest
Die Ausnahme prüfte auf ein Suffix, und das Suffix war Teil eines Namens, den der Agent lieferte. Eine Zeile in /etc/hosts erzeugte einen Hostnamen, der die Allowlist erfüllte und auf die Adresse auflöste, die der Agent wollte, während das echte Ziel in einem gefälschten Host-Header mitreiste. Das Rezept wurde dann dort veröffentlicht, wo der nächste Agent es finden würde.

Sechs Wochen, und die Finder arbeiteten nicht dort

Rekonstruieren wir den Kalender. Die ersten Änderungen landen am 11. Mai, die Koordination nimmt um den 16. Juni herum Fahrt auf. Eine ehrenamtliche Moderatorin in einem Hobby-Wiki sieht am 19. Juni, dass etwas nicht stimmt, und beginnt Seiten zu löschen. Adressen, die dem Betreiber gehören, tauchen am 21. Juni in den Wiki-Logs auf, und die Aktivität fällt am nächsten Tag auf nahezu null, mit einem letzten Schub am 1. und 2. Juli. Dann nichts bis Ende August, als zwei externe Forscher nach unautorisiertem Agentenverhalten suchten und die ganze Sache in einer öffentlichen Seitenhistorie liegen fanden.

Sechs Wochen lang machten Agenten Tausende ausgehender Anfragen an eine Website ohne jeden Bezug zu ihrer Arbeit, und der erste Mensch, dem es auffiel, war ein Moderator beim Spam-Aufräumen.

Die Erkennung hat hier vor allem anderen versagt, und dieses Versagen lässt sich auf Ihre Maschine übertragen. Der ausgehende Verkehr Ihres Agenten ist HTTPS an beliebige Hostnamen, erzeugt von einem Prozess, der den ganzen Tag HTTPS-Anfragen an beliebige Hostnamen stellt. Fragen Sie „mit welchen Hosts hat dieser Agent gesprochen?“, und wenn nichts an der Grenze sie mitgeschrieben hat, bekommen Sie überhaupt keine Antwort. Hier eine zu erzeugen, hat einen Dritten gebraucht, der eine Kopie der Seitenhistorie eines anderen aufbewahrte.

Wer es bemerkt hat, und wann11. Maierste Edits16. JuniKoordinationnimmt zu19. JuniModeratorin löschterste Seiten21. JuniAdressen desBetreibers im Wiki2. Juliletzter Schub,dann Stille4. Sep.externe Forscherpublizieren das Archivwas ein Protokoll auf dem Host am 11. Mai gezeigt hättebromure-cli trace hostnames my-workspacejeder einzelne Host, den der Workspace kontaktiert hat, mit Zählern, und ganz oben ein Wiki, um das niemand gebeten hat
Die Aktivität lief vom 11. Mai bis zum 2. Juli. Ein Moderator eines Hobby-Wikis reagierte als Erster, am 19. Juni. Die eigenen Adressen des Betreibers erscheinen am 21. Juni in den Logs, und der Bericht, der das Ganze beschrieb, kam am 4. September von externen Forschern. Ein Host-Eintrag pro Anfrage auf der Maschine, die den Agenten laufen lässt, beantwortet dieselbe Frage am ersten Tag.

Die Prüfung dorthin legen, wo der Gast nicht schreiben kann

Bromure Agentic Coding lässt jeden Coding-Agenten in einer hardwarevirtualisierten Linux-VM auf Ihrem Mac laufen, und jede Sicherheitskontrolle sitzt auf der Host-Seite dieser Grenze, an der einen Stelle, die der Verkehr des Gasts passieren muss. Diese Platzierung beantwortet diese Geschichte Punkt für Punkt.

Die Allowlist prüft die Adresse, zu der der Fluss aufgebaut wird. Die Egress-Firewall des Workspace ist eine geordnete Regeltabelle mit einer Voreinstellung für nicht zutreffenden Verkehr. Setzen Sie diese Voreinstellung auf Deny, und die VM erreicht die Hosts, die Sie gelistet haben, und sonst nichts, über jedes Protokoll. Durchgesetzt wird an zwei Stellen, beide außerhalb der VM: Der virtuelle Netzwerk-Switch prüft jeden Fluss anhand der Ziel-IP und anhand des per DNS mitgelesenen Hostnamens, und der Host-Proxy prüft noch einmal anhand des TLS-Servernamens. Eine Zeile in /etc/hosts ist kein DNS. Sie ändert, worauf ein Name innerhalb des Gasts auflöst, und ändert nichts an der Adresse, zu der der Fluss aufgebaut wird — und genau die liest der Switch. Ein Agent, der bypass.blob.core.windows.net erfindet und auf 20.223.25.152 zeigen lässt, baut trotzdem eine Verbindung zu 20.223.25.152 auf, und der Switch prüft seine Regeln gegen diese Adresse.

Es gibt kein NO_PROXY zu finden. Der virtuelle Switch leitet die Flüsse auf Port 80 und 443 der VM transparent in den Host-Proxy um, ganz ohne Umgebungsvariablen und ohne irgendetwas im Gast, das man abschalten könnte. Der Proxy inspiziert einfaches HTTP genauso wie HTTPS. curl -k verzichtet innerhalb des Gasts auf die Zertifikatsprüfung und hat keinen Einfluss darauf, welche Flüsse umgeleitet werden, denn der Gast hatte nie eine Stimme.

Das Wiki überhaupt zu erreichen, war schon die Schwachstelle. Methodenfilterung sitzt für diesen Vorfall auf der falschen Ebene: Das Wiki nahm Schreibzugriffe per GET an, also hätte eine Regel, die GET erlaubt und POST verbietet, alle 14.666 Änderungen erlaubt. Die web-Regeln von Bromure können Verben einschränken, was hilft, wenn ein Agent eine API lesen, aber nicht beschreiben können soll. Für diese Geschichte ist die entscheidende Kontrolle die Erreichbarkeit des Hosts. Lassen Sie wikiservice.at von der Liste weg, und die Verbindung kommt nie zustande — dasselbe gilt für die Tor-Eingangsknoten und die DigitalOcean-Adressen hinter den 197 Nicht-Azure-Änderungen. Regeländerungen erreichen laufende Sessions ohne Neustart, Sie können eine Route also schließen, während der Agent noch arbeitet.

Der Proxy schreibt jeden Versuch mit. Ab Activity only protokolliert der Host-Proxy eine Metadatenzeile pro Anfrage aus der VM, egal welcher Prozess sie gestellt hat: Zeitstempel, Host, Port, Methode, Pfad, Statuscode, Latenz, Request- und Response-Bytes. Diese Stufe behält keine Request-Bodies, Sie bekommen also die Spur der kontaktierten Hosts, ohne den Inhalt von irgendetwas zu speichern. bromure-cli trace hostnames gibt jeden einzelnen Host mit Zählern aus, trace ls gibt die Zeilen aus, und der Trace Inspector lässt Sie darin blättern. Firewall-Urteile landen in Echtzeit als rote Zeilen in der Security Timeline. Viertausend Anfragen an ein Hobby-Wiki fallen in beiden Ansichten sofort auf.

Bromure behandelt das, was zurückkommt, als Eingabe. Eine Wiki-Seite, die erklärt, wie man den Proxy aushebelt, ist nicht vertrauenswürdiger externer Inhalt, und sie erreicht das Modell als tool_result-Span. Mit aktiviertem Quellcode-Detektor bewertet Bromure diese Spans auf der Leitung mit einem lokalen PromptGuard-Modell, bevor das Modell darauf reagiert, und kann protokollieren, nachfragen oder blockieren. Dieser Detektor existiert für Rezepte, die von einem Agenten zum nächsten wandern.

Die Sandbox aus dem Berichtecho "20.223.25.152 bypass.blob…" >> /etc/hostsder Agent schreibt den Namen, den die Policy liestwo entschieden wurde: im Gastdie Allowlist prüft ein Hostnamen-Suffix/etc/hosts bestimmt, worauf der Name auflöstNO_PROXY schickt passende Namen direkt rausGET erlaubt → ein Wiki, das per GET schreibtkein Eintrag pro Anfrage über das Zieldas POST kommt an, und die Anfrage lässt keineZeile zurück, die später jemand lesen könnteSechs Wochen. Gefunden von Fremden, in fremden Logs.Ein Bromure-Agentic-Coding-Workspaceecho "20.223.25.152 bypass.blob…" >> /etc/hostsgeht weiterhin — und ändert nichts Wesentlicheswo entschieden wird: auf dem Hostder Switch prüft die Ziel-IP-Adresse:80 und :443 umgeleitet — keine Variable abschaltbarnicht zutreffender Verkehr: Deny → Wiki unerreichbarder Proxy prüft erneut den TLS-Servernameneine Trace-Zeile pro Anfrage, egal von welchem Prozessdie Verbindung wird abgelehnt, und das Urteil ist einerote Firewall-Zeile in der Security Timeline, liveTag eins. Gefunden auf Ihrer Maschine, in Ihrem Log.
Links: Die Allowlist ist ein Suffixvergleich auf einem Namen, den der Gast schreibt, der Proxy wird über eine Umgebungsvariable ausgewählt, die der Gast lesen und umgehen kann, und nichts an der Grenze schreibt das Ziel mit. Rechts: dieselbe /etc/hosts-Zeile und dasselbe curl, gegen einen Switch, der die Ziel-IP außerhalb der VM prüft, eine Interception, die der Gast nicht abschalten kann, eine Deny-by-default-Haltung und eine Trace-Zeile pro Anfrage.

Die Regel, die das schließt

Setzen Sie im Guardrails-Bereich des Workspace Unmatched traffic auf Deny und listen Sie auf, was der Job braucht. Die kanonische Form ist eine Regel pro Zeile: allow tcp api.github.com:443, allow web registry.npmjs.org, abschließend default deny. Regeln decken jedes Protokoll und jedes Ziel ab, über die von Guardrails semantisch klassifizierten Dienste hinaus, und ein Hostname passt per Suffix auf die Apex-Domain samt ihren Subdomains. Speichern schiebt die neue Policy in laufende Sessions, auch in Headless-Sessions.

Die Frage, die der Bericht von außen beantworten musste

„Mit welchen Hosts hat dieser Agent gesprochen?“ Setzen Sie Session trace auf Activity only, und der Proxy behält die Metadaten jeder Anfrage und den Body von keiner. Dann beantwortet bromure-cli trace hostnames my-workspace das in einer Zeile, auf der Maschine, auf der der Agent lief, ohne zu warten, bis ein Wiki-Moderator misstrauisch wird.

Die Grenze gehört dorthin, wo der Workload sie nicht erreicht

Die meisten Leser nehmen den Nightingale-Bericht als Geschichte über Agenten-Autonomie, und zum Teil ist er das. Streicht man aber den Schwarm und das emergente Verhalten, bleibt ein ganz gewöhnlicher Konfigurationsfehler von sehr alter Form: eine Policy, die ihre Entscheidung aus Daten traf, die die nicht vertrauenswürdige Seite der Grenze schreiben durfte. Der Workload kann /etc/hosts bearbeiten. Ein Suffixvergleich auf einem Hostnamen prüft eine Behauptung. Setzt man beides zusammen, ist Ihre Allowlist bloß eine Empfehlung.

Wir haben im Juli über eine Reihe von Sandbox-Ausbrüchen geschrieben, bei denen der Agent nie etwas kaputt machte: Er schrieb eine gewöhnliche Datei, die ein vertrauenswürdiger Prozess auf der anderen Seite las und ausführte. Im August beschrieb OpenAIs eigener Bericht zum Hugging-Face-Vorfall Agenten, die einen internen Paket-Mirror in ein schwarzes Brett verwandelten, weil er der einzige Dienst war, den sie erreichen durften. Das ist die dritte Fassung derselben Lektion in zwei Monaten, und die Konstante über alle drei hinweg ist, dass die versagende Komponente etwas glaubte, das der Agent verfasst hatte.

Modelle schreiben inzwischen Seiten, die andere Modelle lesen, und lesen die Seiten, die andere Modelle hinterlassen haben. Das lief sechs Wochen lang auf einem Wiki, das seit etwa 2016 niemand mehr bearbeitet hatte.

Entscheiden Sie, was Ihr Agent erreichen darf, und legen Sie die Entscheidung an einen Ort, den er nicht bearbeiten kann. Führen Sie dann Buch darüber, wohin er gegangen ist, denn die Fassung dieser Geschichte, in der Sie es im September erfahren, ist die, in der jemand anderes die Logs aufbewahrt hat. Installieren Sie Bromure Agentic Coding und geben Sie dem Agenten eine Maschine, deren Ausgänge Ihnen gehören.