Das Repo war wirklich Microsofts
Am 5.–6. Juni 2026 schob der Miasma-Wurm credential-stehlenden Code in 73 Repositories über vier von Microsofts eigenen GitHub-Organisationen — Azure, Azure-Samples, microsoft, MicrosoftDocs — darunter Azure/functions-action, die offizielle Deploy-Action, und durabletask, ein Repo, das im Mai bereits einmal bereinigt worden war. Diesmal wartete die Nutzlast nicht auf npm install. Sie feuerte in dem Moment, in dem ein Entwickler das Repository in Claude Code, Cursor, Gemini CLI oder VS Code öffnete. Hier ist, warum das Vertrauenssignal — „es ist ein Microsoft-Repo“ — erneut die Angriffsfläche war, und was sich ändert, wenn der Agent, der es öffnet, in einer Bromure-VM pro Profil lebt, hinter einem Credential-Broker, einem Read-Write-Guardrail und einem Paket-Cooldown.
Vor einer Woche ritt der Wurm auf Red Hats npm-Scope herein und feuerte
durch einen preinstall-Hook. Diese Woche ritt er auf Microsofts
GitHub herein und brauchte überhaupt keine Installation. Miasma
pflanzte projekt-gescopte Konfiguration in 73 Microsoft-eigene
Repositories — Azure/functions-action, die offizielle Deploy-Action,
darunter — und die Nutzlast führte sich aus in dem Moment, in dem ein
Entwickler das Repo in Claude Code, Cursor, Gemini CLI oder VS Code
öffnete. Das Klonen war nicht der Auslöser. Es in Ihrem Agenten zu
öffnen war es.
Ein Entwickler, der Azure/functions-action klont, um ein
fehlschlagendes Deploy zu debuggen, zögert nicht, und der Agent, auf den
er ihn richtet, auch nicht. Es ist ein First-Party-Repository aus
Microsofts eigener Azure-Organisation — die kanonische Quelle der
GitHub-Action, die das halbe Ökosystem als
Azure/functions-action@v1 referenziert. Es gibt keinen Maintainer zu
prüfen, denn der Maintainer ist Microsoft. Es gibt keinen Namen, bei dem
man die Augen zusammenkneifen müsste, denn der Name ist genau das, was er
sein sollte. Also wird das Repo geöffnet, und der Agent liest die
Konfiguration des Projekts, so wie es jedes moderne Coding-Tool beim
Öffnen des Ordners tut — und eine dieser Konfigurationsdateien zeigt auf
einen Befehl, und der Befehl ist ein rund 4,3 Megabyte großer Blob,
der anfängt, das Dateisystem nach Schlüsseln zu durchsuchen.
Wir schrieben die npm-Hälfte genau dieser Kampagne auf vor sieben Tagen. Miasma ist derselbe Wurm — eine Variante des „Mini-Shai-Hulud“-Codes, den TeamPCP Mitte Mai öffentlich freigab — und die unbequeme Tatsache, die er demonstriert, ist dieselbe, eine Drehung weiter geschraubt: seriöse Quelle ist keine Sicherheitskontrolle. Es fühlt sich wie eine an. Der Großteil der Supply-Chain-Ratschläge lehnt sich daran an. Und am 5. Juni kaufte es exakt nichts, gleich zweifach: der Namespace war Microsofts, und die Ausführung kam nicht von einem Paket, das Sie zu installieren wählten. Sie kam vom Öffnen eines Ordners.
Was Miasma mit Microsofts Repositories tat.
Am 5.–6. Juni 2026 deaktivierte GitHub 73 Repositories über vier Microsoft-GitHub-Organisationen, nachdem bösartige Commits in sie geschoben worden waren, laut The Hacker News und einer detaillierten Analyse von StepSecurity. Redmond Magazine berichtete am 8. Juni darüber. Die Aufschlüsselung:
- Azure — 49 Repositories, darunter
Azure/functions-action(die offizielle Functions-Deployment-Action) und die Language-Worker für .NET, Python, Java, Go und PowerShell. - microsoft — 10 Repositories.
- Azure-Samples — 13 Repositories.
- MicrosoftDocs — 1 Repository.
Die Form, auf ihre Mechanik heruntergebrochen:
- Der Einstiegspunkt war ein zuvor kompromittierter
Contributor-Account mit Commit-Zugang, genutzt, um bösartige Commits
direkt in die Repositories zu schieben — markiert mit
[skip ci], sodass die Änderungen an den CI/CD-Checks vorbeirutschten, die sonst gelaufen wären. - Der Commit pflanzte projekt-gescopte Konfiguration — die Art Datei, die ein Coding-Agent oder eine IDE liest und automatisch ausführt, wenn man den Ordner öffnet: ein Editor-Task, ein Agent-Hook, ein projektdefinierter MCP-Server. Das ist dieselbe Klasse von Vertrauensgrenze, die Adversa AIs TrustFall über Claude Code, Cursor CLI, Gemini CLI und Copilot CLI demonstrierte — alle vier führen projektdefinierte Konfiguration direkt nach dem Folder-Trust-Prompt aus.
- Die Nutzlast — rund 4,3 MB obfuskierter Code — führte sich aus,
als das Repository in Claude Code, Gemini CLI, Cursor oder VS Code
geöffnet oder über ein
npm test-Script ausgeführt wurde. Nicht beim bloßen Klonen. Der Agent auf den geklonten Baum zu richten ist das, was sie ausführte. - Bei der Ausführung durchsuchte sie den Host nach GitHub-Tokens,
AWS-Schlüsseln, Azure-Service-Principals, GCP-Credentials, npm- und
PyPI-Publishing-Tokens, SSH-Schlüsseln und
.env-Dateien, dann nutzte sie den gestohlenen Zugang, um sich selbst weiterzucommitten — was sie zu einem Wurm macht statt zu einem Einmaleffekt.
Ein Detail ist es wert, sich daran aufzuhalten: Azure/durabletask war
unter den getroffenen Repositories — und es war im Mai bereits
kompromittiert worden, in der TeamPCP-Kampagne, und bereinigt. Ein
Repo, das einmal behoben wurde, wurde fünf Wochen später neu vergiftet.
Bereinigung ist kein Zustand, den man erreicht und behält; es ist ein
Zustand, aus dem man in dem Moment wieder herausfällt, in dem ein
weiteres Credential in der Kette übernommen wird.
Es lohnt sich, ebenso präzise zu sein, was nicht geschah. Microsofts
Unternehmensnetzwerk wurde nicht kompromittiert. Azure, der
Cloud-Dienst, wurde nicht kompromittiert. Keine Kundendaten und kein
Produktivsystem wurden berührt. Das war ein Angriff auf
Quellcode-Repositories — und seine am breitesten spürbare Folge
hatte mit der Malware überhaupt nichts zu tun: in dem Augenblick, in dem
GitHub Azure/functions-action deaktivierte, hörte jede Pipeline auf
Erden, die Azure/functions-action@v1 referenzierte, auf aufzulösen.
Microsoft war der prominenteste Träger. Die tatsächlich Übernommenen
waren die Entwickler, die die vergifteten Repos zwischen dem 3. und 5.
Juni in einem Agenten öffneten und denen die Credentials von ihren
eigenen Maschinen gewischt wurden.
Dasselbe Repo, geöffnet innerhalb von Bromure Agentic Coding.
Bromure Agentic Coding lässt Ihren Coding-Agenten
innerhalb einer Linux-VM pro Profil laufen — eigener Kernel, eigenes
Dateisystem, eigener Netzwerk-Stack, auf Apples Virtualization-Framework.
Ein Profil ist ein kohärenter Arbeits-Scope: dieser Kunde, dieses
interne Produkt, dieses Open-Source-Repo, das Sie zum Debuggen eines
Deploys geklont haben. Sie klonen Azure/functions-action in dieses
Profil und öffnen es dort drin mit Ihrem Agenten. Der Auslöser beim
Öffnen des Ordners feuert genau wie konstruiert. Die Nutzlast läuft. Und
dann geht sie auf einem Host, den sie nicht erreichen kann, auf die Suche
nach Schlüsseln.
Denn die Credentials sind nicht im Profil. Die VM wird mit Stubs
ausgeliefert — gefälschten Tokens, die für git, gh, aws,
kubectl, npm und alles andere, das einen Authorization-Header
erwartet, echt aussehen. Ein Proxy auf Ihrem Mac sitzt vor jeder
Verbindung, die die Sandbox verlässt, erkennt den Stub und tauscht ihn
auf dem Draht gegen das echte Secret aus, während die Anfrage hinausgeht
(die Sandbox, die den Schlüssel hielt
führt durch den Mechanismus). Der echte GitHub-PAT, der echte
AWS-Schlüssel, das echte Azure-Principal — keines von ihnen berührt eine
Datei, eine Umgebungsvariable oder eine Speicherseite, die die VM lesen
kann. SSH-Schlüssel verlassen den macOS-Keychain überhaupt nicht; nur der
ssh-agent-Socket wird hineingeleitet, so wie OpenSSH es immer
beabsichtigt hat.
Gehen Sie also Miasmas Durchsuchung durch diese Grenze. Die Nutzlast
liest die Umgebung nach $GITHUB_TOKEN und findet einen Stub. Sie liest
~/.aws und findet nichts. Sie liest ~/.npmrc und findet kein
Publish-Token. Sie liest ~/.ssh und findet keine Schlüsseldatei — da ist
ein hineingeleiteter Socket, kein privater Schlüssel auf der Disk. Der
4,3-MB-Blob läuft bis zum Ende durch, genau wie geschrieben. Er
exfiltriert nur eine Box, die nie Ihre Schlüssel hielt, auf der falschen
Seite einer hardware-erzwungenen Grenze von allem, was zählt.
Der Propagationsschritt ist ein Write, und Writes bekommen einen Prompt.
Schlüssel zu stehlen ist nur die Hälfte von Miasma. Die andere Hälfte ist
Verbreitung: er nutzte gestohlenen GitHub-Zugang, um sich selbst ins
nächste Repository zu committen, und das ist es, was eine Handvoll
vergifteter Repos in 73 verwandelte. Selbst in einem Profil, das legitim
Push-Zugang hat — sagen wir, Sie klonten functions-action genau, weil
Sie beabsichtigen, einen PR dagegen zu öffnen — muss der
Propagationsschritt des Wurms immer noch durch den Proxy hinausgehen, und
genau dort treffen ihn die Guardrails.
Guardrails lesen die Operation, nicht nur die Verbindung — sie
unterscheiden einen Read von einem Write. Ein git fetch ist ein Read;
ein git push ist ein Write. Setzen Sie das GitHub-Credential eines
Profils auf bei Write fragen, und in dem Moment, in dem der Agent nach
einem zustandsändernden Aufruf greift — dem git-receive-pack, das der
Wurm braucht, um seine Config zurückzucommitten, einem DELETE gegen eine
API, einem Terminate* an EC2 — stoppt Bromure ihn auf dem Draht und
blendet auf Ihrem Mac einen Prompt ein, der das Verb, das Ziel und das
Profil nennt. Der Grant, den Sie geben, ist zeitlich begrenzt: fünfzehn
Minuten für ein Release, einmalig für die unheimlichen, niemals, wenn die
Anfrage keinen Sinn ergibt. Reads unterbrechen Sie nie; der Agent fetcht
und greppt und liest den ganzen Tag. Es ist die Mutation, die
pausiert.
Das ist der Unterschied zwischen „der Agent hat ein Token“ und „der Agent kann mit dem Token machen, was er will“. Miasmas ganzer Verbreitungsmechanismus ist ein Write, von dem der Agent Ihnen nie sagte, dass er ihn machte — und ein Write, von dem der Agent Ihnen nie sagte, dass er ihn machte, ist genau das, wofür der Read-Write-Prompt gebaut ist. Der Push, der den Wurm propagiert, wird zu einem Dialogfeld, bei dem Sie auf Nicht erlauben klicken, genauso wie „der Agent löschte die Produktionsdatenbank“ aufhört, ein Postmortem zu sein und zu einem Prompt wird, den Sie ablehnten.
Die Version war Stunden alt, und Bromure lässt Pakete altern.
Es gibt einen zweiten Weg, auf dem Miasma — und die breitere
Mini-Shai-Hulud-Linie — einen Entwickler erreicht: nicht durch ein Repo,
das Sie öffnen, sondern durch ein frisch vergiftetes Paket, das der
Agent während seiner Arbeit installiert. Die Red-Hat-Hälfte dieser
Kampagne war genau das, ein preinstall-Hook auf 32 Paketen in einem
vertrauenswürdigen Scope. Und das brutale Detail jener Vorfälle ist das
Timing: eine kompromittierte Version wird typischerweise innerhalb von
Stunden erwischt und zurückgezogen — aber das sind genau die Stunden,
in denen ein autonomer Agent, der unbeaufsichtigt läuft, sie ziehen
könnte.
Bromures Supply-Chain-Schicht verwandelt denselben Grenz-Proxy in einen Scanning-Checkpoint, und sie tut die zwei Dinge, die gegen eine taggleiche Kompromittierung tatsächlich zählen:
- Sie erzwingt einen Scan jedes Fetches gegen socket.dev wie auch gegen OSV. OSV erwischt bekannte CVEs oberhalb der Schweregradschwelle, die Sie setzen. socket.dev erwischt, was die Vulnerability-Datenbanken noch nicht aufgeholt haben — bösartige Install-Scripts, verhaltensbasierte Malware, Typosquats, die gerade veröffentlichte Kompromittierung. Ein markiertes Release wird blockiert, bevor das Tarball je in der VM landet. Entscheidend ist, dass der Scan unterhalb des Agenten läuft, am Proxy: wie auch immer der Agent seine eigene Config umschreibt, um Sie zu umgehen, der Fetch verlässt ihn trotzdem durch die Grenze, die er nicht überqueren kann.
- Sie erzwingt einen Cooldown. Bromure stellt jedes Release unter
Quarantäne, das in den letzten zwei Tagen veröffentlicht wurde —
einstellbar — sodass eine vor einer Stunde hochgeladene Version in
diesem Profil schlicht nicht installierbar ist, während das Ökosystem
aufholt. Gegen einen Wurm, dessen ganzes Zeitfenster die Lücke zwischen
publish und yank ist, ist ein Cooldown keine Heuristik darüber, ob
ein Paket schlecht aussieht. Es ist eine Weigerung, der Erste zu sein,
der es herausfindet. Kombinieren Sie es mit dem Install-Script-Stripping,
das Bromure im Flug erledigt —
postinstall-Hooks aus dem Tarball ziehen und den Metadaten-Hash fixen, sodass die Installation weiterhin verifiziert — und das Paket, das doch landet, landet inert.
Für Miasma im Speziellen ist der Repo-Open-Vektor die Schlagzeile. Aber
dieselbe Kampagne verbreitet sich auch durch Pakete, und der Cooldown ist
die Kontrolle, die die npm-Seite davon ausgehungert hätte: ein frisches
@redhat-cloud-services-Release, oder eine frisch vergiftete transitive
Abhängigkeit, gezogen während des Debuggens jenes Microsoft-Repos, sitzt
in Quarantäne durch genau die Stunden, in denen es gefährlich ist.
Wo dich das nicht rettet.
Ein Push, den du genehmigst, ist ein Push, der passiert.
Das Read-Write-Guardrail erwischt den Write, von dem der Agent dir
nichts sagte. Es liest das Diff nicht. Wenn du legitim nach
functions-action pushst und den Prompt genehmigst, leitet Bromure
den Push weiter — einschließlich, im Prinzip, eines vergifteten
Workflows, den du im Diff nicht bemerkt hast. Lies, was du
genehmigst. Der
Session-Trace sagt dir,
welche Diffs zu lesen sind.
Der Cooldown ist ein Fenster, keine Mauer.
Zwei Tage sind auf die beobachtete Publish-zu-Yank-Lücke abgestimmt, aber ein geduldiger Angreifer kann länger auf einer kompromittierten Version sitzen als der Cooldown und am dritten Tag immer noch installierbar sein. Der Cooldown hungert taggleiche Würmer aus; er bürgt nicht für ein Paket, das bloß alt geworden ist. socket.dev und OSV müssen weiterhin ihren Teil tun.
Das Profil ist langlebig, also bleibt Persistenz bestehen.
Ein Bromure-Profil ist keine Wegwerf-Disk. Eine Nutzlast, die sich selbst in einen Startup-Pfad innerhalb des Profils schreibt, kann in die nächste Session in diesem Profil überleben. Was sie aufwacht vorfindet, ist ein Gast ohne Host-Schlüssel und ein Broker, der nur kurzlebige, geprompete, scope-limitierte Tokens spricht — Präsenz in einer Box, in der nichts drin ist — aber dennoch Präsenz.
Scope den Broker mit Absicht.
Wenn ein Profil heute bereitgestellt ist, um in ein Repo zu pushen, und dieses Profil heute Miasma ausführt, geht ein genehmigter Write durch. Broker-Grants funktionieren, weil sie schmal sind. Ein Profil, das ein Repo nur lesen muss, sollte es nicht schreiben können; ein Profil, das nie veröffentlicht, sollte kein Publish-Token halten. Isolation begrenzt die Explosion; Scoping entscheidet, wie groß sie je hätte sein können.
Das nächste vertrauenswürdige Repo ist irgendwo schon geklont.
Die Lehre des TanStack-Wurms war,
dass die Lockfile und die Signatur keine Verteidigungen sind. Die Lehre
des Red-Hat-Scopes war, dass es
auch der Publisher nicht ist. Microsoft fügt das nächste Korollar hinzu:
auch nicht das Repository, und der Auslöser muss nicht einmal eine
Installation sein, die du wähltest — er kann ein Ordner sein, den dein
Agent öffnete. Das Azure/functions-action-Repo tat nichts falsch,
indem es vertrauenswürdig war. Vertrauenswürdig zu sein ist der ganze
Zweck einer kanonischen First-Party-Action, und es ist genau das, was es
des Vergiftens würdig machte — zweimal, im Fall von durabletask.
Das kannst du nicht beheben, indem du sorgfältiger vertraust, denn das Vertrauen war nie fehlplatziert. Du behebst es, indem du die Dinge so arrangierst, dass „welches Repo ist das“ und „welcher Scope hat das veröffentlicht“ aufhören, die Fragen zu sein, von denen deine Keychain abhängt. Bromure Agentic Coding ist die Konfiguration, in der der Agent das Repo innerhalb einer VM pro Profil öffnet, die echten Credentials auf dem Host hinter einem Broker bleiben, jeder Write, den der Agent macht, an einem Prompt vorbei muss, und ein Paket nicht installiert werden kann, bis es einen Cooldown überlebt hat. Das Schlimmste, was ein vergiftetes Ordner-Öffnen anrichten kann, ist, eine Box zu exfiltrieren, die nie deine Schlüssel hielt. Es ist kostenlos, Open Source und heute ausgeliefert.