Das Flag sagte Nein
Am 3. August 2026 berichtete The Hacker News über FaceHugger: drei Schwachstellen in Hugging Faces Diffusers-Bibliothek — sieben Millionen Downloads pro Monat —, die es einem präparierten Modell-Repository erlauben, beliebigen Code auf der Maschine auszuführen, die es lädt, selbst mit gesetztem trust_remote_code=False. Die Ursache: Die Vertrauensprüfung lief zu einem anderen Zeitpunkt als das Laden des Codes. Coding-Agents ziehen Modelle so, wie sie Pakete ziehen — das Flag, das log, bewachte also Entwickler-Laptops. Bromure Agentic Coding legt die Grenze unter den Prozess statt in ihn hinein: Das Laden läuft in einer Wegwerf-VM, die erreichbaren Credentials sind Köder, und der Heimruf des Payloads stirbt am Host-Proxy — das bösartige Repo kostet den Angreifer seinen Payload und Sie nichts.
Das Repository enthielt eine Datei namens None.py, und das war der
ganze Trick. Das Sicherheits-Flag war gesetzt, die Prüfung lief, und der
Code lief trotzdem — weil Prüfung und Laden zu zwei verschiedenen
Zeitpunkten geschahen, und der Angreifer nur beim zweiten anwesend sein
musste.
Am 3. August 2026 griff The Hacker News
Forschung auf, die Zafran Labs Ende Juli veröffentlicht hatte:
drei Schwachstellen in Hugging Faces Diffusers-Bibliothek, gemeinsam
FaceHugger getauft, die es einem präparierten Modell-Repository
erlauben, beliebigen Python-Code auf jeder Maschine auszuführen, die es
lädt. Diffusers ist der Standardweg, Diffusionsmodelle auszuführen — rund
sieben Millionen Downloads pro Monat, verbaut in Produktions-Pipelines,
CI-Jobs, Notebooks und Container-Images. Die Bibliothek hat eine
Schutzvorkehrung für genau dieses Szenario: trust_remote_code, ein Flag,
das ungeprüften Code aus einem Modell-Repo davon abhalten soll, auf Ihrer
Maschine zu laufen. Alle drei Schwachstellen gehen daran vorbei, während
es auf False steht.
Prüfung und Laden waren zwei verschiedene Ereignisse
Ein Modell vom Hub zu laden ist keine einzelne Operation. Die Bibliothek
macht zwei aufeinanderfolgende HTTP-Requests: Der erste holt die
Konfiguration des Repositorys, der zweite holt den Code und die Gewichte,
auf die diese Konfiguration zeigt. Das trust_remote_code-Gate
inspizierte während des ersten Requests. Das, wovor es schützen sollte,
kam im zweiten.
Zafrans Forscher fanden drei Wege durch diese Lücke, inzwischen mit CVEs
versehen
und in Diffusers 0.38.0 gepatcht. Bei CVE-2026-44827 (CVSS 8.8) baut eine
Eigenheit der String-Formatierung den Dateinamen None.py, wenn keine
Custom-Pipeline angefordert wird — und die Existenzprüfung für diese Datei
läuft auf einem Codepfad, der sie nicht meldet, sodass ein Repository, das
eine Datei namens None.py mitbringt, das Gate passiert und beim Laden
ausgeführt wird. CVE-2026-45804 ist ein Wettlauf: Etwa eine Drittelsekunde
liegt zwischen den beiden Requests, und ein Repository, das sich
dazwischen ändert, wird als das eine validiert und als das andere
ausgeführt. CVE-2026-44513 überspringt das Gate bei lokalen
Snapshot-Ladevorgängen. Zafrans Forscher komprimierten alle drei in einen
Satz: Jede Methode, die den Loader Custom-Code sehen lässt, den das Gate
nicht sah, erlaubt den Bypass.
Das Muster hat Geschichte. Transformers — die andere Säule des
Hugging-Face-Ökosystems — hatte seinen eigenen
trust_remote_code=False-Bypass (CVE-2026-4372), ausnutzbar über einen
ganz normalen Modell-Ladeaufruf. Die Bug-Klasse kommt mit dem Design: ein
Sicherheitsversprechen, das im Inneren des Prozesses lebt, den es
überwacht. Das Flag ist ein Funktionsargument, während die Durchsetzung
über Codepfade, Dateinamen-Formatierung und Request-Timing verstreut ist.
Sobald irgendetwas davon dem Flag widerspricht, verliert das Flag — und
nichts sagt Ihnen, dass es verloren hat. Das Modell lädt und die Demo
funktioniert.
Ihr Agent lädt Modelle an einem Dienstag
Lesen Sie die Geschichte vom Stuhl eines Coding-Agents aus. „Zieh die
Inpainting-Pipeline vom Hub und benchmarke sie gegen unsere“ ist eine ganz
gewöhnliche Dienstagsaufgabe. Das Projekt pinnt diffusers==0.37, denn
Projekte pinnen Dinge. Der Agent schreibt, was ein sorgfältiger Ingenieur
schreiben würde — from_pretrained(..., trust_remote_code=False) — und
die sorgfältige Version ist die verwundbare Version. Den Quellcode eines
Pakets kann man vor der Installation lesen; ein Modell-Repo ist Config,
Gewichte und, dank des Loaders, was auch immer der zweite HTTP-Request
behauptet.
Agents haben diesen Ladepfad heiß gemacht. Sie holen Modelle so, wie sie Pakete holen — mitten in der Aufgabe und per Name —, und Angreifer haben längst herausgefunden, dass schon die Empfehlung vergiftet sein kann. Ein Modell-Repo, das beim Laden detoniert, ist derselbe Zug eine Registry weiter, mit besserer Tarnung: Der Payload sitzt in einem Artefakt, das Sie unter Daten ablegen, nicht unter Code.
Zafrans Rat lautet, Modell-Repositorys als nicht vertrauenswürdigen Code zu behandeln. Richtig — mit einer Voraussetzung, bei der der Bericht nicht verweilt: einem Ort, an dem nicht vertrauenswürdiger Code laufen kann, ohne Sie etwas zu kosten. Eine Politik des Misstrauens ist eine Disziplin, die man durchhält, bis eine Deadline laut wird. Ein für Detonationen gebauter Raum braucht Ihre Disziplin nicht.
Das Laden passiert in der Box
Bromure Agentic Coding ist dieser Raum, und er beginnt dort, wo FaceHuggers Flag versagte: Die Grenze sitzt unterhalb des Prozesses, in einer Umgebung, mit der die Innereien des Loaders nicht diskutieren können, durchgesetzt, ob der Prozess mitspielt oder nicht.
Spielen Sie den Angriff durch ein Profil durch. Ihr Agent nimmt die
Benchmark-Aufgabe, Pins inklusive, und ruft den Loader auf dem bösartigen
Repo auf. None.py wird ausgeführt — in einer Wegwerf-Linux-VM, einen
Hypervisor von macOS entfernt. Die Maschine, die der Payload jetzt
besitzt, ist eine Maschine, die für diese Aufgabe existiert, den Workspace
dieser Aufgabe hält und verworfen wird, sobald die Arbeit gemergt ist.
Der erste echte Zug des Payloads geht nach draußen. Er muss: eine zweite
Stufe holen oder das Gefundene an seinen Operator verschicken. Jeder
dieser Requests kreuzt den Host-Proxy, wo das Ziel gegen die Liste geprüft
wird, die Sie für dieses Profil freigegeben haben. huggingface.co steht
auf der Liste — so kam das Modell herein. Die Ablage des Angreifers steht
nicht darauf. Der Draht verweigert, so wie das Gate es hätte tun
sollen — nur hängt diese
Verweigerung nicht davon ab, dass die Codepfade der Bibliothek
untereinander einig sind. Der Proxy weiß nicht und kümmert sich nicht
darum, welche Python-Datei den Request stellt. Er prüft das Ziel, findet
nichts Freigegebenes und kappt die Verbindung.
Angenommen, der Payload lässt das Netz aus und geht stattdessen auf Beutezug, durch Umgebungsvariablen und Schlüsseldateien. Er findet Broker-Köder. Die echten Werte leben auf dem Host und werden am Draht injiziert, nur für freigegebene Ziele — die Passwörter waren nie in der VM, um gestohlen zu werden. Und wenn er versucht, seinen Aufenthalt dauerhaft zu machen — eine Config umschreiben, etwas abschalten —, halten destruktive Muster für einen Guardrail-Dialog auf dem Host an, und Persistenz in einer Maschine mit der Lebensdauer einer Aufgabe ist ohnehin ein Verlustgeschäft.
Währenddessen gelingt die Aufgabe. Der Benchmark läuft, die Zahlen kommen zurück, Sie lesen den Diff. Der Angreifer hat eine Supply-Chain-Position für einen Payload ausgegeben, der in einem Raum ausgeführt wurde, in dem es nichts zu stehlen gab und keinen Weg nach Hause. Sie haben nichts ausgegeben — nicht einmal Aufmerksamkeit, es sei denn, Sie lesen zum Vergnügen Proxy-Logs.
Die Bibliothek patchen, den Raum behalten
Die Fix-Notiz in Zafrans Bericht sagt Organisationen, sie sollten upgraden und dann auf die Jagd gehen: Anwendungen, Notebooks, Inferenz-Services und Container-Images, die ältere Diffusers-Releases pinnen. Diese Jagd hat keine Ziellinie — irgendwo in Ihrem Abhängigkeitsbaum pinnt irgendein Projekt die Version mit der Lücke, und der nächste FaceHugger wird das Flag einer anderen Bibliothek mit einem anderen Bypass sein. Der Wächter und die Shell waren sich uneinig war dieses Versagen in einer Befehls-Allowlist; die Sandbox war ein Satz war dieses Versagen in einem Prompt. In jedem Fall lebte eine Prüfung im Inneren dessen, was sie prüfte, und das Ding gewann.
Die Grenze eines Profils teilt dieses Schicksal nicht, weil sie an dem
Prozess, den sie einschließt, nicht teilnimmt. Die VM parst keine
Pipeline-Configs. Der Proxy hat keinen None.py-Codepfad. Ihr einziger
Job — diese Maschine ist wegwerfbar, dieser Draht verweigert ungelistete
Ziele — ist am Tag, an dem ein Bypass veröffentlicht wird, derselbe wie am
Tag, an dem er gepatcht wird. Ein CISO von Sumo Logic, der diese Forschung
kommentierte, ohne an Bromure zu denken, benannte die Verteidigungen, die
halten: „die unglamourösen: Egress-Kontrolle, Segmentierung und
Credential-Hygiene.“
Wir haben die unglamourösen in ein Profil gebaut, das Sie anklicken.
Ziehen Sie weiter Modelle — dort liegt der Hebel, und Ihr Agent sollte sie für Sie ausprobieren. Hören Sie auf, ein Funktionsargument das Einzige sein zu lassen, das zwischen dem Hub und Ihrem Laptop steht. Installieren Sie Bromure Agentic Coding, geben Sie dem Agent ein Profil, dessen Regeln am Draht halten, und wenn das nächste Mal das Versprechen eines Loaders bricht — und eines wird brechen —, bleibt die Schlagzeile die von jemand anderem.