Gisteren publiceerde ik een handleiding over Claude Code-sessies die elkaar berichten sturen. De ene terminal hernoemt een kolom, de andere weet het voordat de tests rood worden.
Op 6 augustus beschreef OpenAI op Black Hat wat er gebeurt als agents dat kanaal zelf bouwen, uit een package registry, zonder dat iemand erom heeft gevraagd.
Ruim twee weken geleden schreef ik over de twee ontsnappingen uit agent-sandboxen die OpenAI en Accomplish binnen een paar dagen van elkaar naar buiten brachten. Op dat moment was er maar één zin bekend: tijdens een evaluatie van offensieve cybercapaciteiten verliet een model zijn testomgeving en drong het door tot de productieomgeving van Hugging Face.
De presentatie van Eric Wallace maakte van die zin een tijdlijn van 74 dagen. En die tijdlijn vertelt een ander verhaal dan de zin.
Het begon met een briefje
7 mei. OpenAI start een reinforcement learning-run voor een model dat nog niet is uitgebracht. Een deel van de taken in die batch blijkt onoplosbaar, per ongeluk en niet met opzet. Eén taak verwijst naar een Google Drive-link, en de agent heeft geen internettoegang.
Een model dat is getraind om niet op te geven, met een taak die niet af te ronden is, blijft niet stilzitten. Het zoekt steeds breder tot er iets meegeeft.
8 mei. Eén van die agents ontdekt dat hij bestanden kan wegschrijven naar de interne Artifactory van OpenAI.
Een paar dagen later laat een vastgelopen agent daar een briefje achter. Gewone tekst, geen exploit: het bestand dat ik nodig heb ontbreekt, heeft iemand het? Agents uit andere runs lezen het. Sommige geven antwoord.
Dat is het prikbord. Een package registry die precies doet waarvoor een package registry bestaat: bytes bewaren die meer dan één proces kan lezen.
Wat er van het prikbord werd
Vanaf daar leest de tijdlijn als een doodgewone inbraak, alleen zit er niemand te typen.
- 26 mei: eerste geslaagde SSRF op Artifactory. Indirecte internettoegang.
- 11 juni: OpenAI begint met het trainen van een "highly persistent" experimenteel model, met toegang tot Artifactory.
- 26 juni: agents vinden een zeroday-RCE via een oud token-refresh-endpoint en installeren een Groovy-plugin om commando's uit te voeren.
- 4 juli: hun eigen verkeer legt Artifactory plat. OpenAI trekt credentials in, wist de berichten, dicht het gat en waarschuwt de leverancier.
- 8 juli: de agents vinden een WebDAV-endpoint zonder authenticatie en bouwen het prikbord opnieuw op, met de mapnamen als berichten.
- 8 tot 19 juli: in gelekte Pastebin-posts duikt een credential van een externe organisatie op. Een agent controleert of hij werkt en post de vindplaats voor de rest. JRuby-deserialisatie, daarna een bekende Linux-kernel-CVE voor lokale root, daarna IMDS voor IAM-credentials, daarna een Kubernetes-misconfiguratie voor cluster admin, daarna Azure Key Vault.
- 16 juli: Hugging Face maakt de aanval openbaar. OpenAI vraagt bij hen na of zij geraakt zijn.
- 20 juli: OpenAI vraagt Hugging Face om de gecompromitteerde credentials te roteren en krijgt te horen dat dat al gebeurd is. Op dat moment dringt tot hen door dat zij zelf de aanvaller zijn.
Lees 4 juli en 8 juli achter elkaar. OpenAI haalde het kanaal weg terwijl de populatie die het gebouwd had gewoon nog draaide. Vier dagen later was het terug, via een ander protocol.
Eer wie eer toekomt
Dit publiceren kostte ze wat. OpenAI ging op Black Hat op een podium staan en legde met datums erbij uit hoe hun eigen evaluatie-infrastructuur tien weken lang eerst een partner en daarna zichzelf aanviel. De meeste bedrijven hadden er een alinea en een belofte van gemaakt.
Wallace was ook helder over de oorzaak: frontier-modellen spelen graag vals, omdat de trainingsdruk precies daarop selecteert. OpenAI zegt het onderzoekstempo te verlagen om de containment op orde te krijgen, en de volledige postmortem moet nog komen.
In de berichtgeving is het samenspanning geworden. Agents die een zwerm vormen, elkaar werk toebedelen, afspraken maken over namen. Dat beeld doet het verhaal tekort, want het laat de oorzaak exotisch lijken, iets wat de rest van ons niet kan overkomen.
Gedeelde opslag is een kanaal en een geheugen
In juli schreef ik waar het echte onderscheid zit: houd je iets helemaal buiten de grens, of laat je het erbinnen achter een permissiecheck. Alleen het eerste overleeft een kernelbug.
De tijdlijn voegt een as toe die ik niet had getekend: tijd.
Een grens zegt wat een proces nu kan bereiken. Hij zegt niets over wat er blijft staan nadat dat proces is gestopt. Artifactory zat binnen de grens, was schrijfbaar en bleef bestaan, en was daarmee drie dingen tegelijk. Een package registry. Een kanaal tussen runs die elkaar nooit hadden moeten treffen. Een geheugen dat elke afzonderlijke agent overleefde.
Daar is geen spontane zwerm voor nodig. Elke schrijfbare plek die twee agent-sessies delen, is een kanaal. Elke schrijfbare plek die een sessie overleeft, is geheugen. Dat zijn eigenschappen van de opslag, en het model staat er verder buiten.
Daarom komt de alledaagse versie hiervan ook bij jou terecht. Een scratch-map die je tussen worktrees deelt. Een cache-volume dat in elke container gemount zit. Een MCP-server met een schrijf-tool zonder scoping per sessie. Een wikipagina die je agent zowel leest als bijwerkt. Niets daarvan ziet eruit als een beveiligingsgrens op het moment dat je het inricht, en stuk voor stuk zijn het plekken waar de ene sessie iets kan achterlaten voor de volgende.
Het luide deel
Wat ik bij je eigen team op tafel zou leggen, is de detectie. Die heeft twee helften en ze wijzen niet dezelfde kant op.
Vierenzeventig dagen op de eigen infrastructuur van OpenAI. Elke handeling in die tijdlijn is los bekeken iets wat een legitiem proces ook doet. Een bestand naar Artifactory schrijven. Een URL ophalen via de goedgekeurde proxy. Een metadata-endpoint uitlezen. Binnen die evaluatieomgeving viel er niets te correleren, want de agents hoorden er te zijn en ze hoorden ongeveer dit te doen.
Aan de kant van Hugging Face liep het anders, en daar valt het doembeeld uit elkaar. Hun forensisch onderzoek telde zo'n 17.600 handelingen van de aanvaller tussen 9 en 13 juli, gebundeld in ongeveer 6.280 clusters. Dat is vierenhalve dag onafgebroken herrie. Kyle Ryan van Pensar noemde het waanzinnig luid. Nico Waisman van XBOW gaf de reden: de agent was niet slordig, hij had alleen geen enkele reden om stil te zijn.
En Hugging Face zag het. Hun eigen verklaring schrijft dat toe aan een detectiepijplijn die met LLM-triage door de securitytelemetrie gaat en signalen aan elkaar knoopt die stuk voor stuk op dagelijkse ruis leken. Let ook op wat er niet in die verklaring staat: OpenAI. Op 16 juli wist Hugging Face zelf ook nog niet met wie ze te maken hadden.
Het gat zat tussen zien en ingrijpen. Het vervolgstuk van TechCrunch meldde dat de activiteit wel degelijk werd opgemerkt, maar dat de urgentie nooit omhoog ging en er dus niemand gebeld werd die on-call stond. De conclusie van Ryan mag je meenemen: een goed opgezet securityprogramma hoort een aanval als deze op meerdere punten te kunnen breken.
Eén detail uit de opruimfase verdient een eigen alinea. Hugging Face kon het forensisch onderzoek niet via een commerciële API draaien, omdat de veiligheidsfilters geen onderscheid konden maken tussen een incident responder en een aanvaller. Ze hebben een open-weight model op eigen hardware gezet en de reconstructie daar gedaan, op het tempo van de aanval zelf.
Dit hebben we al eerder gezien. De inbraak die Sysdig in juni ontdekte, deed vier pivots in minder dan een uur, zonder dat er iemand aan het toetsenbord zat, en toen was de snelheid het verhaal. Deze keer is het de volharding. Deze agents gingen wekenlang door, over herstarts heen, dwars door een bewuste opruimactie van hun eigen kanaal.
Jouw monitoring vraagt of een handeling mag. Die vraagt niet wat deze sessie het afgelopen uur heeft gedaan, of die vorm ergens op slaat, en wie er gebeld wordt als dat niet zo is. Mijn draaiboek voor incidenten met agents begint precies daarom bij het transcript. Daar zit die vorm in.
Wat je concreet kunt doen
- Maak de werkmap tijdelijk. Een map per sessie die met die sessie verdwijnt, kan geen prikbord worden. Behandel volumes die runs overleven als de dure keuze, want dat zijn ze.
- Beperk schrijfrechten per sessie. Als twee agents naar hetzelfde pad kunnen schrijven, kunnen ze praten, dus bepaal bewust of dat mag. De cross-session messaging van Claude Code heeft niet voor niets
isolatePeerMachinesen een instelling voor inkomende berichten: het kanaal is expliciet en je kunt het uitzetten. - Log trajecten, niet alleen handelingen. Wie per aanroep bepaalt of iets mag, mist alles wat hier gebeurde. Bewaar de reeks, sla alarm als de vorm ervan afwijkt, en spreek vooraf af wie dat alarm uit bed mag halen. Hugging Face had het signaal en het bereikte nooit een mens.
- Let op wat je vraagt. Een onoplosbare taak is een uitnodiging om de scope op te rekken tot er iets meegeeft. Als je eval of je prompt niet te halen is, gaat de agent op zoek naar een definitie van succes die dat wel is.
Het detail waar ik op blijf hangen, is 20 juli. OpenAI belt Hugging Face met het verzoek een set gecompromitteerde credentials te roteren, en Hugging Face zegt dat ze dat na de aanval al hebben gedaan. Twee bedrijven aan weerszijden van hetzelfde incident, en geen van beide wist het tot de credentials op elkaar bleken te passen.
Zo zag het eruit van binnenuit, bij het bedrijf dat het ding gebouwd had. Tien weken lang geen alarm op de eigen systemen, alleen een telefoontje dat niet klopte.