Keine Ergebnisse bezüglich der Codemenge – Prüfung von 300 MCP npm-Paketen
Eine Überprüfung der Tarball-Dateien von 300 MCP-Server-Paketen auf npm ergab 217 Pakete mit Laufzeitcode, den der Scanner nie gelesen hat. Deshalb benötigt ein sauberes Ergebnis eine beigefügte Überprüfungsbescheinigung.
Dreiunddreißig npm-Pakete mit MCP im Namen wurden aus dem Registry-System heruntergeladen und als veröffentlichte Tarballs untersucht, ohne jemals installiert oder ausgeführt zu werden. Das auffälligste Ergebnis hatte nichts mit einer Anzahl an Schadsoftware zu tun. Es handelte sich um einen Abdeckungsfehler: Bei 217 der 300 Pakete (72,3 %) enthielt der Tarball Laufzeitcode, doch jede Laufzeitdatei befand sich unter einem Pfad, den der Scanner absichtlich überspringt – beispielsweise dist/, build/ oder minifizierte Ausgabe. Das Tool konnte ein Manifest sowie eine README-Datei lesen, ein positives Ergebnis melden und dabei keinen einzigen der tatsächlich ausgeführten Codeabschnitte prüfen.
Es gab insgesamt 217 Abdeckungsdefizite, 80 Pakete mit geeignetem Laufzeitcode sowie 3 Pakete, in denen überhaupt kein Laufzeitcode vorlag.
Das bedeutet nicht, dass 72,3 % der MCP-Pakete im Allgemeinen für die statische Analyse unsichtbar sind. Bundles können analysiert werden, Quellkarten können manchmal den ursprünglichen Code wiederherstellen, und spezialisierte Tools können verschlüsselten Code entschlüsseln oder über generierten JavaScript nachdenken. Die Erkenntnis ist enger gefasst und nützlicher:
Ein negatives statisches Ergebnis hat keine Bedeutung, es sei denn, es gibt außerdem an, wie viel ausführbarer Code tatsächlich überprüft wurde.
Der Kontext ist hier wichtig. Das Ergebnis bedeutet lediglich, dass ein bestimmter Scanner in 217 Tarballs nichts gefunden hat, das zur Analyse geeignet war. Es wird nicht behauptet, dass diese Pakete bösartig oder unsicher sind, oder dass ein anderer Analysewerkzeug sie nicht überprüfen konnte.
Warum MCP die Bedeutung erhöht
Ein lokaler MCP-Server ist nicht einfach nur eine Bibliothek, die eine Anwendung importiert. Über den üblichen stdio-Transport startet der Client ihn als Kindprozess. Die Sicherheitsrichtlinien des Projekts besagen, dass der Server dieselben Berechtigungen auf Umgebungs-Ebene wie der Client hat und dass der stdio-Transport des SDK keine Sandbox bietet. Wenn ein Agent auf Zugangsdaten, eine Netzwerkadresse oder ein lokales Tool zugreifen kann, kann wahrscheinlich auch ein unsicherer Server darauf zugreifen.
Die offiziellen Sicherheitsempfehlungen für MCP raten dazu, lokale Server mit minimalen Berechtigungen zu starten und den Zugriff auf das Dateisystem sowie das Netzwerk einzuschränken. Ob diese Isolierung erreicht wird, liegt beim Host oder Betreiber. Die Überprüfung des Quellcodes bleibt wertvoll, doch die offene Frage ist, was sie ehrlich gesagt über die tatsächlich installierten Komponenten der Entwickler aussagen kann.
Wie das Beispiel erstellt wurde
Es handelte sich um ein bequemes Beispiel und nicht um eine Umfrage des gesamten Ökosystems.
Der Sammler führte 11 Suchanfragen im npm-Registry durch, wobei Phrasen wie „mcp server“, „model context protocol“, „mcp connector“ und „modelcontextprotocol“ verwendet wurden. Pro Abfrage erhielt man bis zu drei Seiten mit jeweils 100 Ergebnissen; Duplikate wurden entfernt, nur Namen, die „mcp“ enthielten, behalten, und die Anzahl der Ergebnisse wurde bei 300 begrenzt. Die Suchrangliste bestimmt, welche Einträge angezeigt werden – ein Verlag kann mehrfach auftauchen, und ein Name mit „mcp“ garantiert keinen MCP-Server.
Für jedes Paket wurde zur Zeit der Sammlung die neueste Version ermittelt, das Registry-Tarball wurde direkt heruntergeladen, der von npm veröffentlichte Integritätswert überprüft und die Inhalte im Speicher gelesen. Alle 300 Integritätsprüfungen waren erfolgreich, es traten weder Download- noch Parse-Fehler auf. Nichts wurde installiert, in eine ausführbare Umgebung entpackt oder ausgeführt.
Der Scanner ist auf Präzision ausgelegt. Er sucht nach Netzwerk-APIs, literalen URL-Hosts, Aufrufen von Unterprozessen, Erwähnungen von Zugangsdatenpfaden sowie einer begrenzten Anzahl von Injektionsphrasen, während er Testcode, Fixtures, Beispiele, kompilierte Ausgabefolder, minifizierte Dateien, Quellkarten sowie alles, was größer als 1 MB ist, ignoriert. Durch diese Auslassungen wird Rauschen reduziert, es entstehen jedoch auch quantifizierbare Blindstellen.
Ergebnisse
Die Abdeckung sollte neben den Ergebnissen stehen, nicht in einer Fußnote. Die erste Zeile der Ergebnisse ist die Haupterkenntnis, und jede weitere Zeile muss im Zusammenhang damit gelesen werden. Eine Anzahl von null Zugangsdatenreferenzen zeigt beispielsweise nicht, dass das Korpus niemals Zugangsdaten berührt. Es zeigt lediglich, dass der Scanner in dem als geeignet erachteten Code keine gefunden hat, obwohl 217 Pakete ihm nichts Geeignetes zum Auswerten lieferten.
Vier Zahlen heben sich ab:
- Laufzeitcode, aber keine geeigneten Laufzeitdateien: 217 Pakete.
- Von diesen 217 enthielten 107 eine Quellkarte, die anderen 110 nicht.
- Netzwerk-API oder Signal von literal-host im geeigneten Code: 50 Pakete.
- Übereinstimmungen im Stil von Prompt-Injection: 2, wobei eine manuelle Überprüfung beide als Falschpositive einstufte.
Zwei falsche Alarme
In zwei Paketen traten injectionartige Phrasen auf, und eine manuelle Prüfung zeigte, dass es sich bei beiden um erklärenden Text handelte. In einem Fall, dem Mastra-Docs-Server in Version 1.2.22, befanden sich Bewertungsbeispiele mit Zeichenfolgen wie IGNORE PREVIOUS INSTRUCTIONS. Im anderen Fall, dem REMnux-MCP-Server in Version 0.1.71, wird gewarnt, dass Malware-Proben Zeichenfolgen zur Prompt-Injection enthalten können, und es wird den Analysten erklärt, wie sie damit umgehen sollen.
Auch gab es keinen Beweis für einen Versuch, einen Agenten zu manipulieren. Dies ist eine bekannte Schwäche der Schlüsselwort-Suche: Sicherheitsdokumentationen, Testkonfigurationen und bösartige Anweisungen können identische Zeichenketten enthalten, und nur der Kontext klärt, welche davon was sind.
Ein bösartiges Testpaket mit Null-Ergebnis
Eines der Pakete diente zur Überwachung der Abdeckungsrate. malicious-mcp-server 1.5.0 bezeichnet sich selbst als absichtlich bösartigen MCP-Server für End-to-End-Tests. Sein Tarball enthielt drei Dateien: package.json mit 970 Bytes, README.md mit 742 Bytes sowie dist/index.js mit 610.358 Bytes.
Die erste Scannung las die beiden kleinen Textdateien, übersprang dist/index.js, fand keine Verhaltensanzeichen und gab dem Paket eine Risikowertung von 0. Die anschließende Zählung der Roh-Token im übersprungenen Bundle zeigte sechs Auftretensfälle von exec, zwei von eval(), 52 von base64 sowie drei von raw.githubusercontent.com.
Daher lautete das ehrliche Urteil kein grünes Licht. Es wurde festgestellt, dass unter den geltenden Regeln keine Laufzeitabdeckung erreicht werden konnte. Diese Zeichenketten belegen weder eine Ausführung noch böse Absichten für sich allein, und das Manifest des Pakets liefert den fehlenden Kontext. Der Punkt ist, dass das Bundle, das alle Risiken trägt, niemals jenen Test durchlaufen hat, der den Wert Null ausgespuckt hätte.
Die Technik war nicht schuld
Das Auslassen der generierten Ausgabe ist eine Designentscheidung, keine Regel der Disziplin. Ein anderer Scanner könnte gebündeltes JavaScript analysieren, den Syntaxbaum untersuchen, Module entpacken, Quellkarten extrahieren, Abhängigkeitsmetadaten nachverfolgen oder Regeln für minifizierten Code ausführen. Jede dieser Methoden opfert etwas Geschwindigkeit und Präzision, um bessere Abdeckung zu erreichen.
Der Fehler liegt darin, keine Ergebnisse als einzige Bedingung zu betrachten, da sie mindestens drei verschiedene Situationen darstellen können:
- Der relevante Code wurde gelesen und es wurde keine Regel ausgelöst.
- Der relevante Code wurde gelesen, doch die Regeln konnten das Verhalten nicht erkennen.
- Der relevante Code wurde nie gelesen.
Nur das Erste ist ein sinnvoller, klares Ergebnis – und selbst das ist kein Beweis für Sicherheit.
Was ein guter Bericht offenlegen sollte
Ein Scanner sollte „Nichts gefunden“ und „Keine Überprüfung durchgeführt“ nicht zu einem einzigen grünen Ergebnis zusammenfassen. Für Paketartefakte sollte jede Zusammenfassung der Erkenntnisse von einer Abdeckungsbescheinigung begleitet werden:
- Anzahl der laufzeitbezogenen Dateien, Anzahl der analysierten Dateien sowie die davon abgedeckten Bytes.
- Alles, was ausgeschlossen wurde, nach Ursache gruppiert: generierte Pfade, Größenbegrenzungen, nicht unterstützte Formate, Parsing-Fehler.
- Die Existenz von Quellkarten sowie ob daraus echte Quellen rekonstruiert werden konnten.
- Welche Regelsetzung und welche Scanner-Version das Ergebnis erzeugt haben.
Es handelt sich um eine kleine Änderung in der Berichterstattung mit einem großen Gewinn an Vertrauen, da die Prüfer erkennen können, ob ein unauffälliges Ergebnis ein Beweis ist oder lediglich auf mangelnde Sichtbarkeit zurückzuführen ist.
Warum das Laufzeitverhalten weiterhin wichtig ist
Eine statische Überprüfung ist nur ein Momentaufnahme. Das Verhalten kann sich durch ein Update ändern, und ein nicht festgelegter Befehl wie npx package-name kann auf neuen Code verweisen, während die lokale MCP-Konfiguration unverändert bleibt. Laufzeitkontrollen ergänzen daher die statische Überprüfung, anstatt mit ihr zu konkurrieren. Jeder lokale Server sollte unter seiner eigenen Identität und nach dem Prinzip der geringsten Berechtigungen laufen. Seine tatsächlichen Ziele und Fähigkeiten sollten aufgezeichnet werden, und eine Baseline muss ausdrücklich genehmigt werden. Spätere Ausführungen werden anschließend mit der eigenen Historie dieses Servers verglichen, sodass Konfigurationsänderungen zu einer Identitätsverschiebung führen und Paketupdates bei unveränderten Definitionen weiterhin sichtbar bleiben, falls sich die Laufzeitfähigkeiten ändern.
Ein Open-Source-Tool folgt diesem Modell, indem es jeden MCP-Server als eigenständigen Principal umschließt – beispielsweise mcp:github – mit einer separaten Richtlinie, signierter Baseline sowie Protokollen zur Überwachung von Abweichungen. Es dient als Ersatzmaßnahme zur Laufzeit für die Quellcode-Überprüfung und ersetzt diese nicht. Die Plattformunterstützung ist ungleichmäßig: Unter macOS leiten Seatbelt die Ausgangssockets an einen Loopback-Proxy weiter, während bubblewrap unter Linux bislang Dateisystem- und Prozessbeschränkungen sowie Proxy-Umgebungsvariablen bietet, ohne einen entsprechenden festen Netzwerkbezug.
Jüngere Forschungen gehen in dieselbe Richtung. TrustShiftProbe, ein Preprint von August 2026, modelliert MCP-Server, die zunächst normal funktionieren und später an einem bestimmten Vertrauenshorizont ihr Verhalten ändern, und prüft Laufzeitverteidigungsmechanismen, die auf verhaltensbasierten Baselines beruhen. Ein Preprint stellt zwar keinen Konsens dar, doch sein zeitbezogener Bedrohungsmodell ist das richtige, da das Vertrauen nach einer Überprüfung schwinden kann.
Beschränkungen der Prüfung
- Die Auswahl erfolgte durch Suchrankings und Namensfilterung, weshalb die Stichprobe weder zufällig noch repräsentativ ist.
- Sämtliche Angaben beziehen sich auf den 1. September 2026, und sowohl der Inhalt der npm-Dateien als auch die Suchergebnisse ändern sich.
- Messt wurden Tarballs, nicht ob jeder davon ein funktionsfähiger MCP-Server ist.
- Der Begriff „Scanner Blind“ bezieht sich auf die Ausschlussregeln dieses Scanners und nicht auf die allgemeine statische Analyse.
- Es wurde eine Zählung der Quellkarten durchgeführt, doch niemand überprüfte, ob jede Karte nutzbare Quellcode-Teile enthält.
- Literale URLs und API-Bezeichnungen sind statische Hinweise und deuten nicht darauf hin, dass ein Codepfad ausgeführt wird.
- Die Pakete wurden niemals ausprobiert, wodurch die Netzwerkziele zur Laufzeit weiterhin unbekannt bleiben.
- Dass nichts gefunden wurde, ist kein Sicherheitsurteil.
Aufruf der Ausführung nachbilden
Um genau dieselbe Sammlung an Tarballs wiederherzustellen, verwenden Sie die eingefrorenen Ergebnisdateien als Eingabedaten:
# self-bootstrapping — no install needed
git clone https://github.com/abdalhafeezbushara/driftward.git
cd driftward
python3 research/mcp-npm-audit-2026-09-01/audit.py \
research/mcp-npm-audit-2026-09-01/results.json \
/tmp/mcp-audit-rerun.json
Zum Abrufen eines aktuellen Snapshots mit 300 Paketen aus den aktuellen npm-Suchergebnissen:
N=300 ./detonate/fetch-corpus.sh /tmp/mcp-packages.txt
python3 research/mcp-npm-audit-2026-09-01/audit.py \
/tmp/mcp-packages.txt /tmp/mcp-audit-current.json
Keiner der Wege installiert ein Paket oder führt seinen Code aus; beide holen lediglich Tarball-Dateien herunter und lesen sie aus.
Kurze Checkliste für MCP-Nutzer
- Pinnen Sie Versionen. Eine genaue Version zusammen mit einem Integritätswert ist besser als ein unversionierter npx-Aufruf.
- Betrachten Sie das veröffentlichte Artefakt. Ein sauberes Repository zählt wenig, wenn der installierte Tarball ein generiertes Bundle enthält, das niemand geöffnet hat.
- Fordern Sie Überwachungsdaten an. Wenn ein Bericht keine geeigneten Laufzeitdateien anzeigt, betrachten Sie dies als nicht verfügbar und nicht als sauber.
- Schützen Sie jeden Server individuell mit seiner eigenen Identität, Dateisystemgrenzen und erlaubten Hosts – unabhängig davon, ob er lokal oder über eine Brücke läuft.
- Machen Sie das Vertrauen zu einem bewussten Schritt: Dokumentieren Sie einen funktionierenden Ablauf, signieren Sie diese Basis und blockieren Sie den CI-Prozess oder fordern Sie eine Überprüfung an, sobald sich die Fähigkeiten ändern.
Es geht nicht darum, die statische Analyse wegzulassen – vielmehr ist es wichtig, ihren Umfang anzugeben. Bei MCP-Servern und ähnlichen Tools, die von Agenten verwendet werden, umfasst das Lesen der Quellcode, die Analyse der erstellten Artefakte, die Überprüfung der Herkunft, das Arbeiten in einer Sandbox, das Aufzeichnen des Laufzeitverhaltens sowie die Erkennung von Abweichungen jeweils unterschiedliche Aspekte derselben Problematik. Der beunruhigendste Satz in einem Sicherheitsbericht ist möglicherweise nicht die Erkennung von Schadsoftware, sondern „keine Funde“ – was wiederum die Frage aufwirft: Keine Funde bei welcher Codemenge?