Zurück zu allen Beiträgen
Veröffentlicht am · von Renaud Deraison

Die Sandbox öffnete den Port

CVE-2026-65105 ist ein Netzwerkfehler in NVIDIA NemoClaw, einem Werkzeug, dessen einziger Zweck es ist, einen KI-Agenten in einer Sandbox laufen zu lassen. Die Sandbox ist ein Docker-Container, Container erreichen das Loopback-Interface des Hosts nicht, also startete NemoClaw den lokalen Modellserver stattdessen auf allen Interfaces — womit genau die eine Prüfung abgeschaltet war, die eine Webseite davon abgehalten hätte, mit ihm zu sprechen. Was eine besuchte Seite dann mitnahm, war das Chat-Template des Modells, jene Schicht, die jeden System-Prompt rendert, bevor das Modell ihn liest. In Bromure Agentic Coding lauscht die lokale Engine auf dem Loopback, auf einem Port, den der Gast nie erfährt, und der Gast erreicht sie über vsock statt über ein Netzwerk.

Die Eindämmung selbst hat das Loch geöffnet. Eine Sandbox, die das Loopback-Interface Ihres Rechners nicht erreichen kann, drängt den Modellserver stattdessen auf alle Interfaces — und dann erreicht ihn auch ein Browser-Tab.

Sie betreiben Ihren Coding-Agenten auf die sorgfältige Art. Er lebt in einer Sandbox. Das Modell, mit dem er denkt, läuft auf Ihrem eigenen Rechner, also verlässt kein Prompt das Haus. Sie haben die beiden Dinge getan, die Ihnen alle empfehlen.

Dann öffnen Sie einen Browser-Tab, und von diesem Moment an schreibt Ihr Agent Code mit einem Fehler darin, den zu erwähnen er unterlässt.

Das ist CVE-2026-65105, am 25. August offengelegt von Elad Luz und Ofek Itach bei Oasis Security, deren Analyse das Ganze Drive-by-Agent-Hijacking nennt. Sie gingen vor der Veröffentlichung zum PSIRT von NVIDIA, und die Geschichte lief am selben Tag in The Hacker News, SiliconANGLE und CSO Online. NVIDIA hat ein Advisory und einen Patch.

Das Produkt heißt NemoClaw, NVIDIAs Werkzeug, um einen OpenClaw-Agenten in einer OpenShell-Sandbox mit lokalem Ollama-Backend für die Inferenz auszurollen. Eindämmung ist das Verkaufsargument.

Der Container erreichte das Loopback nicht

Ollama lauscht auf Port 11434 und bindet standardmäßig an 127.0.0.1 — das Loopback-Interface, erreichbar nur vom Rechner selbst.

OpenShell-Sandboxen sind Docker-Container. Ein Container hat seinen eigenen Netzwerk-Namespace, also ist 127.0.0.1 im Container der Container und nicht der Host. Der Agent in der Sandbox kann einen an das Loopback des Hosts gebundenen Modellserver folglich nicht erreichen.

NemoClaw löste das mit einer Umgebungsvariablen. Es startet Ollama mit OLLAMA_HOST=0.0.0.0:11434: jedes Interface des Rechners, einschließlich des einen, das zum Büro-WLAN zeigt. Der Installer druckte weiterhin Using Ollama on localhost:11434, während der Socket der Welt antwortete.

Dann kommt der Schritt, der eine Konfigurationsentscheidung in eine Verwundbarkeit verwandelt. Ollamas API hat keine Authentifizierung, also trägt sie stattdessen zwei Wächter. Der erste ist eine CORS-Prüfung des Origin-Headers. Der zweite ist eine Host-Allowlist, die localhost, den eigenen Hostnamen des Rechners und Namen mit den Endungen .localhost, .local oder .internal akzeptiert.

Der zweite Wächter enthält eine Ausnahme. Ollama schaut auf die Adresse, an die es gebunden ist, und wenn diese Adresse nicht Loopback ist, überspringt es die Host-Prüfung vollständig. Man sieht, warum das jemand so geschrieben hat: Wer ein öffentliches Interface bindet, will entfernte Clients, und eine für Loopback gebaute Host-Allowlist würde jeden einzelnen von ihnen abweisen. Das Ergebnis: Die Einstellung, die den Port freilegt, ist dieselbe Einstellung, die die schützende Prüfung entschärft.

Übrig bleibt die CORS-Prüfung, und DNS-Rebinding geht per Konstruktion durch CORS hindurch. Der Angreifer liefert seine Seite von einer Domain aus, die er kontrolliert, auf Port 11434, und lässt diese Domain dann erneut auf 127.0.0.1 auflösen. Origin und Host sind nun derselbe vom Angreifer gewählte Hostname, was Ollama als gleiche Herkunft liest. Den Rebinding-Mechanismus haben wir letzte Woche im Detail behandelt, nehmen Sie ihn also als gegeben: Eine Seite, die Sie besuchen, wird zum Client eines Dienstes auf Ihrem Rechner, und es dauert etwa eine Minute.

Rebinding ist der interessante Weg hinein. Es ist auch der schwerere. Ein Server auf 0.0.0.0 antwortet jedem anderen Gerät im Netzsegment ganz ohne Browsertrick: dem Laptop des Gastes, dem Smart-TV, dem kompromittierten Rechner zwei Schreibtische weiter.

die RandbedingungOpenShell-Sandbox = Docker-Containereigener Netzwerk-Namespace, also127.0.0.1 = der Container, nicht der Hostder Agent erreicht den Modellserver nichtein echtes Problem, das eine echte Antwort brauchtedie Antwort, die NemoClaw auslieferteOLLAMA_HOST=0.0.0.0:11434jedes Interface, keine AuthentifizierungInstaller druckt: „Using Ollama on localhost“Ollamas zwei Wächter1 · CORS-Prüfung des Origin-Headers2 · Host-Allowlist: localhost, Hostname,.localhost .local .internalWächter 2 entfällt, wenn die Bindung nicht Loopback istzwei Wege hineineine Seite: Domain auf 127.0.0.1 umbinden,Origin und Host stimmen überein, CORS geht durchdas LAN: den Port direkt wählen, ohne Trickbeide landen unauthentifiziert an der ganzen APIDie Konfiguration, die den Port freilegte, ist dieselbe Konfiguration, die die schützende Prüfung abschaltete.
Warum der Port umgezogen ist. Die Sandbox ist ein Docker-Container und erreicht das Loopback-Interface des Hosts deshalb nicht; NemoClaw löste das, indem es den Modellserver an alle Interfaces band. Ollama überspringt seine Host-Header-Prüfung, sobald die Bindeadresse nicht Loopback ist, womit nur eine CORS-Prüfung bleibt — und DNS-Rebinding macht Origin und Host zum selben vom Angreifer gewählten Namen.

Sie wollten keine Codeausführung

Die API zu erreichen ist die langweilige Hälfte. Was Oasis tat, sobald sie sie hatten, ist der neue Teil.

Der naheliegende Zug wäre, einen bösartigen System-Prompt ins Modell zu schreiben. Das scheitert hier: OpenClaw schickt bei jeder Anfrage seinen eigenen System-Prompt im messages-Array mit, und der Prompt des Clients gewinnt gegen den im Modell gespeicherten. Also gingen die Forscher eine Schicht tiefer.

Ollamas /api/create-Endpunkt akzeptiert ein Feld template. Ein Chat-Template ist ein Go-Template, das das strukturierte messages-Array — Rollen, Inhalte, Werkzeugdefinitionen — in den einen flachen Textblock verwandelt, den das Modell tatsächlich liest. Es läuft zur Inferenzzeit, nachdem der Client seine Nachrichten übergeben hat, und es fasst sie alle an.

Der Angriff sind drei Anfragen. Das echte Template mit /api/show auslesen. Dessen Werkzeug-Rendering und Spezialtokens exakt so lassen, wie sie sind, und nur ändern, wie System-Nachrichten gerendert werden, indem man eine Anweisung eigener Wahl anhängt. Mit /api/create zurückschreiben.

Der Client schickt weiterhin seinen eigenen sorgfältigen System-Prompt. Das Template hüllt diesen Prompt jedes Mal in den des Angreifers, bevor das Modell ein einziges Token davon sieht. In Elad Luz' Worten, zitiert von CSO Online, sitzt die Anweisung „eine Schicht unterhalb von allem, was ein Guardrail oder ein Betreiber sehen kann“.

Die Änderung landet in der Modelldefinition auf der Platte, sie überlebt also die Konversation, den Reset und den Neustart. Metadaten, Größe und aufgeführte Fähigkeiten des Modells bleiben gleich, und in einer Liste installierter Modelle sieht nichts anders aus. Jeder Konsument dieses Modells bekommt sie: die CLI, an der Sie von Hand herumtippen, und der Agent, der läuft, während Sie beim Essen sind.

Oasis führt auf, wofür eine solche Anweisung taugt. Nichts davon ist dramatisch genug, um aufzufallen.

Den Fehler einbauen

Code produzieren, in dem ein feiner Defekt steckt — die Sorte, die sich im Review gut liest, weil sie geschrieben wurde, um sich im Review gut zu lesen.

Still bleiben

Nie ein Sicherheitsbedenken melden. Ein Agent, der Sie früher vor etwas gewarnt hat und es nicht mehr tut, ist schwer zu bemerken.

Die Wahl lenken

Ein bestimmtes Paket, eine bestimmte URL, eine bestimmte Konfiguration empfehlen. Sie wollten einen Vorschlag; Sie haben einen bekommen.

Alles nach Hause schicken

Wo der Agent Netzwerkzugang hat, Gesprächs- und Dateiinhalte an einen Endpunkt nach Wahl des Angreifers verschicken.

Der Rest der unauthentifizierten API ist Nebenbesetzung: /api/generate und /api/chat, um Inferenz auf fremder GPU laufen zu lassen, /api/pull, um eine Platte zu füllen, /api/delete, um die Modelle zu zerstören, /api/push, um unter dem ollama.com-Konto des Opfers zu veröffentlichen, und /api/me, um Hostnamen, öffentlichen Schlüssel und angemeldeten Benutzernamen dessen zu erfahren, bei dem man gerade gelandet ist.

Die Sandbox war nie der Explosionsradius

Oasis ist sorgfältig darin, was die Sandbox geleistet hat und was nicht. Die OpenShell-Sandbox funktioniert: Sie isoliert Dateisystem, Netzwerk und Prozesse, und sie hält den Endpunkt sauber. Ein Agent in einer Organisation verdient sich seinen Platz, indem er Versionskontrolle, CI/CD, interne APIs, Cloud-Konten, Chat und einen Stapel MCP-Server hält. Nehmen Sie den Agenten, und Sie lenken diesen Zugriff. Die Zusammenfassung der Analyse lautet, dass der wahre Explosionsradius den Ressourcen folgt, die der Agent erreichen darf, nicht der Grenze seiner Sandbox.

Das ist die Frage, die ein Container nie für Sie beantwortet, und hier kommt sie mit einer Wendung. Die Eindämmungsschicht hat die Exposition erst geschaffen. Der Docker-Netzwerk-Namespace hat seine Arbeit getan. Ihn zu umgehen setzte den Modellserver ins WLAN.

Wo das lokale Modell in einem Profil wohnt

Bromure Agentic Coding betreibt ebenfalls lokale Inferenz. Die Agenten eines Profils lassen sich statt auf einen Cloud-Anbieter auf ein Modell auf dem Gerät richten, also genau das Feature, das NemoClaw anbietet. Die Installation darunter ist andersherum gebaut, und jeder ihrer Schritte ist eine direkte Antwort auf etwas weiter oben.

Die Engine bindet Loopback, niemals 0.0.0.0. Der Modellserver auf dem Gerät läuft auf dem Mac, auf 127.0.0.1, auf einem Port, den der Kernel beim Start vergibt, statt auf einer festen Nummer. Der dynamische Port hat einen langweiligen Grund: damit Bromure sich nie mit dem streitet, was auf diesem Mac schon die traditionelle 11434 hält, Ollama und LM Studio eingeschlossen. Er bedeutet auch, dass es keinen wohlbekannten Port gibt, auf den eine Seite zielen könnte.

Der Gast erreicht sie nicht über ein Netzwerk. In der VM wählt der Agent 127.0.0.1:11434, die Adresse, die er erwartet. Diese Verbindung kommt keiner Route nahe. Eine Brücke in der VM spleißt den TCP-Strom auf vsock, den virtio-Socket-Transport, auf Port 8446, und das Host-Ende des Kanals reicht ihn an die Loopback-Engine weiter. Ein vsock-Kanal ist eine Röhre zwischen einem Hypervisor und einem Gast. Er hat keine IP-Adresse, keinen Hostnamen und keinen DNS-Eintrag, es gibt also nichts umzubinden, nichts zu scannen und keinen Weg für einen Browser, ihn zu wählen. Der Gast erfährt nie, auf welchem Port die Engine sitzt.

Nichts in Ihrem LAN erreicht die VM. Unter Resources → Network ist der Standardmodus NAT: Ausgehendes funktioniert, und nichts in Ihrem lokalen Netz erreicht die VM. Das schließt jene Hälfte des NemoClaw-Befunds, die gar kein Rebinding braucht — das Gerät im selben WLAN, das den Port direkt wählt — und es schließt sie, ohne dass Sie eine Einstellung ändern.

Es gibt in der VM keine Modelldefinition zum Umschreiben. Gast-Agenten sind auf eine einzige Modellkennung festgenagelt, bromure-local, und sie adressieren sie unter bromure.llm, einem synthetischen Hostnamen ohne DNS-Eintrag dahinter. Der Proxy in der VM fängt diesen Namen ab und leitet ihn an den Host weiter. Welches Modell antwortet, ist eine Zuordnung, die Sie auf dem Host halten, im Panel Local Models des Profils, und sie zu ändern ist ein Remapping auf der Host-Seite: keine Rekonfiguration in der VM, kein Agenten-Neustart. Template, Gewichte und Routing leben allesamt auf dem Mac. Nichts im Gast hält ein Äquivalent zu /api/create, weil nichts im Gast das Modell hält.

Lokale Inferenz läuft durch dieselbe Pipeline wie Cloud-Inferenz. Weil dieser Verkehr durch Bromures Proxy geht statt direkt an einen Port, bekommt er dieselbe Behandlung wie ein Aufruf an Anthropic oder OpenAI: denselben Trace, dasselbe Logging und dieselbe Prompt-Injection-Erkennung. Das Panel Prompt Injection bewertet Dateiinhalte, Webseiten und Werkzeugausgaben, die der Agent liest, mit einem lokalen PromptGuard-Modell, und bewertet die Dateien CLAUDE.md, AGENTS.md und GROK.md, die er als Autorität lädt, mit einem feinabgestimmten ModernBERT-Klassifikator plus einem deterministischen Scanner für Payloads aus unsichtbarem Unicode. Funde gehen ins Security Log, oder pausieren die Anfrage, oder liefern ein hartes 451 zurück, je nachdem, welche der drei Reaktionen Sie gewählt haben.

Ein Port auf allen Interfaceswo lauscht die Engine?0.0.0.0:11434 · fest, wohlbekanntwie erreicht die Sandbox sie?über IP, wie alle anderen im WLANwer sonst erreicht sie?eine umbindende Seite und das LAN, ohne Authwer darf das Chat-Template umschreiben?alles, was den Port erreicht, perPOST /api/createEin Kanal ohne Adressewo lauscht die Engine?127.0.0.1:<Kernel-Port> · nur Hostwie erreicht die VM sie?vsock 8446 — eine Röhre, kein Netzwerkwer sonst erreicht sie?niemand: keine IP, kein Hostname, kein DNSwer wählt das Modell?Sie, im Panel Local Models des Profils;der Gast kennt nur den Namen bromure-local
Zwei Arten, einem Agenten ein lokales Modell zu geben. Links ein HTTP-Port auf allen Interfaces, ohne Authentifizierung, mit einer beschreibbaren Modelldefinition dahinter — erreichbar für jedes Gerät im Netz und für jede Seite, die einen Hostnamen umbindet. Rechts eine Loopback-Engine auf einem vom Kernel vergebenen Port, vom Gast über einen vsock-Kanal erreicht, der keine Adresse zum Wählen hat, mit der Modellauswahl auf dem Host.

Nehmen Sie jetzt an, das Modell lügt Sie an

Treibt man ein Architekturargument weit genug, sollte jemand es prüfen. Also schenken Sie dem Angreifer den Sieg auf dem Weg, der Ihnen lieber ist: ein vergiftetes Template, ein schlechter Tag bei einem Modellanbieter, eine Prompt-Injection, die durchkam. Ihr Agent arbeitet nun für jemand anderen, und seine Ausgabe liest sich immer noch gut. Führen Sie jene vier Payloads durch ein Profil.

Die Wahl lenken — und die Wahl wird trotzdem geprüft. Dieses Payload stützt sich am stärksten auf die Autorität des Modells und läuft am härtesten gegen die Wand. Bromure bewertet jeden Paketabruf am Host-Proxy, bevor der Agent die Antwort sieht, über npm, PyPI, Cargo, RubyGems, Maven, NuGet, Go Modules und Packagist hinweg, und der Proxy fragt nicht, wer das Paket vorgeschlagen hat. Eine Zwei-Tage-Altersschranke ist standardmäßig an, was das meiste abdeckt, was ein frisch veröffentlichter Typosquat braucht. Schalten Sie die OSV-Abfrage ein, richten Sie die Paketfilterung auf socket.dev oder Delpi, entfernen Sie Installationsskripte — und eine Empfehlung muss vier Meinungen überstehen, bei denen das Modell nichts zu sagen hat. Die .npmrc und pip.conf in der VM können diese Einstellungen verschärfen. Lockern können sie sie nicht.

Alles nach Hause schicken, über eine Leitung, die Ihnen gehört. Exfiltration braucht ausgehenden Verkehr. Guardrails → Outbound connections ist eine Regeltabelle im pf-Stil — eine Aktion, ein Protokoll (tcp, udp, web, any), ein Host oder CIDR, eine Portliste und für web eine Liste von HTTP-Methoden — von oben nach unten geprüft, der erste Treffer gewinnt, mit Unmatched traffic auf Allow oder Deny. Stellen Sie es auf Deny, listen Sie die Hosts, die Ihre Arbeit braucht, und der Endpunkt des Angreifers ist nicht darunter. Durchgesetzt wird am virtuellen Switch und auf der SNI-Ebene des Hosts, also ändert nichts, was der Gast an seinem eigenen Routing tut, das Urteil.

Den Fehler einbauen — und ihn dann ausliefern wollen. Guardrails trägt außerdem für jeden Dienst, den der Agent erreichen kann, einen Modus: Block destructive oder Read-only für GitHub, GitLab, Bitbucket, AWS, Kubernetes, DigitalOcean, Container-Registries und jeden konfigurierten Datenbank-Endpunkt. Im Nur-Lese-Modus gilt ein git push als Schreibzugriff und wird blockiert; ein Fetch ist immer erlaubt. Der hintertürige Commit bleibt in der VM.

Und der Zugang, den er erbt, ist gefälscht. Oasis' Punkt zum Explosionsradius ist der, in den ein Profil die meiste Mühe steckt. Die Zugangsdaten in der VM sind Attrappen: brm_…-Platzhalter als Umgebungsvariablen, eine synthetische ~/.kube/config mit Wegwerf-Clientzertifikaten, ein gefälschter Base64-Blob in ~/.docker/config.json und AWS-Anfragen, die auf dem Host neu signiert werden, so dass alles, was den Proxy umgeht, InvalidSignatureException statt Zugriff bekommt. Private SSH-Schlüssel sind überhaupt nie in der VM — der Host signiert über einen Agenten pro Profil. Schalten Sie Require approval to use für eine Zugangsdatei ein, und jede Ersetzung wird zu einem Host-Dialog mit zeitlich begrenzter Freigabe: fünf Minuten, eine Stunde, der Rest der Sitzung. Ordnerfreigabe ist auf acht von Hand gewählte Verzeichnisse gedeckelt, der Rest Ihres Macs ist also gar nicht da, um gelesen zu werden.

Und Sie sehen das alles. Das Fenster Security Log (Window → Security Log…) ist eine einzige chronologische Tabelle auf dem Host: Paketurteile, jedes Ziel, das die VM geöffnet hat, samt Erlaubt oder Verweigert, Zugangsdaten-Tausch, Injection-Funde. Gast-Code kann sie nicht bearbeiten, weil Gast-Code sie nicht erreicht. Wenn der Tag endet, bringen Erase home… und Reset to base… unter Resources → Storage das Profil in seinen Zustand direkt nach dem Klonen zurück.

Schalten Sie es ein

Wenn Sie NemoClaw betreiben, nehmen Sie NVIDIAs Patch — er holt Ollama zurück auf Loopback und setzt einen tokengesicherten Proxy vor alles, was legitim heraus muss. The Hacker News merkt an, dass der Windows- und WSL-Pfad von diesem Release nicht vollständig abgedeckt ist, prüfen Sie Ihre Plattform also am Advisory, statt es anzunehmen. Suchen Sie dann jeden anderen Modellserver auf Ihrem Rechner und fragen Sie ihn, an welche Adresse er gebunden ist. Die Antwort lautet häufiger 0.0.0.0, als man erwartet, weil Container immer wieder danach fragen.

In einem Profil sind die Einstellungen, die zwei Minuten wert sind, die übliche kurze Liste. Guardrails → Outbound connections mit Unmatched traffic auf Deny. Credentials → Require approval to use für alles, was Geld ausgeben oder Daten löschen kann. Supply Chain → OSV vulnerability check und socket.dev- oder Delpi-Filterung, falls Sie einen Schlüssel haben, zusätzlich zur ohnehin aktiven Altersschranke. Prompt Injection → beide Detektoren, damit der Verkehr zu Ihrem lokalen Modell so sorgfältig gelesen wird wie der zu einem Cloud-Modell.

Lassen Sie das Modell ruhig weiter auf Ihrem eigenen Rechner laufen. Diese Wahl kauft Ihnen Prompts, die lokal bleiben, und sie ist es wert. Sie sagt nichts darüber, wer sonst mit dem Server sprechen darf, der sie hält — und das ist eine Frage über einen Socket, und ein Socket verdient eine bessere Antwort als eine Umgebungsvariable, die gesetzt wurde, um einen Container zufriedenzustellen. Installieren Sie Bromure Agentic Coding, wählen Sie Ihr Modell auf dem Host und lassen Sie dem Gast eine Röhre statt eines Ports.