Zehntausend Sterne und ein Commit

Am 14. Juli hat xAI den Quellcode von Grok Build unter Apache 2.0 veröffentlicht, und bis heute Morgen hatte das Repository über zehntausend Sterne. Der Veröffentlichung ging ein Test auf Netzwerkebene voraus, der Version 0.2.93 des Werkzeugs dabei fand, wie sie ein verfolgtes Repository samt vollständiger git-Historie als Bundle in einen von xAI kontrollierten Cloud-Speicher hochlud, darunter ein Repository, das der Assistent ausdrücklich nicht lesen sollte. Wir haben diesen Befund am 14. Juli behandelt, und die Anweisung lautete damals, sämtliche Schlüssel und Zugangsdaten zu rotieren, die das Werkzeug je gesehen hat. Diese Anweisung gilt weiter.

Den Code zu veröffentlichen wirkt wie die stärkste denkbare Antwort auf einen solchen Befund. Es ist der Schritt, den eine Entwicklungsorganisation geht, wenn sie überzeugt ist, dass die Akten sie entlasten, und genau so wird er auch gelesen. Die nützliche Frage ist deshalb nicht, ob xAI richtig daran getan hat zu veröffentlichen. Sie ist enger und praktischer: Wenn Sie jetzt in dieses Repository schauen, um sich Gewissheit darüber zu verschaffen, was das Werkzeug auf Ihren Rechnern getan hat, was ließe sich tatsächlich feststellen?

Sehr wenig, wie sich zeigt, und die Gründe sind struktureller Natur und nicht finsterer. Das Repository trägt einen einzigen Commit, verfasst von einem Bot am 16. Juli um 05:46 UTC, mit der Nachricht, dass er Harness und TUI als Open Source veröffentliche. Ein Commit bedeutet keine Historie. Es gibt kein Vorher, kein Diff, keine Abfolge von Änderungen, nichts zum Vergleichen. Zehntausend Sterne auf einem Repository ohne Historie sind zehntausend Menschen, die eine Geste bestätigen.

Was das Repository nicht sagen kann

Beginnen wir mit der einen Frage, die der Befund tatsächlich aufgeworfen hat: Wohin ging der Code? Die Uploads gingen in einen Bucket in Google Cloud Storage, der im ausgelieferten Binary benannt ist. Im veröffentlichten Quellcode taucht dieser Name nicht auf. Er wird aus einer Umgebungsvariable zur Kompilierzeit gelesen und erst beim Bauen des Binaries aufgelöst. Wer die Veröffentlichung kompiliert, gibt das Ziel vor, und der Quellcode schweigt dazu, worauf der ausgelieferte Build gezeigt hat. Der veröffentlichte Code kann die Frage nicht beantworten, in keine Richtung.

Dann zur Funktion, die den Upload erledigt hat. Sie ist noch da, im Shell-Crate, und sie tut nichts mehr. Sie nimmt ihre Parameter entgegen, markiert sie als unbenutzt, wartet auf den Channel, wirft das Ergebnis weg und gibt einen Fehler zurück, der vermerkt, dass der Upload des Sitzungszustands nicht verfügbar sei. Der Rumpf wurde entfernt, die Umgebung blieb: Die Aufrufstellen sind intakt, das Manifest führt die Abhängigkeiten weiter auf, die Storage-Helfer sind nach wie vor einkompiliert. Lesbar ist das Skelett des Mechanismus, dem der Mechanismus entnommen wurde.

Es ist zugleich das zweite Mal, dass die Korrektur an einer Stelle vorgenommen wurde, die Sie nicht einsehen können. Die ursprünglichen Uploads wurden am 13. Juli über ein serverseitiges Flag gestoppt, nicht über ein Client-Release, und das war der schärfste Teil der ersten Geschichte: Das Binary, das Ihr Team geprüft und gepinnt hat, war nie die Instanz, die entschieden hat, was den Rechner verlässt. Jetzt ist der Code öffentlich, das Ziel ist weiterhin eine Eingabe zur Build-Zeit, und der Schalter sitzt weiterhin auf dem Server. Die Fläche, die prüfbar ist, und die Fläche, die entscheidet, sind einander kein Stück näher gekommen.

Vier Dateien sind umgezogen, eine ist nicht angekommen

Es gibt ein weiteres Detail, und es muss sorgfältig formuliert werden, weil es sich leicht überinterpretieren lässt. Die Strings im ausgelieferten Binary 0.2.93 nennen ein Crate namens xai-data-collector mit fünf Quelldateien: den Storage-Client, die Cloud-Storage-Schicht, die Queue, einen Observer für den Circuit Breaker und einen File-Access-Tracker. Im veröffentlichten Repository existiert kein Crate dieses Namens. Derselbe Satz Dateien liegt in einem Crate namens xai-file-utils, und vier der fünf entsprechen einander. Die fünfte, der File-Access-Tracker, ist im veröffentlichten Quellcode überhaupt nicht enthalten.

Was das belegt und was nicht, ist der ganze Punkt. Eine Absicht belegt es nicht. Ein Crate von einem Namen, der das Sammeln von Daten beschreibt, in einen umzubenennen, der den Umgang mit Dateien beschreibt, ist genau das, was ein Team beim Aufräumen vor einem Release tut, und ein Modul zu entfernen, das an nichts mehr angebunden ist, ist gewöhnliche Instandhaltung. Es gibt hier keinen Beleg für eine Verschleierung, und wir behaupten auch keine. Erwähnenswert ist zudem die Asymmetrie der Belege selbst: Die Binary-Seite stützt sich auf die String-Extraktion eines Dritten, während die Quellcode-Seite jeder überprüfen kann, der das Repository klont.

Was es belegt, ist, dass die Veröffentlichung nicht als Aufzeichnung dienen kann. Die Komponente, deren Name am unmittelbarsten das Verfolgen von Dateizugriffen eines Nutzers beschreibt, fehlt, ihre Geschwister sind unter einem anderen Namen vorhanden, und es gibt keine Commit-Historie, in der sich das eine oder das andere prüfen ließe. Unschuldige Erklärungen und schuldhafte erzeugen ein identisches Repository. Das ist das Problem daran, eine Veröffentlichung als Beweis zu behandeln: Es funktioniert nur, wenn das Artefakt zwischen beiden unterscheiden kann, und dieses kann es nicht.

Die Behauptung, die nie aufgestellt wurde

Man muss dem Forscher zugutehalten, dass die Disziplin auf dieser Seite der Geschichte der Grund dafür ist, dass sie standhält. Die Analyse auf Netzwerkebene wurde mit einem abfangenden Proxy gegen ein gepinntes Binary durchgeführt, auf einem Wegwerf-Repository, das mit Canary-Dateien bestückt war, und sie ist reproduzierbar: Es gibt ein öffentliches Harness, und jeder kann es laufen lassen. Die Messung war unmissverständlich. Ein zwölf Gigabyte großes Repository erzeugte 5,10 Gibibyte Upload-Verkehr gegenüber 192 Kilobyte tatsächlicher Modell-Konversation, ein Verhältnis von nahezu achtundzwanzigtausend zu eins. Die Canary-Datei, die der Assistent nicht lesen sollte, kam unversehrt aus dem mitgeschnittenen Bundle wieder heraus.

Und dann hat der Forscher aufgeschrieben, was der Test nicht bewiesen hat. Dass Hochladen kein Training ist, weil nur die Übertragung gemessen wurde. Dass ein Mitschnitt bei drei Gigabyte nicht gesichert wurde. Dass eine frühere Schlussfolgerung falsch gewesen war, weil eine prozessbezogene Netzwerkmessung Uploads übersehen hatte, die direkt an Google-Adressen gingen, und dass diese Schlussfolgerung zurückgezogen wurde. Ein Befund, der seine eigenen Grenzen und seinen eigenen Widerruf mitveröffentlicht, ist ein Befund, mit dem sich arbeiten lässt.

Dem stehen die Reaktionen gegenüber. xAI hat erklärt, Privatsphäre sei dem Unternehmen zutiefst wichtig, es respektiere die Wahl seiner Kunden, und für Teams mit Zero Data Retention würden weder Trace- noch Code-Daten jemals aufbewahrt. Elon Musk sagte, sämtliche zuvor hochgeladenen Nutzerdaten würden vollständig und restlos gelöscht, und es werde rein gar nichts übrig bleiben. Das mag durchaus zutreffen. Überprüfbar ist nichts davon, und die Löschung lässt sich von außen nicht verifizieren. Das Muster zieht sich durch die gesamte Episode: Die Aussagen, die sich testen lassen, kamen von der Person mit dem Proxy, und die Aussagen, die sich nicht testen lassen, kamen vom Anbieter.

Drei Fragen, bevor Sie es als behoben abhaken

Die verallgemeinerbare Lehre hat nichts mit xAI zu tun, und sie wird noch in diesem Monat wieder gebraucht werden. Offenlegung ist zur Standardantwort auf einen Sicherheitsbefund geworden, und sie ist eine gute Antwort, wenn das Artefakt Belege trägt. Von selbst tut es das nicht. Wenn ein Anbieter also auf einen Befund über Ihre Daten antwortet, indem er Code veröffentlicht, stellen Sie ihm drei Fragen, bevor das Ticket geschlossen wird.

Kann ich die Historie einsehen? Ein zu einem einzigen Commit zusammengefasster Startpunkt ist eine Momentaufnahme, keine Aufzeichnung. Wenn das Repository am Tag der Veröffentlichung beginnt, kann es nicht zeigen, was sich geändert hat, und untersucht wird genau eine Änderung. Entspricht das veröffentlichte Artefakt dem ausgelieferten Binary? Wenn ein Verhalten, auf das es ankommt, zur Build-Zeit gesetzt oder auf einem Server vorgehalten wird, ist der Quellcode die Beschreibung einer Möglichkeit und nicht dessen, was auf Ihren Rechnern lief. Enthält der Code die Komponente, die der Befund benannt hat? Wenn genau das, was gefunden wurde, nicht im Repository liegt, ist sein Fehlen keine Antwort, was auch immer es verursacht hat.

Nichts davon spricht dafür, Code geschlossen zu halten, und nichts davon ist ein Vorwurf. Es spricht für eine Unterscheidung, die Ihr Einkaufsprozess vermutlich noch nicht trifft: Eine Veröffentlichung ist ein Akt der Offenlegung, und ein Audit ist ein Verfahren, das zu einem Schluss kommt. Sie sind kein Ersatz füreinander, sie sind nicht einmal nahe Verwandte, und ein Anbieter, der das Erste getan hat, hat das Zweite nicht getan. Teams, die einen Link auf ein Repository als erledigten Fall verbuchen, begehen einen Kategorienfehler, und das ist die Art von Fehler, die erst im Rückblick sichtbar wird, nach dem nächsten Befund.