Eingeloggt sein genügte
Ein Entwickler, der Plattenplatz aufräumte, fand 700 MB in einem versteckten Verzeichnis und zog an dem Faden: ZCode von Z.ai hatte seinen gesamten Arbeitsbaum in ein Tar gepackt, 42.411 Dateien, davon 86,6 % .git, es mit einem Schlüssel verschlüsselt, den nur Z.ai besitzt, und es direkt in einen Alibaba-Cloud-Bucket geschickt. Kein Angreifer, keine CVE, keine Malware. Der Auslöser war, eingeloggt zu sein. Der Client verschlüsselte das Archiv, also konnte kein Scanner es lesen, und die einzigen Fakten, die übrig blieben, waren das Ziel und die Größe. Das sind zwei der Felder, die Bromure Agentic Coding für jede Anfrage eines Workspace notiert, auf einem Draht, den das Werkzeug in der VM nicht auswählen darf.
Ihr Coding-Werkzeug muss nicht kompromittiert sein, um Ihren Quellcode irgendwohin zu schicken. Es braucht nur eine Voreinstellung. Dem Anbieter zu vertrauen ist nicht die Frage. Fragen Sie, ob Sie es merken würden.
Sie räumen Platz auf einer vollen Platte. Ein verstecktes Verzeichnis in Ihrem
Home-Ordner belegt mehr als 700 Megabyte, und Sie erinnern sich nicht, etwas in
dieser Größe installiert zu haben. Darin, unter einem Ordner namens
checkpoints, liegt eine einzige 313-MB-Datei mit der Endung .enc und daneben
ein Metadatensatz, in dem failureCount: 564 steht.
Fünfhundertvierundsechzig Versuche für etwas, um das Sie nie gebeten haben.
Siebenhundert Megabyte und ein Faden zum Ziehen
Dort begann der chinesische Entwickler, der als ferstar bekannt ist, am 18. September, und die Reverse-Engineering-Aufschreibung dessen, was er fand, lohnt sich in Gänze. Das Verzeichnis gehörte zu ZCode, dem Desktop-KI-Coding-Client von Z.ai, der Firma hinter den GLM-Modellen. CSO Online und InfoWorld übernehmen beide seine Zusammenfassung des Verhaltens wortwörtlich:
„Immer wenn Sie eingeloggt sind, packt ZCode Ihren gesamten Workspace still zusammen — komplette .git-Historie, LFS-Asset-Cache, Reflogs und globale App-Konfigurationen —, verschlüsselt ihn und lädt ihn direkt zu Aliyun OSS hoch.“
Der Auslöser sitzt im ersten Teilsatz. Keine Frage, die Sie gestellt haben, nicht die Indexierungsfunktion, die Sie eingeschaltet haben: ein gültiges Sitzungstoken, auf das der Capture-Prozess wartet, und sonst nichts. Eine einzige Sitzung verzeichnete in seinen Logs 62 Capture-Events. Als er das Archiv löschte, baute der Client innerhalb einer halben Stunde ein neues und erhöhte den Fehlerzähler.
Was in der Kiste war
Der Snapshot, den er auseinandernahm, enthielt 42.411 Dateien, 345 MB vor der Verschlüsselung und 313 MB danach. Woraus diese 345 MB bestanden:
.git/lfs/: 196,1 MB, 56,8 %.git/objects/: 102,2 MB, 29,6 %.git/logs/: 0,6 MB, 0,2 %- alles andere, also echter Quellcode und echte Dokumentation: 46,2 MB, 13,4 %
86,6 % des Uploads waren .git. Das Archiv trug jedes Objekt der Historie des
Repositorys, jede große Binärdatei, die der LFS-Cache heruntergeladen hatte, und
das Reflog, das jeden Branch auflistet, auf dem Sie waren, und jeden Commit, den
Sie gemacht und dann zurückgenommen haben. Wer Ihren Arbeitsbaum liest, erfährt,
was Sie ausliefern; wer Ihr .git liest, erfährt, was Sie versucht haben, was
Sie zurückgerollt haben und wer es committet hat.
Beide Schalter regelten ihre Seite
ZCode kam mit zwei Einstellungen, die ein sorgfältiger Entwickler gefunden und abgeschaltet hätte: eine für Erfahrungsoptimierung, eine für die Indexierung von Repository-Snapshots. Beide taten etwas Echtes, und keine tat, was ihr Name nahelegt.
Die erste regelte, ob Z.ai befugt war, die Daten zu nutzen. Die zweite regelte, ob der Server den Snapshot indexierte, sobald er angekommen war. Das Packen und der Upload liefen unabhängig davon, weil der Capture-Sidecar startet, sobald der Token-Provider ihm ein gültiges JWT überreicht, ohne irgendeine Nutzereinstellung irgendwo auf dem Weg. Schalten Sie beide Schalter ab, und der Client packte Ihr Repository weiterhin, verschlüsselte es weiterhin, schickte es weiterhin in den Bucket und versprach Diskretion über das, was danach geschah.
Der Bug eines Anbieters, aber die Form wiederholt sich überall. Eine Kontrolle, die in dem Programm wohnt, das sie einschränkt, ist eine Bitte. Sie läuft auf demselben Code, der falsch sein müsste, damit Sie sie brauchen.
Nichts auf dem Draht konnte es lesen
Der Client verschlüsselte jedes Archiv mit AES-256-CTR, bevor es die Maschine
verließ, und hüllte den symmetrischen Schlüssel mit einem öffentlichen
RSA-OAEP-SHA256-Schlüssel ein, den ihm zcode.z.ai überreichte. Der passende
private Schlüssel kommt nie herunter. ferstar konnte sein eigenes Archiv nicht
öffnen; die eine Partei, die es konnte, war die mit dem Bucket.
Das schließt jede Verteidigung aus, die Sie besitzen und die dadurch funktioniert, dass sie Bytes liest. Ein Secret-Scanner findet in diesem Tarball keinen AWS-Key, und Deep Packet Inspection sieht eine TLS-Sitzung zu einem Storage-Endpunkt, die Chiffrat in Chiffrat verpackt trägt.
Zwei Fakten überleben: wohin es ging und wie groß es war. Ein 313-MB-POST an einen Objektspeicher-Host in einer Region, in die Ihr Team nicht deployt, fällt auf — vorausgesetzt, jemand notiert, wohin Ihre Werkzeuge sich verbinden und wie viel sie senden. Niemand tat es, und deshalb brauchte es zum Finden Plattenplatz-Archäologie und eine Woche Reverse Engineering statt eines Blicks in ein Log.
Wo der Ausgang liegt
Bromure Agentic Coding setzt den Agenten und seine Toolchain in eine Ubuntu-VM auf Ihrem Mac und gibt dieser VM genau einen Weg ins Internet: einen Man-in-the-Middle-Proxy, der auf dem Host läuft, außerhalb des Guests, wo kein Prozess in der VM ihn umkonfigurieren kann.
Das verlangt von der Software nichts. Der virtuelle Netzwerk-Switch leitet die
Port-80- und Port-443-Flüsse der VM transparent in den Host-Proxy um, ohne
nötige Umgebungsvariablen und ohne etwas, das der Guest abschalten könnte,
standardmäßig aktiv für jeden Workspace. Ein Werkzeug, das HTTPS_PROXY
ignoriert, seinen eigenen Socket öffnet und direkt mit einem Storage-Endpunkt
spricht, geht trotzdem hindurch, weil das Abfangen im Switch wohnt, an dem der
Guest hängt, und nicht im Guest.
Vier Dinge passieren dann mit einem 313-MB-POST, um den niemand gebeten hat.
Jede Anfrage hinterlässt einen Eintrag
Jede Anfrage durch den Proxy hinterlässt einen Trace-Eintrag: Zeitstempel, Host, Port, Methode, Pfad, Status, Latenz und Request-Bytes, gemessen vor jedem Credential-Tausch. Sie müssen kein Archiv entschlüsseln, um einen repository-großen Upload an einen Host zu bemerken, auf den Sie nie deployt haben: Größe und Ziel sind Spalten. Sortieren Sie nach der einen, filtern Sie nach der anderen.
Es verlässt den Mac nie
Die Egress-Firewall pro Workspace ist eine geordnete Regeltabelle (Aktion,
Protokoll, Host oder CIDR, Ports, HTTP-Methoden), die mit default allow
oder default deny endet. Betreiben Sie einen Workspace im Allowlist-Stil,
und der Upload hat keinen Ort, wohin er könnte. Zwei Stellen setzen die
Regeln durch: der Switch prüft Ziel-IP und per DNS mitgelesenen Hostnamen,
der Proxy prüft den TLS-Servernamen noch einmal, und Ihre Änderungen
erreichen laufende Sitzungen sofort.
Jedes Urteil ist eine Zeile
Jede Firewall-Entscheidung landet in der Security Timeline, also zeigt sich ein Werkzeug, das es immer wieder versucht, sagen wir 564 Mal, als wiederholte Ablehnung gegen einen benannten Host und nicht als langsam volllaufende Platte. Das Muster, dessen Rekonstruktion eine Woche dauerte, ist genau das, was dieses Fenster anzeigen soll.
Die mitgepackten Configs sind Attrappen
„Globale App-Konfigurationen“ ist die Wendung, die Sie in ferstars Satz am
meisten beunruhigen sollte. Innerhalb eines Bromure-Workspace existieren
~/.git-credentials, ~/.docker/config.json, ~/.kube/config und
~/.aws/config und funktionieren, und jeder Wert darin ist eine
strukturerhaltende Fälschung. Keine Datei, keine Umgebungsvariable und kein
Prozess in der VM hält jemals einen echten API-Key, ein echtes OAuth-Token,
ein echtes AWS-Secret oder einen echten SSH-Private-Key.
Den Rest macht der Zuschnitt. Ein Workspace ist ein Projekt oder eine
Credential-Grenze; zwei Workspaces teilen nie eine VM, und das Home des Guests
ist eine eigene Image-Datei. Was ein Werkzeug innerhalb eines Workspace
zusammenpackt, ist dieser Workspace, und das lässt die anderen vierzig
Repositorys auf Ihrem Mac, das ~/.aws/config Ihres Hosts und Ihre SSH-Keys
außen vor. Die Keys erreichen überhaupt keinen Guest: das Signieren passiert auf
dem Host über eine vsock-Brücke, und die privaten Bytes bleiben dort.
Was Z.ai danach tat
Z.ai entschuldigte sich an dem Tag, an dem ferstar veröffentlichte. Das Unternehmen schaltete den Upload-Workflow in ZCode v3.14.0 ab, das laut InfoWorld am 19. September ausgeliefert wurde und einen Fix für ein anomales Repository-Upload-Problem auflistete, und holte die Sicherheitsfirma NSFOCUS für ein Audit des Ergebnisses. NSFOCUS bestätigte, dass „alle Datenobjekte im Alibaba-Cloud-OSS-Bucket zcode-prod sowie der Bucket selbst gelöscht wurden“, und Z.ai sagt, nach dem Audit sei „kein funktionaler Pfad identifiziert worden, der die Erzeugung lokaler Repository-Snapshots oder die Übertragung lokaler Dateien nach außen auslösen könnte“, und der Code sei „nie für Modelltraining verwendet worden“. Dann legten sie die Sache offen: Client, Backend, gemeinsame UI, Agent CLI und Runtime, Apache-2.0, auf GitHub. Das übertrifft den Branchenstandard, und es bedeutet, dass der nächste Mensch, der nachsehen will, keinen Disassembler braucht.
Cris Thomas von Semgrep, in der CSO-Berichterstattung zitiert, benannte die Kategorie: „Das ist nicht wirklich ein KI-Modell-Problem, es ist ein altmodisches Problem der Sicherheitsarchitektur.“ Er will, dass Anbieter offenlegen, was die Maschine verlässt, wohin es geht und wie lange es aufbewahrt wird, „mit den minimalen Berechtigungen standardmäßig aktiv, nicht den maximalen“. Kein Kunde kann das von außen erzwingen.
Die Voreinstellung ist das Bedrohungsmodell
Hier hat niemand jemanden angegriffen. Niemand hat ein Credential gestohlen, ein Paket vergiftet oder einem Modell etwas eingeredet. Ein Produkt tat, was seine Autoren es zu tun gebaut hatten, und was sie es zu tun gebaut hatten, war, Ihr Repository irgendwohin zu schicken, wo Sie es nicht lesen konnten. Der Vorfall ist eine Voreinstellung, und die Voreinstellungen wählen Leute, deren Interessen neben Ihren herlaufen.
Das ist das Argument dafür, die Grenze außerhalb des Werkzeugs zu ziehen. Sie müssen nicht glauben, dass Ihr Coding-Assistent feindlich ist; Sie müssen nur bemerken, dass Sie nicht auditieren können, was Sie nicht sehen, und dass der Einstellungsbereich des Anbieters ein seltsamer Ort für den Schalter ist. Lassen Sie den Agenten und seine Toolchain dort laufen, wo jede Verbindung, die sie öffnen, einen Draht kreuzt, der Ihnen gehört, wo der Eintrag über diese Kreuzung auf Ihrem Mac geschrieben wird, und wo die Regel, die einen 313-MB-Upload stoppt, eine Zeile ist, die Sie getippt haben, statt ein Kästchen, das jemand anders respektiert hat.
Dann ist „was schickt mein Coding-Werkzeug eigentlich?“ ein Fenster, das Sie an einem Dienstagnachmittag öffnen, und kein Forschungsprojekt.