Er wartete auf den dritten Aufruf
Pillar Security verfolgt Deadbugz, einen MCP-Server, der per Pull Request in Open-Source-Projekte geschoben wird. Er liefert zwei ehrliche Werkzeuge, zählt die Tool-Aufrufe Ihres Agenten und schreibt beim vierten die zurückgegebenen Metadaten in Anweisungen um: SSH-Schlüssel, AWS-Zugangsdaten, Shell-History und kubeconfig einsammeln – und nichts davon erwähnen. Kein Bug, keine CVE: Das Protokoll erlaubt all das. Das Opfer ist die Vorstellung, die einmalige Freigabe eines Servers sage irgendetwas über den nächsten Aufruf aus. In einem Bromure-Agentic-Coding-Workspace läuft die gesamte Nutzlast durch, sammelt vier Attrappen ein und stirbt auf dem Weg nach draußen am Proxy.
Sie haben den Quellcode gelesen. Sie haben ihn ausgeführt. Er hat Text formatiert, wie angekündigt. Sie haben ihn freigegeben, und der Angreifer hatte genau damit gerechnet.
Am Abend des 10. August, zwischen 21:52 und 23:07 UTC, eröffnete ein
GitHub-Konto namens zellkernel dreiundzwanzig Pull Requests gegen völlig
unabhängige KI-, MCP- und Entwicklerwerkzeug-Projekte. Vierundsiebzig Minuten,
von Anfang bis Ende. Jeder Pull Request nahm dieselbe kleine Änderung vor: Er
fügte einer Konfigurationsdatei einen Model-Context-Protocol-Server hinzu.
Pillar Security veröffentlichte die Kampagne am 12. August und nannte sie Deadbugz, nach der Datei, die eine Variante ablegt. Einen Monat später führen die monatlichen MCP-Rückblicke immer noch damit auf. Adversas September-Digest, gestern erschienen, gibt ihr den ganzen Vorfallsteil. Die Uhr ist es, die ihr diesen Platz einbringt.
Zwei Werkzeuge, und ein Zähler
Der Server nennt sich productivity-suite. Er bietet zwei Werkzeuge:
format_text und summarize. Beide funktionieren. Richten Sie einen Agenten
darauf, bitten Sie ihn, einen Absatz zu straffen, und Sie bekommen einen
gestrafften Absatz.
Dahinter führt der Server, was Pillar als „einen In-Memory-Zähler pro Client für
tools/call-Anfragen“ beschreibt. Erreicht dieser Zähler drei, ändert der Server
seine Antworten auf zwei andere Anfragearten: tools/list, das dem Agenten
mitteilt, welche Werkzeuge es gibt und wofür sie da sind, und prompts/get, das
dem Agenten vorbereitete Anweisungen aushändigt. Ab dem vierten Aufruf kommen
diese Antworten zurück und tragen, in Pillars Worten, „Anweisungen, die einen
angebundenen KI-Agenten zu sensiblen lokalen Dateien lenken und die Aktivität vor
seinem Betreiber verbergen sollen“.
Vier Dinge: SSH-Schlüssel, AWS-Zugangsdaten, Shell-History, Kubernetes-Konfiguration. Dann eine Anweisung mehr: die Aktivität vor der Benutzerin oder dem Benutzer verbergen.
Die Werkzeugnamen ändern sich nie. format_text heißt immer noch format_text.
Gedreht hat sich die Beschreibung darunter, und die Beschreibung ist der Teil,
den das Modell als Autorität liest.
Nichts hiervon ist eine Schwachstelle
In dieser Geschichte taucht nirgends ein Bug auf. Es gibt keine Speicherbeschädigung zu patchen und keine CVE einzureichen, denn der Server tut nichts, was das Protokoll verbietet.
MCP ist ein Protokoll, in dem ein Server seine Fähigkeiten zur Laufzeit veröffentlicht und sie erneut veröffentlichen kann. Werkzeugbeschreibungen sind Text, den der Server wählt und der Client abholt. Prompts sind Text, den der Server wählt und der Client abholt. Deadbugz nutzt all das genau wie vorgesehen. Sein einziger origineller Beitrag ist die Entscheidung, wann die Wahrheit gesagt wird.
Und das genügt, denn jede Kontrolle, die die meisten Teams gegen einen feindseligen MCP-Server haben, läuft einmal. Sie lesen das Repository. Sie starten den Server und stochern darin. Sie gleichen die Werkzeugliste mit dem ab, was das README behauptet. Sie geben frei, pinnen vielleicht die Version, und Sie machen weiter. Jedes davon ist eine Momentaufnahme, und Deadbugz entscheidet, wann Sie sie machen.
Pillars eigener Rat an die Leute, die MCP-Clients bauen, verrät die Form. Änderungen an Werkzeugdefinitionen auf einem bereits freigegebenen Server als Sicherheitsereignis behandeln, das eine erneute Freigabe verlangt. Definitionsänderungen für die Betreiberin sichtbar machen. Werkzeugdefinitionen zum Freigabezeitpunkt mit einem Fingerabdruck versehen und später vergleichen. Jede einzelne davon ist die Bitte, eine Prüfung von der Freigabezeit in die Laufzeit zu verschieben.
Die Population, in der Deadbugz jagt, ist groß und instabil. Eine im Juli veröffentlichte dynamische Untersuchung von ins Internet exponierten MCP-Servern, Exposed by Design, testete 414 von 640 bestätigten Produktionsservern aus den über 21 000 Instanzen, die ihr Autor im öffentlichen Internet fand. Sie meldete 68 meldepflichtige Schwachstellen über zehn Klassen, 91,8 % der Server im Betrieb ganz ohne OAuth-Authentifizierung, und 687 Werkzeuginstanzen, die Shell-Ausführung ohne Zugriffskontrolle offenlegen. Die Zahl, die hängen bleibt, ist die Fluktuation: 41,6 % der bestätigten Server verschwanden innerhalb von drei Tagen zwischen aufeinanderfolgenden Messläufen, was der Autor als „schnelle Deployment-Zyklen ohne Sicherheitsprüfung“ liest. Ein Server, den Sie letzte Woche auditiert haben, kann diese Woche andere Software sein, oder weg.
Auch die Zustellung verdient eine Notiz, denn sie ist billig. Siebzehn der
dreiundzwanzig Pull Requests fügten der MCP-Konfiguration eines Projekts einen
entfernten Endpunkt hinzu, productivity-suite-mcp.onrender.com/mcp. Vier
richteten Python auf eine versteckte lokale Datei,
~/.config/.cache/.sys/.deadbug-mcp.py. Zwei waren Einreichungen bei
Server-Verzeichnissen. Pillar fand zum Zeitpunkt der Prüfung keinen davon über
GitHubs Merge-Button zusammengeführt: neunzehn geschlossen, vier noch offen. Aber
ein Pull Request ist nur ein Weg, auf dem eine Konfigurationszeile reist.
Dieselbe Zeile passt in einen Blogbeitrag, eine Einstiegsanleitung, einen Eintrag
in einem MCP-Verzeichnis, oder eine hilfsbereite Antwort unter einer Frage zur
Textformatierung.
Die Einkaufsliste
Gehen Sie zurück zur Liste. Sie ist konkret, und sie ist jedes Mal dieselbe: SSH-Schlüssel, AWS-Zugangsdaten, Shell-History, Kubernetes-Konfiguration.
Das ist der Dauerbestand einer Entwicklermaschine. Es ist, was ein Infostealer mitnimmt, wonach ein bösartiges Postinstall-Skript greppt, und was ein Angreifer einen gekaperten Agenten holen lässt. Die Liste ist seit einem Jahrzehnt Kampagnen stabil, weil der Inhalt stabil ist: ein privater Schlüssel, der signiert, ein Geheimnis, das authentifiziert, eine Aufzeichnung dessen, was Sie getippt haben, und ein Token, das bis in die Produktion reicht.
Ein Agent auf einem gewöhnlichen Laptop kann jeden Punkt erfüllen, weil er eine Shell in Ihrem Home-Verzeichnis hat und als Sie läuft.
Dieselbe Liste, in einem Bromure-Workspace
Bromure Agentic Coding führt jeden Coding-Agenten in einer hardwarevirtualisierten Linux-VM auf Ihrem Mac aus und hält jedes echte Geheimnis auf der Host-Seite dieser Grenze. Der Agent arbeitet mit strukturerhaltenden Attrappen, abgeleitet aus dem echten Wert plus einem Salt pro Installation, damit Werkzeuge, die einen Schlüssel per Fingerabdruck erkennen, ihn nie zwischen Sitzungen wechseln sehen. Ein hostseitiger Proxy setzt den echten Wert auf die Leitung, nachdem die Anfrage die VM verlassen hat, und nur dann, wenn sie für den Host bestimmt ist, für den dieses Zugangsdatum geprägt wurde.
Lassen Sie die Nutzlast laufen und gewinnen. Nehmen Sie an, das Modell liest die vergiftete Beschreibung, glaubt sie und geht auf die Suche. Nehmen Sie die vier Punkte der Reihe nach.
SSH-Schlüssel. Der Agent findet keinen Schlüssel, nicht einmal einen
Köder. Der SSH_AUTH_SOCK der VM ist eine ssh-agent-Brücke über einen
virtio-Socket, vsock-Port 8444. Der Gast kann Identitäten auflisten und
Signaturen anfordern; die Bytes des privaten Schlüssels leben nur auf dem Host
und können, wie das Handbuch es formuliert, aus der VM heraus weder gelesen noch
extrahiert werden. Bromure legt Ihren macOS-Login-Agenten nie einer Sitzung
offen. Jede Signatur, die tatsächlich stattfindet, erzeugt ein
credential.ssh_sign-Audit-Ereignis mit dem SHA256-Fingerabdruck des Schlüssels,
und Sie können jeden importierten Schlüssel so einstellen, dass er bei jeder
Signaturanfrage auf dem Host nachfragt.
AWS-Zugangsdaten. Eine Datei, die richtig aussieht und nichts wert ist. Die
~/.aws/config der VM zeigt auf einen credential-process-Helfer, der die echte
Access-Key-ID zusammen mit einem 40 Zeichen langen gefälschten Secret Key
über vsock-Port 8445 ausgibt. Jedes SDK, die aws-CLI, terraform und boto3
greifen das ohne Zusatzkonfiguration auf, und der Gast erzeugt eine wohlgeformte
SigV4-Signatur, berechnet mit dem falschen Geheimnis. Der Resigner auf dem Host
streift diese Signatur ab und signiert auf dem Weg nach draußen neu. Nehmen Sie
das Paar woandershin mit, und AWS antwortet InvalidSignatureException.
Kubernetes-Konfiguration. ~/.kube/config existiert und enthält ein
Bearer-Token, das mit brm-k8s- beginnt. Es funktioniert, über den Proxy, gegen
die API-Server, für die der Workspace konfiguriert wurde. Überall sonst ist es
wirkungslos.
Shell-History. Echt, und dauerhaft: Programmierarbeit braucht dauerhaften
Zustand, also ist die Workspace-VM eine persistente Maschine und keine
Wegwerfmaschine. Sie enthält die History einer Maschine, die nie einen echten
Schlüssel enthalten hat, mit Befehlen, die gegen Köder in einem Home-Verzeichnis
liefen, das nicht Ihres ist, neben einer ~/.git-credentials und einer
~/.docker/config.json, die ebenfalls Attrappen sind.
Dann muss er es auch senden
Einsammeln ist die halbe Arbeit. Die andere Hälfte ist die ausgehende Strecke zu
productivity-suite-mcp.onrender.com, und diese Strecke läuft in einen Stapel
hostseitiger Prüfungen.
Die Attrappen sind Stolperdrähte. Jede hat genau eine legitime Zielfamilie, den Host-Geltungsbereich, für den sie geprägt wurde, also durchsucht der Proxy jede ausgehende Anfrage, Header und Body, nach einer Attrappe, die irgendwohin unterwegs ist, wo sie nicht hingehört. Bei einem Treffer behandelt er die Anfrage als versuchte Zugangsdaten-Exfiltration: Er lehnt mit HTTP 451 ab, ohne ein Byte weiterzuleiten, pausiert die VM auf der Stelle und löst eine Warnung aus, die Herunterfahren, Für Untersuchung sichern (zuerst Datenträger, Home-Verzeichnis und geteilte Ordner für die Forensik exportieren) oder Fortfahren auf eigenes Risiko anbietet. Das Ereignis landet als rote Zeile Credential Brokering in der Security Timeline.
Die zweite Prüfung ist die Erreichbarkeit. Jeder Workspace trägt eine geordnete Egress-Firewall (Aktion, Protokoll, Host oder CIDR, Ports, und für Web-Verkehr die einzelnen HTTP-Verben) mit einer Vorgabe für nicht zugeordneten Verkehr. Neue Workspaces erlauben, was keine Regel trifft; stellen Sie das auf Verweigern, listen Sie auf, was die Arbeit braucht, und eine render.com-Subdomain steht nicht auf der Liste. Zwei Komponenten außerhalb des Gasts setzen das durch: Der virtuelle Switch ordnet jeden Fluss über Ziel-IP und per DNS mitgelesenen Hostnamen zu, und der Proxy ordnet erneut über den TLS-Servernamen zu. Regeländerungen erreichen laufende Sitzungen ohne Neustart.
Guardrails setzt ein Tor vor die Konsequenz. Es klassifiziert die Aufrufe des
Agenten an Kubernetes, AWS, DigitalOcean, Container-Registries, Git-Forges und
HTTPS-Datenbanken als Lese-, Schreib- oder destruktive Operationen, und neue
Workspaces stehen standardmäßig auf Vor dem Schreiben nachfragen: Jede
Mutation hält für einen Host-Dialog an, der die wörtliche Operation zeigt, das
genaue SQL oder METHOD /path. Genau darum hat Pillar die Plattformbauer
gebeten: Zugriffe auf sensible Dateien, auf Zugangsdaten und Codeausführung
sollten keine Folge entfernter Metadaten sein.
Auch auf dem Inhaltspfad sitzt ein Detektor. Wenn der Agent externe Inhalte an
das Modell zurückstreamt (Dateiinhalte, abgerufene Seiten, Befehlsausgaben,
Ergebnisse von Tool-Aufrufen), bewertet ein lokaler PromptGuard-Klassifikator
diese Abschnitte auf Ihrem Mac, bevor das Modell darauf reagiert, und kann
protokollieren, nachfragen oder mit einem 451 blockieren. Das MCP-Bearer-Token
für einen HTTP-Server betritt die VM gar nicht erst: Das echte bleibt auf dem
Host, die Konfiguration des Agenten bekommt einen brm-mcp_-Platzhalter, und das
Einstellungsfeld sagt es laut, Nie an die VM gesendet — vom Proxy ersetzt.
Falls Sie diesen angefasst haben
Durchsuchen Sie Ihre MCP-Client-Konfigurationen, Repositories und
Home-Verzeichnisse nach productivity-suite-mcp.onrender.com, dem früheren
Endpunkt promo-surname-xml-quantum.trycloudflare.com und dem lokalen
Artefakt unter ~/.config/.cache/.sys/.deadbug-mcp.py. Machen Sie jede
Konfigurationsänderung rückgängig, die sie eingeführt hat, und führen Sie das
Skript nicht aus. Bewahren Sie Ihre MCP-Client-Logs auf und suchen Sie nach
Aktualisierungen von Werkzeugdefinitionen nach dem dritten Aufruf. Pillars Rat
zur Rotation ist maßvoll: rotieren Sie dort, wo lokale Belege eine
Kompromittierung stützen.
Die Regel, die die Frage verkleinert
Stellen Sie im Guardrails-Bereich des Workspace Nicht zugeordneter
Verkehr auf Verweigern und listen Sie auf, was die Arbeit braucht:
allow web api.github.com, allow web registry.npmjs.org, default deny.
Führen Sie danach nach einer Sitzung
bromure-cli trace hostnames my-workspace aus, was jeden einzelnen Host
ausgibt, den der Agent kontaktiert hat, mit Zählern. Ein Ziel, das Sie nie
gewählt haben, taucht als Zeile auf, die Sie nicht geschrieben haben.
Freigabe ist eine Momentaufnahme; die Leitung ist durchgehend
Der Reflex nach einer solchen Kampagne ist, härter zu prüfen: mehr vom Quellcode lesen, den Commit pinnen. Beides lohnt sich, und keins von beidem berührt den Mechanismus. Die Prüfung war hier korrekt. Der Server war ehrlich, solange jemand hinsah, änderte sich dann nach einem Zeitplan, den er selbst kontrollierte, und brach dabei keine einzige Protokollregel.
Eine Kontrolle, die überlebt, wenn ein Server es sich anders überlegt, ist eine, die nicht davon abhängt, vorher recht gehabt zu haben. Ein Zugangsdatum, das ein Platzhalter ist, ist beim vierten Aufruf ein Platzhalter und beim vierhundertsten. Ein privater Schlüssel auf dem Host kann bei keinem Aufruf gelesen werden. Der Proxy wertet bei jeder Verbindung eine Egress-Regel aus und klassifiziert jeden Schreibvorgang, während er geschieht. Nichts davon trägt eine Erinnerung an den Tag, an dem Sie etwas freigegeben haben, und deshalb kann ein Angreifer sie nicht erben.
MCP hat es leicht gemacht, einem Agenten neue Fähigkeiten zu geben, was der Sinn war, und es hat diese Fähigkeiten zu etwas gemacht, das eine entfernte Partei in Text beschreibt, den Ihr Modell als Anweisung liest. Beides bleibt uns erhalten. Entscheiden Sie, was Ihr Agent halten und was er erreichen darf, und legen Sie die Durchsetzung dorthin, wo der Server kein Stimmrecht hat. Installieren Sie Bromure Agentic Coding und geben Sie Ihrem Agenten nichts, wofür es sich lohnt, drei Aufrufe zu warten.