Der Commit war ein Branch
Air hat Plugin4Shell am 17. September offengelegt: Die Plugin-Marketplaces von Claude Code, Codex, Gemini CLI und Copilot heften jedes Plugin an einen vierzig Zeichen langen Commit-Hash, und die Agenten checken diesen Hash aus, ohne je zu prüfen, ob sie ihn auch bekommen haben. Ein Angreifer, der einen Branch nach dem gepinnten Hash benennt, gewinnt den Checkout, und der Hintergrund-Updater erledigt den Rest, ohne Rückfrage und ohne Klick. Anthropic und OpenAI haben gepatcht. Google wird es nicht tun, Microsoft hat es nicht getan. In einem Bromure Agentic Coding Workspace landet der Code, der den Checkout gewinnt, in einer VM mit Platzhalter-Zugangsdaten, hinter einer Push-Policy und einem Egress-Regelwerk, die auf dem Host durchgesetzt werden.
Jeder Leitfaden zur Lieferkette sagt Ihnen, Abhängigkeiten an einen Hash zu heften, denn eine Versionsnummer ist ein Etikett, das jemand verschieben kann, und ein Hash ist der Inhalt selbst. Vier Coding-Agenten haben diesen Rat befolgt. Keiner von ihnen hat geprüft, ob der Hash das war, was er bekommen hat.
Ein Plugin besteht die Prüfung. Sie lesen es, oder Ihr Plattform-Team liest es, und es kommt auf die Freigabeliste, geheftet an einen Commit: vierzig hexadezimale Zeichen, die nur einen einzigen Baum beschreiben können, weil eine Änderung am Baum die Zeichen ändert. Genau darin liegt der Reiz. Wer die passenden Rechte hat, kann ein Tag verschieben oder eine Version neu veröffentlichen, aber ein Commit-Hash soll eine Tatsache sein.
Am 17. September haben drei Forscher von Air (Or Nevo, Dor Granat und Niv Hoffman) Plugin4Shell veröffentlicht. Ihr Befund: Der Pin ist nur so gut wie das, was ihn auflöst, und der Resolver in vier großen Coding-Agenten prüft seine eigene Arbeit nicht. The Register berichtete noch am selben Tag. Claude Code, OpenAIs Codex, Googles Gemini CLI und Microsofts Copilot sind alle betroffen.
Git bevorzugt die Ref
Ein Commit-Hash ist Inhalt, und er ist zugleich ein Name. Branches und Tags sind es auch, und git löst sie alle über dieselbe Suche auf. Geben Sie git eine Zeichenkette, die zugleich Branch-Name und Objekt-ID ist, muss es sich entscheiden; es entscheidet sich für den Branch. Die Forscher bringen es in einem Satz auf den Punkt: „Wenn ein Name zugleich eine gültige Ref und eine Objekt-ID ist, bevorzugt git die Ref.“
Git warnt durchaus. Es gibt für diese Referenz einen Mehrdeutigkeitshinweis aus, in ein Terminal, das Sie nicht lesen, weil ein Hintergrund-Updater den Checkout ausführt.
Git-Branch-Namen erlauben vierzig hexadezimale Zeichen. Ein Angreifer, der das Repository des Plugins kontrolliert, legt einen Branch mit genau dem Namen an, den der Marketplace gepinnt hat, und macht ihn zum Standard-Branch. Der Clone holt diesen Branch neben dem gleichnamigen Commit herunter. Dann führt der Agent seinen Checkout aus:
git clone <plugin repo> ./
git checkout aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Der Checkout landet auf dem Branch. Gemini CLI nimmt einen anderen Weg zum
selben Ziel: Es holt den richtigen Commit mit --ref und führt dann
git checkout FETCH_HEAD aus, was zu einem Branch namens FETCH_HEAD auflöst,
falls das Repository einen hat.
Fünf Schritte, und der letzte hat keinen Klick
Die Forscher legen den Angriff in fünf Zügen aus, und die ersten drei sind Dinge, die ein gut geführter Marketplace mit Absicht tut.
Pflanzen. Ein harmloses Plugin veröffentlichen. Es besteht die Prüfung beim
Commit aaa…aaa, weil nichts daran falsch ist.
Verbreitung. Entwickler installieren es, geheftet an den geprüften Commit. Das ist der Schritt, in dem Sie tun, was die Leitfäden Ihnen sagen.
Versionssprung. Der Marketplace heftet neu an einen jüngeren Commit,
bbb…bbb, ebenfalls harmlos und ebenfalls geprüft.
Rug-Pull. Der Angreifer legt einen Branch namens bbb…bbb an, macht ihn zum
Standard und zeigt damit auf bösartigen Code. Er veröffentlicht nichts neu, und
der Eintrag im Marketplace bewegt sich nicht. Die vierzig Zeichen, die Sie
prüfen würden, sind die vierzig Zeichen, die Sie schon geprüft haben.
Vom Auto-Update zur Codeausführung. Claude Code und Codex aktualisieren installierte Plugins standardmäßig im Hintergrund. Das nächste geplante Update checkt den Branch aus. Air beschreibt diesen Schritt als „keine Rückfrage, kein Klick“.
Es gibt einen zweiten Weg hinein, der das Pflanzen überspringt: das Repository eines legitimen Plugin-Autors übernehmen und die bösartige Version an jeden Agenten ausliefern, der das Plugin bereits installiert hat. Der Branch-Trick ist derselbe, und es gibt keine Prüfung zu bestehen.
Air beschreibt das Ergebnis als „vollständige entfernte Codeausführung auf dem Rechner des Mitarbeiters“, laufend mit den Rechten dieses Mitarbeiters. Der Angreifer braucht keine Rechteausweitung. Der Code läuft als die Person, der der Laptop gehört, und erreicht ihre Dateien und ihren Produktionszugang.
Es ist das dritte Mal, dass diese Forscher dieselbe Form zählen. Ihre früheren Arbeiten zu bösartigen Agent-Skills beschreiben eine, die mehr als 26.000 Agenten erreichte, und eine Übernahmekampagne, die 925 bereits genutzte Skills auf 134.000 Agenten kaperte. Jene Kampagnen brauchten Sie, um etwas Schlechtes zu installieren; diese brauchte Sie, um etwas Gutes zu installieren und zu warten.
Zwei der vier haben keinen Patch
Air hat im Juni an alle vier Hersteller gemeldet.
Anthropic hat Claude Code am 17. Juni gepatcht, in Version 2.1.179. OpenAIs Korrektur kam in Codex 0.146.0 und wurde am 12. August verifiziert. Google antwortete am 4. August, Gemini CLI sei abgekündigt und werde nicht gepatcht. Google verweist Nutzer stattdessen auf Antigravity, sodass eine Gemini-CLI- Installation, die auf der Platte bleibt, verwundbar bleibt. Microsoft hat für Copilot nichts ausgeliefert. GitHub sagt, die eigene Plattform blockiere Branch- und Tag-Namen, die wie Commit-SHAs aussehen, was Plugins auf GitHub abdeckt und für ein anderswo gehostetes Plugin-Repository nichts tut, Bitbucket eingeschlossen. The Register merkt mit Microsofts eigener Zahl an, dass fast 90 % der Fortune 500 Copilot einsetzen.
Die Korrektur selbst ist eine Zeile, und sie muss im Agenten laufen:
test "$(git rev-parse HEAD)" = "<pinned-sha>" || abort
Den Commit auflösen, der im Arbeitsbaum gelandet ist, und die Weiterarbeit verweigern, wenn er nicht passt. Kein Marketplace kann das für Sie tun, denn Ihr Agent löst den Pin auf Ihrem Rechner auf, nachdem der Marketplace zu Ende gesprochen hat.
Für eine große Zahl von Entwicklern, die das heute lesen, ist „aktualisieren Sie Ihren Agenten“ keine verfügbare Antwort. Bleibt die andere Frage: Was findet der Code vor, wenn er den Checkout gewinnt und zu laufen beginnt?
In einem Bromure Agentic Coding Workspace
Airs Formulierung, laufend mit den Rechten des Mitarbeiters, ist genau. Ein Workspace existiert, um sie falsch zu machen.
In Bromure Agentic Coding läuft der Agent in einer
hardwarevirtualisierten Linux-VM auf Ihrem Mac, und die VM hält nie echte
Zugangsdaten. Beim Start der Sitzung schreibt die App strukturerhaltende
Platzhalter in die Umgebung, in der der Agent läuft: ANTHROPIC_API_KEY,
GH_TOKEN, LINEAR_API_KEY und die übrigen als Umgebungsvariablen, und
passende Fälschungen in ~/.git-credentials, ~/.docker/config.json,
~/.kube/config, ~/.aws/config und die MCP-Konfigurationsdateien des Agenten.
Jeder Platzhalter behält die Form, die seine Werkzeuge erwarten, also nehmen sie
ihn an: ein GitHub-Platzhalter ist ghp_ plus 36 Zeichen, ein Anthropic-
Platzhalter beginnt mit sk-ant-api03-brm-, ein Kubernetes-Bearer-Token beginnt
mit brm-k8s-. Bromure leitet jeden davon per HKDF-SHA256 mit einem
installationsspezifischen Salt aus dem echten Wert ab, was ihn über Sitzungen
hinweg stabil hält und für jeden, der ihn einsammelt, wertlos macht.
Die echten Werte liegen verschlüsselt auf dem Host. Ein Proxy auf der Host-Seite setzt sie auf der Leitung ein, nachdem die Anfrage die VM verlassen hat, und nur dann, wenn das Ziel zu dem Host passt, für den diese Zugangsdaten geprägt wurden. Ein Plugin, das das Home-Verzeichnis nach Konfigurationsdateien durchkämmt, das Erste, was diese Art von Payload tut, sammelt einen Satz wohlgeformter Platzhalter ein.
Der Push muss auf dem Host genehmigt werden
Das Wertvollste, was ein kompromittiertes Plugin auf einem Entwicklerrechner tun kann, ist pushen. So wird aus einem Laptop hundert Repositories.
Guardrails klassifiziert jeden Aufruf, den der Agent an GitHub richtet. Ein
git push über HTTPS kommt am Proxy als git-receive-pack an, was als
Schreibzugriff zählt. Der Modus nur lesen weist ihn ab. Der Modus
vor dem Schreiben fragen öffnet einen Dialog auf Ihrem Mac mit dem Titel
Allow write on "<scope>" from workspace "<name>"?, der die Operation wörtlich
zeigt statt einer Zusammenfassung. Ein git fetch zählt als Lesezugriff und
geht durch, ohne Sie zu unterbrechen.
Die Klassifizierung läuft im Host-Proxy, außerhalb der VM. Code im Gast kann sie weder abschalten noch umgehen, weil er nicht auf dem Rechner läuft, der die Entscheidung trifft.
Der Ruf nach Hause trifft auf eine Regel, die der Gast nicht bearbeiten kann
Jeder Workspace hat eine Egress-Firewall: eine geordnete Liste im pf-Stil aus
Erlaubnis- und Verbotsregeln über Host, IP-Bereich, Protokoll, Port und, für
Web-Verkehr, das einzelne HTTP-Verb. allow web api.example.com GET,POST gibt
dem Agenten Abfragen ohne Änderungen, auf der Leitung, egal welches Werkzeug in
der VM die Anfrage stellt.
Zwei Schichten setzen das durch. Der virtuelle Netzwerk-Switch wendet die Regeln auf jeden Fluss an, nach Ziel-IP und per DNS mitgelesenem Hostnamen, und deckt damit einfaches TCP und UDP ebenso ab wie HTTPS. Der Proxy wendet sie erneut an, nach TLS-Servernamen und HTTP-Methode. Bromure leitet den Verkehr der Ports 80 und 443 der VM ohne Mitwirkung des Gasts in den Proxy um, sodass nichts darin sich der Inspektion entziehen kann. Ihre Änderungen erreichen laufende Sitzungen sofort, was an dem Tag zählt, an dem Sie eine Offenlegung wie diese lesen.
Darunter sitzt der Kompromittierungsdetektor, standardmäßig an und ohne etwas zu konfigurieren. Der Proxy durchsucht jede ausgehende Anfrage in einem einzigen Durchgang nach den für diesen Workspace geprägten Platzhalter-Tokens. Ein Platzhalter, adressiert an einen Host, für den er nie geprägt wurde, ist die Signatur einer Exfiltration, und der Proxy antwortet darauf mit HTTP 451 und leitet kein Byte weiter. Er pausiert die VM auf der Stelle und löst einen Alarm aus, der anbietet, den Workspace herunterzufahren, Platte und Home-Ordner zur Untersuchung zu exportieren oder auf eigenes Risiko weiterzumachen. Bromure markiert den Workspace als kompromittiert, und der nächste Start löscht die VM-Platte und den Home-Ordner, behält aber Ihre Tokens, SSH-Schlüssel und Workspace-Einstellungen. Nur der Platzhalter ist abgeflossen, es gibt also nichts zu rotieren.
Zero-Click heißt, es gibt nichts zu bemerken
Die schärfste Eigenschaft von Schritt fünf ist seine Stille. Ein Hintergrund-Update eines Plugins erzeugt weder Rückfrage noch Tool-Aufruf, also gibt die Oberfläche des Agenten dem Entwickler nichts, woran er es festmachen könnte. Airs Punkt ist, dass der Exploit in dem Teil des Systems läuft, den zu beobachten Sie keinen Anlass haben.
Ein Workspace verlegt das Beobachten woandershin. Die Sicherheits-Engines
schreiben jede Entscheidung als Zeile in das Fenster Security Timeline auf Ihrem
Mac: Firewall-Urteile (evil.example:443 tcp — blocked),
Guardrails-Durchsetzungen (DELETE api.github.com/repos/… — blocked), Credential
Brokering einschließlich der roten Zeile
blocked — exfiltration attempt, VM paused, dazu Lieferketten-Urteile und
Prompt-Injection-Treffer, farbcodiert und filterbar. Eine Sitzung kann außerdem
eine verschlüsselte Spur der ausgeführten Befehle und der erreichten Hosts
aufzeichnen.
Ein Plugin, das sich selbst aktualisiert hat, ohne es Ihnen zu sagen, muss trotzdem Anfragen stellen, und jede davon überquert eine Grenze, die ihre eigenen Notizen auf der anderen Seite des Hypervisors führt.
Prüfen Sie zuerst die Version Ihres Agenten
Claude Code 2.1.179 und Codex 0.146.0 enthalten die Korrektur. Wenn Sie Gemini CLI einsetzen, wird es keine geben. Wenn Sie Copilot einsetzen, gibt es noch keine.
Schalten Sie Plugin-Auto-Updates ab, wo Sie können
Die Zero-Click-Eigenschaft kommt vom Hintergrund-Updater. Manuelle Updates holen für Schritt fünf einen Menschen zurück in die Schleife.
Prüfen Sie den Checkout selbst in der CI
git rev-parse HEAD nach einem gepinnten Checkout, verglichen mit dem Pin,
ist dieselbe einzeilige Prüfung, die die Hersteller nachrüsten mussten. Sie
funktioniert überall, wo Sie per SHA klonen.
Nehmen Sie an, dass jemand den Checkout gewinnt
Pinning, Prüfung und die Kuratierung des Marketplace haben hier alle gehalten, und der Angriff kam trotzdem durch. Der Ausgang hängt dann davon ab, was der siegreiche Code erreichen kann.
Plugin4Shell erwischt den sorgfältigen Entwickler zu denselben Bedingungen wie den sorglosen. Wer installiert hat, was gerade angesagt war, kam nicht schlechter davon als der, der den Quelltext las, den Hash pinnte und den Pin notierte. Inhaltsadressierung sollte diesen zweiten Entwickler schützen, und sie tat es nicht, weil git die Adresse über eine Suche auflöst, die dieselben Zeichen auch für etwas anderes verwendet.
Pinnen Sie weiter. Und nehmen Sie dann an, dass eine Kontrolle, die auf einer Suche oder einem Namensabgleich ruht, eines Tages die falsche Antwort bekommt, während Sie schlafen. Entwerfen Sie für diesen Morgen: Lassen Sie den Agenten dort laufen, wo kein Schlüssel liegt, der das Mitnehmen wert wäre, und halten Sie die Aufzeichnung dessen, was er getan hat, auf der anderen Seite einer Grenze, die der Code nicht erreichen kann.