Sie haben die Adresse geändert, nicht das Paket
Vierzehn Stunden lang wurden am 31. August 2026 manche Anfragen an registry.coder.com von Servern beantwortet, die ein Angreifer in Coders eigenen Cloudflare-Origin-Pool eingetragen hatte. Der Hostname stimmte, das Zertifikat war gültig, die Module trugen die Namen und Versionen, die sie immer trugen, und der zurückgelieferte Code machte sich auf die Suche nach SSH-Keys, OIDC-Tokens und Datenbankpasswörtern. Coder hat die Logs des Angreifers nicht, deshalb bittet das Advisory Sie, Ihren eigenen ausgehenden Verkehr zu prüfen. Das ist eine Frage, die die meisten Maschinen mit einem Coding-Agenten nicht beantworten können.
Der Hostname war Coders eigener. Das Zertifikat war gültig. Das Modul trug den Namen und die Version, die Ihr Template ohnehin gepinnt hatte. Vierzehn Stunden lang gehörten am 31. August einige der antwortenden Server jemand anderem.
Eine Plattform-Ingenieurin aktualisiert an einem Montagmorgen ein
Workspace-Template. terraform init holt die Module, die das Template nennt
(Docker, Zed, aider), von registry.coder.com, genau dort, wo sie schon im
letzten Monat herkamen. Terraform druckt seine übliche grüne Wand und der Build
läuft durch. Kein Werkzeug meldet irgendetwas, weder an diesem Morgen noch in
diesem Monat.
Am 1. September veröffentlichte Coder GHSA-vx42-ghc9-gw65, eingestuft als kritisch mit CVSS 9.0. In seinen Worten: „Ein nicht identifizierter böswilliger Akteur verschaffte sich Zugang zu Coders Cloudflare-Infrastruktur und fügte dem Pool, den Coders Modul-Registry nutzt, nicht autorisierte IP-Adressen hinzu.“ Zwischen 07:35 und 21:45 UTC am Montag, dem 31. August, wurden manche Anfragen nach Coder-Modulen von Maschinen beantwortet, die der Angreifer kontrollierte. Coder baut selbst gehostete Cloud-Entwicklungsumgebungen; BleepingComputer nennt Dropbox, Palantir, Square, Mercedes-Benz, KKR, EnBW, US-Regierungsstellen und Rüstungsunternehmen unter seinen Nutzern.
Niemand hat das Paket angefasst
Jede Lieferketten-Gewohnheit eines sorgfältigen Teams ist eine Prüfung des Artefakts. Ist der Name richtig geschrieben. Ist der Herausgeber der, für den er sich ausgibt. Wurde diese Version gestern veröffentlicht. Passt der Hash im Lockfile noch. Lesen Sie das Diff, bevor Sie hochziehen.
Der Angreifer änderte, welche Maschinen antworteten, als Ihr Client nach der
Adresse fragte, und ließ das Artefakt in Ruhe. Er veröffentlichte kein Paket,
übernahm kein Maintainer-Konto, registrierte keinen Look-alike-Namen und
bearbeitete nichts in Coders Registry. Der Name löste auf, wie er immer auflöst.
Der TLS-Handshake kam gegen ein gültiges Zertifikat für den echten Hostnamen
zustande. Das Modul hieß docker und zed und aider, weil das die Module
sind, die ein Coder-Template anfragt, und es trug die Versionsnummer, die das
Template ohnehin gepinnt hatte.
Was zurückkam, war ein anderes. Die vergifteten Kopien lieferten ein
Shell-Skript namens dlp.sh mit, mit einem eigenen Build für die Module docker,
aider, rstudio-server, windows-rdp und zed und einem eigenen Hash für jedes im
Advisory. Das Advisory beschreibt die Nutzlast als Code, der „darauf ausgelegt
ist, eine Reihe von Zugangsdaten zu identifizieren und diese an einen entfernten
Server mit einem Domainnamen zu exfiltrieren, der einem von Coder regelmäßig
genutzten ähnelt.“ Diese Domain ist coder-infra[.]com, registriert am 28.
August, drei Tage bevor sie jemand benutzte, aufgelöst auf 199.91.220.205, mit
dem Rückruf auf http://www[.]coder-infra[.]com/cli/check.
Die Liste dessen, worauf es abzielte, liest sich wie eine Inventur des Vertrauens einer Entwicklungsplattform: Provisioner-Umgebungsvariablen und -Secrets, OIDC-Tokens der Nutzer, SSH-Keys, externe Authentifizierungsdaten und coderd-Konfigurationsvariablen samt Datenbankpasswörtern und Zugangsdaten des Auth-Providers.
Sie mussten nichts Ungewöhnliches tun, um im Fenster zu sein. Laut Advisory: „Nutzer, die die Haupt-Modul-Registry von Coder (registry.coder.com) als Quelle ihrer Templates verwenden und Komponenten in dem Zeitraum aktualisiert haben, in dem dieser Code verfügbar war, könnten die bösartigen Pakete installiert haben.“ Ein Template anlegen, eine Template-Version hochziehen, einen Dry Run starten oder einen Workspace mit ausgeschaltetem Modul-Cache bauen ist ganz gewöhnliche Montagsarbeit.
„Prüfen Sie Firewall-, Proxy-, DNS- und VPC-Flow-Logs“
Das ist Schritt fünf von Coders Gegenmaßnahmen und die lehrreichste Zeile des Advisories. Die Schritte eins bis vier sind Dinge, bei denen Coder helfen kann: SQL, um im Fenster gecachte Module zu finden, SQL, um sie zu löschen, gepatchte Releases (2.37.0, 2.36.4, 2.35.7 und 2.34.9, alle am 1. September draußen), und eine Liste zu rotierender Zugangsdaten. Schritt fünf greift über all das hinaus, weil die Server, die sagen würden, wen es getroffen hat, dem Angreifer gehören. Coder kann sie nicht sehen und sagt das auch: Es kann nicht abschließend jede kompromittierte Installation benennen.
Also kommt die Frage zu Ihnen zurück, und es ist eine Frage nach Belegen. Hat
irgendetwas auf der Maschine, die dieses Modul ausgeführt hat, sich zu
coder-infra[.]com verbunden? Für eine Produktions-VPC können die meisten Teams
das innerhalb einer Stunde beantworten, weil im Plattform-Team schon jemand die
Flow-Logs besitzt.
Stellen Sie die Frage jetzt für die Maschine, auf der Ihr Coding-Agent arbeitet.
Ein Agent führt terraform init, npm install, make, einen Container-Build,
eine Testsuite, ein im Repository gefundenes Skript und ein von einem Modul
heruntergeladenes Binary aus. Jedes davon öffnet Verbindungen, und niemand
schreibt sie dort mit, wo Sie sie eine Woche später durchsuchen könnten. Das
Transkript des Agenten enthält die Tool-Calls, die das Modell gemacht hat. Es
hat keine Zeile dafür, was ein Shell-Skript innerhalb eines Terraform-Moduls mit
dem Netzwerk getan hat, weil das Modell das nie gesehen hat.
Eine Antwort auf Schritt fünf lässt sich im Nachhinein nicht kaufen. Entweder hat etwas die Anfrage aufgezeichnet, als sie die Maschine verließ, oder es gibt nichts zu durchsuchen.
Was das Skript gefunden hätte
Nehmen Sie die Nutzlast beim Wort und lassen Sie sie laufen. Sie durchkämmt die
Umgebung nach Zugangsdaten, liest die SSH-Keys, greift die OIDC- und
External-Auth-Tokens ab, sammelt die Konfigurationsvariablen mit dem
Datenbankpasswort darin ein und postet alles zu coder-infra[.]com.
Bromure Agentic Coding gibt jedem Workspace seine eigene Ubuntu-VM unter Apples Hypervisor, mit einem host-seitigen Proxy als einzigem Weg des Gasts ins Netz. Lassen Sie dort dieselbe Suche laufen, und sie kommt mit einem vollständigen Satz Zugangsdaten zurück, allesamt Attrappen.
ANTHROPIC_API_KEY enthält einen sk-ant-api03-brm-…-Köder, GH_TOKEN einen
ghp_-String der richtigen Länge, und ~/.git-credentials,
~/.docker/config.json und ~/.kube/config enthalten passende Platzhalter. Die
Formate bleiben erhalten, also akzeptieren gh, docker und kubectl sie
klaglos. Der Proxy hält Ihre echten Werte verschlüsselt auf Ihrem Mac und tauscht
sie erst auf der Leitung ein, nachdem die Anfrage die VM verlassen hat, und nur
dann, wenn sie an den Host geht, für den dieses Credential ausgestellt wurde.
Kein Schalter schaltet das ab; so funktionieren Zugangsdaten in der App.
Die SSH-Keys sind der sauberste Fall: In der VM gibt es keine zu lesen.
SSH_AUTH_SOCK zeigt auf eine Brücke über einen virtuellen Socket zu einem
Agenten auf dem Host, und dieses Protokoll hat eine Anfrage, die „signiere diese
Challenge“ bedeutet, und keine Anfrage, die „gib mir den Key“ bedeutet.
ls ~/.ssh/id_* kommt leer zurück, während git push weiter funktioniert.
AWS verdient einen eigenen Absatz, weil Terraform genau dagegen läuft. Die
~/.aws/config der VM zeigt auf einen Helper, der Ihre echte Access-Key-ID
zusammen mit einem falschen Secret Key ausgibt. Terraform, die AWS-SDKs, boto3
und die aws-CLI lesen diesen Helper ohne jede Einrichtung, signieren ihre
Anfragen dann mit dem falschen Key und erzeugen eine wohlgeformte Signatur, die
AWS ablehnen würde. Der Host entfernt diese Signatur und signiert auf dem Weg
nach draußen mit dem echten Secret neu. Ein Skript, das die Umgebung nach
AWS-Material abgrast, geht mit einer Key-ID und vierzig Zeichen nach Hause, die
nichts authentifizieren.
Dann muss es seine Beute irgendwohin schicken, und genau dort sitzt die
Egress-Firewall des Workspace. Stellen Sie Unmatched traffic auf Deny, und
die VM erreicht die Hosts, die Sie gelistet haben, und sonst nichts. Durchgesetzt
wird zweimal, an zwei Stellen, die der Gast nicht erreicht: Der virtuelle
Netzwerk-Switch prüft jeden Flow nach Ziel-IP und per DNS mitgelesenem Hostnamen
über alle Protokolle hinweg, und der Proxy prüft erneut nach dem TLS-Servernamen.
Eine drei Tage alte Domain hat niemand auf diese Liste gesetzt. Regeländerungen
erreichen laufende Sitzungen ohne Neustart, Sie können also
deny any coder-infra[.]com ergänzen, während der Build noch läuft.
Falls der Verkehr doch hinausgeht, weil der Workspace in der voreingestellten
Alles-erlaubt-Haltung läuft oder weil das Ziel gewöhnlich aussah, erledigen die
Köder ihre zweite Aufgabe. Der Proxy durchsucht jede ausgehende Anfrage, Header
und Body, nach einem gefälschten Credential, das irgendwohin unterwegs ist,
wofür es nie ausgestellt wurde. Ein sk-ant-api03-brm-…-String, adressiert an
coder-infra[.]com, ist nicht mehrdeutig. Der Proxy blockiert ihn mit HTTP 451,
bevor ein Byte das Ziel erreicht, pausiert die VM und löst einen Alarm aus, der
das Credential und beide Hosts benennt. Bromure markiert den Workspace als
kompromittiert, und er startet erst wieder, wenn Sie seine Platte und sein Home
gelöscht haben.
Sie bekommen Schritt fünf beantwortet, während er passiert, statt ihn eine Woche später aus Logs zu rekonstruieren.
Ein Befehl beantwortet das Advisory
Der Host-Proxy schreibt für jede Anfrage aus der VM einen Metadatensatz,
gleich welcher Prozess sie gestellt hat: Zeit, Host, Port, Methode, Pfad,
Status, Latenz und Bytes, gemessen vor jedem Credential-Tausch. Stellen Sie
den Session trace des Workspace auf Activity only, und Sie bekommen
diesen Datensatz, ohne dass irgendein Request-Body gespeichert wird. Dann
druckt bromure-cli trace hostnames my-workspace jeden einzelnen Host, den
der Workspace kontaktiert hat, mit Zählern. Coders Schritt fünf, in einer
Zeile, für die Maschine, auf der der Code lief.
Was die Engines entschieden haben
Die Security Timeline (Window → Security Timeline…) ist die separate Sicht darauf, was Bromures Engines entschieden haben: jedes Urteil der Egress-Firewall, jedes vom Proxy vermittelte Credential, jede Lieferketten-Blockade, farbcodiert und filterbar. Eine abgelehnte Verbindung zu einer vor drei Tagen registrierten Domain taucht dort als rote Firewall-Zeile auf, während der Build noch läuft, und nicht als Grep durch einen Monat Flow-Logs, nachdem Ihnen das Advisory eines anderen gesagt hat, wo Sie hinschauen sollen.
Der Gast erreicht genau eine Sache auf Ihrem Mac: einen geteilten Ordner, ein
lebendiges Lese-Schreib-Fenster in Ihr echtes Dateisystem, das die
Kompromittierungs-Löschung bewusst in Ruhe lässt. Teilen Sie das
Projektverzeichnis statt Ihres Home-Verzeichnisses, und ein Skript auf der Jagd
nach id_rsa und .env läuft durch ein Linux-Home voller Checkouts und
Paket-Caches.
Wenn Sie die Quelle nicht prüfen können, beobachten Sie den Ausgang
Alle Provenienzprüfungen laufen auf einen Zug hinaus: vergleichen, was angekommen ist, mit etwas, dem Sie schon vertrauen. Ein Name, ein Herausgeber, eine Signatur, ein Hash im Lockfile. Der Zug funktioniert, solange der Angreifer etwas in den Kanal legen muss, mit dem Sie vergleichen können. Ein Angreifer, der ein Stück des Kanals hält, legt gar nichts hinein, und Coders Origin-Pool war ein Stück des Kanals. Die BdThemes-Kompromittierung im August hatte dieselbe Form: ein gekaperter Storage-Bucket veränderte einen JSON-Feed, den 350.000 WordPress-Seiten abriefen, ohne Release und ohne geänderte Datei.
Vierzehn Stunden sind ein Arbeitstag. Coder hat es bemerkt, am nächsten Morgen Patches ausgeliefert, Hashes und Indikatoren veröffentlicht und den Lesern gesagt, was zu prüfen ist. Das Advisory endet trotzdem damit, jeden Leser zu bitten, den eigenen ausgehenden Verkehr anzuschauen, weil die Aufzeichnung auf der anderen Seite weg ist.
Rotieren Sie die Keys, die das Advisory nennt, löschen Sie die gecachten Module, nehmen Sie den Patch. Entscheiden Sie dann, was der nächste erreichen darf, denn der nächste kommt durch einen Kanal, an dem Sie keinen Grund zum Zweifeln hatten. Installieren Sie Bromure Agentic Coding, geben Sie dem Build seine eigene Maschine, und halten Sie die Antwort bereit, wenn das Advisory erscheint.