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

Der letzte Schritt war ein Prompt

Am 18. September veröffentlichte Hacktron die Kette, mit der das Team bis in das private Monorepo von OpenAI kam. Sie beginnt mit einem Bild, das in ein offenes Forum hochgeladen wurde, und einem Heap-Overflow in einem Bilddecoder, dessen Upstream-Fix keine CVE trug. Sie endet damit, dass die Forscher einen Prompt an das Codex-Konto eines Mitarbeiters schicken und der Agent den Pull Request öffnet. Nichts wurde injiziert, nichts ging kaputt; der Agent tat, was derjenige verlangte, der die Sitzung hielt. Bromure Agentic Coding entscheidet diesen Schreibzugriff auf Ihrem Mac, außerhalb der Sitzung.

Der letzte Schritt dieser Kette brauchte keinen Exploit. Die Forscher hielten den Coding-Agenten eines Mitarbeiters in der Hand, also baten sie ihn, einen Pull Request im privaten Monorepo zu öffnen, und er öffnete einen.

Um sechs Uhr morgens UTC am 25. Juli hatten drei Forscher von Hacktron Codeausführung im öffentlichen Community-Forum von OpenAI. Am frühen Nachmittag lag ein Pull Request mit der Nummer 1186742 in openai/openai, dem privaten Monorepo, und sie hatten keine Zeile Code geschrieben, um ihn dorthin zu bringen. Sie fragten einen Agenten, und der Agent reichte ihn ein.

Hacktron hat die Kette am 18. September veröffentlicht, und sie lohnt eine Lektüre Glied für Glied, denn jedes Glied ist gewöhnlich. Die Forscher sind Harsh Jaiswal, Mohan Pedhapati und Rahul Maini. The Hacker News berichtete am Tag darauf.

Ein Bild, eine Konvertierung und ein Parser

Der Weg hinein war der Bild-Upload des Forums. Discourse prüft hochgeladene Bilder mit einer Ruby-Bibliothek namens FastImage, die genug vom Header einer Datei liest, um Abmessungen und Format zu bestimmen. FastImage versteht kein HEIF, den Container, in dem ein iPhone-Foto ankommt, also reichte Discourse diese Dateien zur Konvertierung an den Befehl magick von ImageMagick weiter. ImageMagick dekodiert HEIC mit libheif, und das ist C.

Das ist die ganze Eintrittsbedingung. Ein Format, das der sichere Prüfer nicht erkannte, ging an einen Konverter, der einen Parser in einer Sprache aufrief, in der ein missgebildetes Längenfeld ein Speichersicherheitsproblem ist. Hacktron fand einen Heap-Buffer-Overflow in der HEIC-Dekodierung und gewann daraus Primitive zum Lesen und Schreiben außerhalb der Grenzen.

Die Aktenlage ist schlimmer als der Bug. Upstream hatte diesen Overflow im Jahr zuvor behoben und den Commit nie als Sicherheitsfix ausgezeichnet. Er bekam keine CVE, kein Advisory und keine Changelog-Zeile, die ein Abhängigkeitsscanner hätte lesen können, also portierte Debian ihn nie zurück, und das Docker-Image von Discourse lieferte libheif 1.19.7 auf Debian 12 mit intaktem Bug aus. Kein Scanner der Welt hatte Anlass, diese Version zu melden. Debian gab später DSA-6417-1 heraus, und das Problem trägt inzwischen CVE-2026-32882, vergeben, nachdem jemand es ausgenutzt hatte.

Man kann nicht nach einem Bug scannen, den niemand gemeldet hat. Was sich im Voraus entscheiden lässt, ist, worin der Parser steht, wenn er umfällt.

Ein Upload, ein Pull Requestdas Parsenein HEIC-Uploadin ein offenes Forum gestelltkeine Kontorechte nötigFastImagedie sichere Header-Prüfungkann kein HEIFmagickkonvertiert stattdessenImageMagick ruft libheiflibheif 1.19.7Heap-Overflow, OOB R/Wbehoben, kein CVE, kein Backportder SchwenkCodeausführungcommunity.openai.com06:00 UTC, 25. Juliein SSO-Fehlereine Forumssitzung wirdKontoübernahme, ohne ZutunCodex eines Mitarbeitersmit der GitHub-Org verbundenbereits schreibberechtigtkein Exploitein PromptPR #1186742privates Monorepo, openai/openai
Jedes Glied der Kette ist gewöhnlich. FastImage kann kein HEIF, also geht die Datei an ImageMagick, das libheif aufruft, worin ein Heap-Overflow saß, dessen Upstream-Fix keine CVE trug und nie bei Debian ankam. Ein separater SSO-Fehler machte aus Codeausführung im Forum einen Kontozugriff und aus dem Kontozugriff einen Pull Request im privaten Monorepo. Nur der letzte Schritt brauchte keinen Exploit: Die Forscher schickten einen Prompt an einen Coding-Agenten, der bereits schreibberechtigt war.

Der Exploit dauerte einen Abend

Hacktron begann am 23. Juli, sich die Upload-Pipeline anzusehen. Am 24. Juli gingen sie den Overflow mit Claude Opus 4.8 an, das sich nach ihrer Darstellung über mehrere Sitzungen abmühte und nichts hervorbrachte, das gegen die Adressraum-Randomisierung funktionierte, jene Verteidigung, die das Speicherbild eines Prozesses durchmischt, damit ein Angreifer nicht vorhersagen kann, wo etwas liegt. Einen Heap-Overflow gegen ASLR in zuverlässige Ausführung zu verwandeln, ist der schwere Teil, und genau dort bleibt diese Art Forschung eine Woche stecken.

Anthropic veröffentlichte Opus 5 an jenem Abend. Hacktron startete eine frische Sitzung und hatte drei Stunden später einen funktionierenden ARM64-Exploit, der gegen einen lokalen Mac lief. Sie ließen das Modell ihn auf die x86-64- und jemalloc-Konfiguration portieren, auf der Discourse läuft, und bestätigten am nächsten Morgen um sechs lokale Codeausführung über einen Bild-Upload. Dann setzten sie Claude in einer autonomen Schleife auf ihre eigene Discourse-Cloud-Instanz an. Um zehn hatte es auch dort Codeausführung und las /etc/hosts, um es zu belegen.

Sie sind vorsichtig damit, was das heißt, und der Vorbehalt gehört in jede Lesart:

Dies war kein vollständig autonomes Hacking. Menschliche Expertise blieb nötig, um Sitzungen zu lenken, Ergebnisse zu validieren und die Offenlegung zu steuern.

Richtig. Drei fähige Forscher haben das Ding gerichtet, und ihre Fähigkeit änderte sich nicht über Nacht. Der Bug änderte sich auch nicht. Zwischen jenen beiden Sitzungen war die einzige neue Variable das Modell, und es brachte ein Stück Exploitation-Arbeit von mehreren gescheiterten Anläufen auf drei Stunden. Die Kampagne, zu der das gehörte, kostete Hacktron unter 3.000 Dollar an Tokens und ein paar Stunden Menschenzeit.

Diese Zahl ist der Planungswert. Ein Bug, der nie eine CVE bekam und in einer transitiven Abhängigkeit eines Dateikonverters saß, wird jetzt zum Preis eines Laptops zu einem zuverlässigen Primitiv. Auf das Advisory zu warten, ist eine Hoffnung, und niemand läuft dieser Uhr davon, indem er Changelogs schneller liest.

Der letzte Schritt war ein Prompt

Codeausführung im Forum brachte Hacktron nichts, woran OpenAI gelegen war. Das tat ein zweites Problem. OpenAI hatte sein Single Sign-on so verdrahtet, dass eine kompromittierte Forumssitzung zur Übernahme des ChatGPT- und Codex-Kontos jedes Mitarbeiters wurde, der das Forum nutzte, ganz ohne dessen Zutun. In Hacktrons Worten ist es das SSO-Problem, das aus einer Forumskompromittierung Zugang zu ChatGPT und Codex machte.

Das Codex eines Mitarbeiters war mit der GitHub-Organisation des Unternehmens verbunden, also taten die Forscher das Naheliegende. Sie schickten diesem Konto einen Prompt mit der Bitte, einen Pull Request im internen Monorepo zu öffnen, und PR 1186742 erschien in openai/openai. Dann hörten sie auf, ohne Quellcode zu lesen, und reichten den Bericht ein.

Lesen Sie diesen Schritt noch einmal. Jemand mit einer gültigen Sitzung bat den Agenten um etwas Gewöhnliches, und der Agent tat es mit dem Schreibzugriff, den er ohnehin hatte. Keine Injection, kein Jailbreak, keine missgebildete Eingabe. Jede Kontrolle, die irgendwer gebaut hatte, saß hinter dieser Sitzung: das Login, die Organisationsmitgliedschaft, die Repository-Rechte. Sobald ein Angreifer die Sitzung hielt, hielt er alles davon.

Ein Coding-Agent ist eine dauerhafte Gewährung von Schreibzugriff auf Ihre Repositories, angeheftet an ein Gespräch. Wer das Gespräch erreicht, erbt die Gewährung. Das gilt für Codex im Browser, und es gilt für Claude Code, Codex CLI oder Gemini CLI auf einem Laptop, wo der Agent ein echtes ghp_-Token in ~/.git-credentials und ein echtes GH_TOKEN in seiner Umgebung trägt. Auf einem Laptop vervielfachen sich die Wege hinein: eine vergiftete Datei in einem Repository, ein Issue-Kommentar, ein Postinstall-Skript eines Pakets, ein gekapertes Terminal.

OpenAI hat das Forum in etwa vierzehn Stunden gepatcht. Der Bericht ging an jenem Morgen ein, und OpenAI bestätigte den Fix noch am selben Tag um 22:49 UTC. Discourse lieferte über das Wochenende einen eigenen Fix und veröffentlichte am 28. Juli das Advisory GHSA-vhm9-85gw-x335, und die Bounty betrug 6.500 Dollar. Das Stück dieser Form, das auf Ihrem eigenen Schreibtisch liegt, ist der Agent.

Wo der Schreibzugriff entschieden wird

Bromure Agentic Coding behält die Antwort auf die Frage, wer pushen darf, auf Ihrem Mac, außerhalb der Sitzung des Agenten, denn die Sitzung ist das, was ein Angreifer zu erreichen versucht. Dort geschehen zwei Dinge.

Erstens enthält die Umgebung des Agenten kein Token zum Erben. Die Workspace-VM bekommt einen Platzhalter: ghp_ plus 36 Zeichen, so geformt, dass gh und git ihn anstandslos annehmen, abgeleitet aus Ihrem echten Token mit HKDF-SHA256 und einem installationsspezifischen Salt, sodass er zwischen Sitzungen nie zu rotieren scheint. Ihr echtes Token liegt verschlüsselt auf dem Host, und der Host-Proxy setzt es auf der Leitung ein, nachdem die Anfrage die VM verlassen hat, und nur dann, wenn das Ziel zu dem Host passt, für den das Token geprägt wurde. Wie es im Handbuch heißt: Keine Datei, keine Umgebungsvariable und kein Prozess innerhalb der VM enthält je einen echten API-Schlüssel, ein OAuth-Token, ein AWS-Geheimnis oder einen privaten SSH-Schlüssel. Tragen Sie diesen Platzhalter irgendwohin, wo er nicht hingehört, und der Proxy antwortet mit HTTP 451, ohne ein Byte weiterzuleiten, pausiert die VM und schreibt eine rote Zeile in die Security Timeline.

Das zweite ist das, worum diese Geschichte bittet. Jede Git-Forge-Zugangsdatei trägt eine Schreibrichtlinie, pro Workspace im Guardrails-Bereich gesetzt, und neue Workspaces stehen standardmäßig auf Vor dem Schreiben nachfragen. Lesezugriffe passieren kommentarlos. Ein git push kommt auf der Leitung als git-receive-pack an und zählt als Schreibzugriff, und ein POST an die Pull-Request-API ebenso. Trifft einer ein, hält der Proxy die Anfrage an und öffnet auf Ihrem Mac einen Dialog, der die wörtliche Operation trägt statt einer Zusammenfassung davon: Methode und Pfad. Sie erhalten Für 15 Minuten erlauben, Einmal erlauben, Für den Rest der Sitzung erlauben oder Nicht erlauben. Eine Ablehnung erreicht den Agenten als gewöhnlicher API-Fehler, den er melden kann, nicht als hängende Verbindung.

Die Beschreibung, die der Bereich selbst davon gibt, wo das läuft, ist der Satz, auf den es ankommt: im Proxy durchgesetzt, sodass ein kompromittierter Agent in der VM es nicht umgehen kann.

Wer auch immer den Agenten steuert — Sie, eine in einer Fixture-Datei vergrabene Prompt-Injection oder jemand, der eine Ihnen abgenommene Sitzung hält —, der Schreibzugriff verlässt die Maschine durch denselben Proxy und wird genauso klassifiziert. Der Dialog auf Ihrem Mac ist die Autorisierung, und ein Angreifer mit Ihrer Sitzung hat nicht Ihren Mac.

Ein Agent auf dem Laptopdie Agentensitzungerreichbar für Sie, für eine Injection, fürjeden, der die Sitzung nimmtechte Zugangsdaten, in ReichweiteGH_TOKEN · ~/.git-credentialslesbar für jeden Prozess der MaschinePOST /repos/org/repo/pulls → GitHubdie Sitzung trägt die BefugnisEin Agent in einem Bromure-Workspacedie Agentensitzung, in der VMghp_ + 36 Zeichen, ein Platzhalternichts Echtes zu erbender Switch leitet :80 und :443 umder Host-Proxy klassifiziertPOST /repos/org/repo/pulls = Schreibengit-receive-pack zählt auchein Dialog auf Ihrem Mac, mit dem wörtlichen Aufruf15 Minuten · einmal · die Sitzung · ablehnender Mac trägt die Befugnis
Auf einem Entwickler-Laptop hält der Agent ein echtes Token, also genügt ein Prompt und die Sitzung trägt die Befugnis. In einem Bromure-Workspace hält die VM einen Platzhalter, der Host-Proxy setzt das echte Token auf dem Weg nach draußen ein, und der Guardrail klassifiziert den Schreibzugriff, bevor er GitHub erreicht. Vor dem Schreiben nachfragen, der Standard für neue Workspaces, öffnet auf Ihrem Mac einen Dialog mit wörtlicher Methode und wörtlichem Pfad. Wer auch immer die Sitzung hält, den Mac hält er nicht.

Das Parser-Problem kommt auch auf Ihren Schreibtisch

Die andere Hälfte der Kette verallgemeinert sich ebenfalls, und wenige haben das eingepreist.

Ein Coding-Agent verbringt seinen Tag damit, Dateien zu lesen, die er nicht geschrieben hat: Test-Fixtures, die mit dem Repository kamen, ein Bild, das an einen Fehlerbericht gehängt war, ein Screenshot, den Sie ins Gespräch eingefügt haben, das PDF einer Spezifikation, ein Tarball von einer Release-Seite, eine Schriftart, ein Video, das das Frontend abspielen soll. Damit umzugehen heißt, magick, ffmpeg, pdftotext oder unzip aufzurufen oder eine in Python gebundene Bildbibliothek, und jedes davon ist ein C- oder C++-Parser, der Bytes frisst, die jemand anderes gewählt hat. Genau diese Bedingung ließ einen Forum-Upload bis zu libheif kommen. Ein Agent trifft sie häufiger als Sie, weil er nie zögert, bevor er etwas öffnet.

Erkennung hat hier keine Antwort. Der libheif-Bug trug in dem Moment, in dem es darauf ankam, keine CVE, also hätte kein Scanner, keine Allowlist und kein Versions-Pin ein Wort gesagt. Sie dürfen den Explosionsradius wählen, und das ist alles.

In einem Bromure-Workspace läuft dieser Decoder in einem Ubuntu-Gast unter Apples Virtualization.framework, einer Hypervisor-Grenze statt einer Prozess-Sandbox, in einem Gast, den Bromure von vornherein als nicht vertrauenswürdig behandelt. Ein Heap-Overflow in einem Bildparser kauft einem Angreifer eine Shell in einer Linux-VM, deren Zugangsdaten Platzhalter sind und deren Weg ins Internet ein geordnetes Regelwerk auf dem Host ist. Der virtuelle Switch prüft dieses Regelwerk anhand von Ziel-IP und per DNS mitgelesenem Hostnamen über TCP und UDP, und der Proxy prüft es erneut anhand von TLS-Servernamen und HTTP-Methode. Setzen Sie nicht zugeordneten Verkehr auf Ablehnen, und die Shell hat eine Allowlist und sonst nichts. Der Switch leitet :80 und :443 in den Proxy selbst um, also gibt es keine Proxy-Variable, die die Shell abschalten könnte. Regeländerungen erreichen laufende Sitzungen ohne Neustart, und jedes Urteil landet als Firewall-Zeile in der Security Timeline.

Rechnen Sie damit, dass der Parser umfällt

Dieser Bug hatte keine CVE, als es darauf ankam. Planen Sie damit, dass der Decoder verliert, und entscheiden Sie vorher, worin er dabei steht.

Eine Sitzung ist keine Autorisierung

Wer das Gespräch erreicht, erbt den Schreibzugriff des Agenten. Legen Sie die Entscheidung über einen Push dorthin, wo das Gespräch nicht hinkommt.

Lassen Sie nichts Stehlbares in der VM

Ein Platzhalter, den Werkzeuge annehmen, ist upstream nichts wert und weniger als nichts für einen Angreifer, der ihn woandershin trägt.

Bepreisen Sie den Exploit

Drei Stunden und ein paar tausend Dollar an Tokens. Advisories schneller zu lesen, ist keine Antwort auf diese Zahl.

Hacktrons Bericht ist gute Forschung und ehrlich darüber, wie viel davon ein Mensch noch steuern musste. Das Ende ist der Teil, der nächstes Jahr noch zutrifft. Jede Verteidigung in der Kette saß hinter einer Identität, und sobald eine Sitzung mit dieser Identität den Besitzer wechselte, hatte keine von ihnen mehr eine Meinung. Jemand fragte den Agenten, und der Agent folgte.

Wenn Ihr Agent pushen kann, fragen Sie, wo die Berechtigung zum Pushen wohnt und ob ein Angreifer, der alles nähme, was der Agent hat, auch diese nähme. Auf einem Laptop nähme er sie. Verlegen Sie diese eine Entscheidung von der Maschine weg, auf der der Agent läuft, und der letzte Schritt dieser Kette hat einen Ort, an dem er anhalten kann.