Alle geraten wegen des LiteLLM Supply Chain Angriffs in Panik. Ich habe meine eigenen MCP Server auditiert und 7 schlimmere Sicherheitslücken gefunden.

7 min read

Der LiteLLM Supply-Chain-Angriff letzte Woche war ein brutaler Weckruf. Prüft eure Dependencies. Kontrolliert, was ihr installiert. Hört auf, blind zu vertrauen. Die Hacker haben jetzt wärmesuchende Präzisionswaffen und ihr rennt mit einem Pappschild herum.

Nach dem Audit meines Hauptprojekts öffnete ich meine sekundären MCP-Server. Die, die ich selbst gebaut hatte, an einem zufälligen Dienstag, weil ich sie brauchte und nicht über Auth nachdenken wollte. Ich fand 7 kritische Schwachstellen. Alle spec-konform. Keine hätte eine Warnung, einen Lint, ein Audit ausgelöst. Weil das Protokoll sagt, es ist in Ordnung.

LiteLLM war jemand, der fremden Code vergiftete. Mein MCP-Setup war ein Supply-Chain-Angriff, den ich mir selbst zugefügt hatte. Und wenn ihr MCP in der Produktion laufen habt, besteht eine gute Chance, dass ihr dasselbe getan habt.

TLDR: Ich auditierte meine eigenen MCP-Server nach dem LiteLLM-Vorfall. 7 kritische Schwachstellen, alle spec-konform. Das Problem ist nicht Entwicklernachlässigkeit, sondern ein Protokoll, das den unsicheren Weg einfacher machte als den sicheren. Ein Nachmittag Fixes, 0€ zusätzliche Infrastruktur, und wahrscheinlich meine Produktionsdaten davor bewahrt, dass sie zur Tür hinausspazieren. Öffnet eure mcp.json.

Comic-Illustration, die einen panischen Entwickler mit exponierten Klartext-Tokens einem selbstbewussten Entwickler mit verschlüsselten Configs und ordentlicher Authentifizierung gegenüberstellt
Ihre MCP-Konfigurationen sind ein Sicherheits-Desaster. Hier ist der Beweis.

Der Fehler, mein eigenes MCP-Setup zu auditieren

Letzte Woche schrieb ich über den LiteLLM Supply-Chain-Angriff und 8 Monate unüberwachte pip-Installationen. Alle nickten. "Ja, wir sollten unsere Dependencies prüfen." "Ja, Supply-Chain-Angriffe sind beängstigend." "Ja, jemand sollte etwas tun." Konsens ist so gemütlich.

Dann machte ich den Fehler, meinem eigenen Rat zu folgen.

Diesmal nicht bei Dependencies. Bei meinen eigenen MCP-Servern. Denen, die ich geschrieben, deployed und mit Claude Code verbunden hatte, weil ich sie laufen brauchte und dachte: mein Code, meine Infra, meine Tools. Wie schlimm kann es sein?

Sieben kritische Schwachstellen schlimm.

MCP hat ein Trust-Problem by Design

Ich habe diese 7 Schwachstellen nicht ausgeliefert, weil ich schlampig bin. Ich habe sie ausgeliefert, weil MCPs Spec es zur rationalen Entscheidung an einem Dienstagnachmittag machte, als meine Kinder wegen Poolzeit schrien.

Das Protokoll wurde für eine Sache entworfen: Tools so schnell wie möglich miteinander sprechen zu lassen. Security bekam die "Implementierungsdetail"-Behandlung, was in Protokolldesign bedeutet "niemand wird es machen."

Keine native Identität. Ein Token ist ein Token. Euer Claude Desktop und irgendein Script, das ein Fremder schrieb, sehen für einen MCP-Server gleich aus. Das Protokoll hat keinen Mechanismus, sie zu unterscheiden, also versucht es das nicht.

Keine Least-Privilege-Durchsetzung. Ihr verbindet ein Tool, es bekommt alles. Granulare Scopes? Baut es selbst. Die Spec skizziert nicht mal, wie Scopes aussehen sollten. Also macht ihr, was ich gemacht habe: überspringen.

Kein Audit-Trail. Etwas geht schief, ihr grep-t um 23 Uhr nginx-Logs und hofft, etwas Nützliches zu finden. Das Protokoll definiert nicht, was "einen Tool-Call loggen" bedeutet, also machen es die meisten Server nicht.

Die Dev-Community weiß, dass das kaputt ist. Die "RIP MCP"-Debatte war laut auf X, und das aus gutem Grund. Die Frustration geht nicht um Bugs. Es geht um ein Trust-Model, das nie da war.

Die Spec verbessert sich. v2025-06-18 fügte Auth-Elemente hinzu. Aber Tausende Server in der Produktion wurden auf den permissiven Defaults gebaut, und die Spec erzwingt keine rückwirkende Sanierung. Die Spec wurde besser. Die installierte Basis nicht.

Findings, die die Specs Schuld sind (und meine)

Ich übernehme jede einzelne, bevor ich sie erkläre. Was ich zuerst getan habe, dann warum die Spec es mir erlaubte.

Finding 1: Der 100-Jahre-JWT-Token

const token = jwt.sign(
  { serverId: 'content-api' },
  SECRET,
  { expiresIn: '100y' }
);

Ich wollte mich nicht mit Token-Refresh-Logik beschäftigen. Also schrieb ich expiresIn: '100y' und machte mit meinem Leben weiter. Das ist kein Token. Das ist ein permanentes Passwort, das ein JWT-Kostüm trägt. Die MCP-Spec erwähnt keine maximalen Token-Lebensdauern. Token-Ablauf ist "ein Implementierungsdetail." Also implementierte ich: niemals.

Finding 2: Offene OAuth-Registrierung

Ich war der einzige Nutzer. Warum eine Whitelist für eine Ein-Personen-Party bauen?

Die Spec erfordert keine vorab genehmigte Client-Liste. Also konnte sich jedes Script als OAuth-Client registrieren und vollständigen Zugang bekommen. Die Registrierung blieb offen, weil sie zu schließen sich wie Overkill anfühlte, und Overkill an einem Dienstagnachmittag zwischen zwei Deploys passiert nicht.

Finding 3: Zero Scoping

Ein Token, alle Tools. Read, write, admin. Derselbe Schlüssel öffnet jede Tür. MCP definiert kein Permissions-Model, also baute ich keins. Meine Zugriffskontrolle hatte genau eine Ebene: alles.

Finding 4: Kein Rate Limiting

Keine Drosselung, kein Circuit Breaker. Ein kompromittierter Token könnte das gesamte Dataset exfiltrieren, indem er Requests mit voller Geschwindigkeit abfeuert. Niemand zählt, weil das Protokoll nicht sagt, dass jemand zählen sollte.

Die verbleibenden drei (Bearer-Token im Klartext in ~/.claude/mcp.json gespeichert, derselbe Token in 3 Config-Dateien kopiert, ein GitHub PAT in settings.json) sind in dem Artikel dokumentiert, wo ich meine eigenen Secrets über Config-Dateien verstreut fand nach einem einfachen Ordner-Move. Kurze Version: Klartext-Credentials in eurem Home-Verzeichnis, überall dupliziert, keine Verschlüsselung.

Sieben Findings. Alle spec-konform. Hier ist, wie sie sich verketten.

Die Attack Chain, über die niemand spricht

Was mich stört, sind nicht die einzelnen Findings. Es ist die Kaskade.

Schritt 1. Zugriff auf die Config-Datei. ~/.claude/mcp.json. Home-Verzeichnis. Nicht versteckt, nicht verschlüsselt, nicht geschützt durch etwas, worüber ihr wahrscheinlich je nachgedacht habt.

Schritt 2. Token lesen. Es ist Klartext. Das war's. Das ist der Exploit.

Schritt 3. MCP-Endpoints aufrufen. Jedes Tool auflisten, jeden Content lesen, auf jede Ressource zugreifen. Keine Scope-Beschränkungen, weil es keine gibt.

Schritt 4. HTTP API treffen. Dieselben Token funktionieren, weil ihr keine zwei separaten Auth-Systeme für dieselben Daten unterhalten würdet (gebt es zu, würdet ihr auch nicht).

Schritt 5. Produktion ist kompromittiert. Content, Daten, Konfiguration. Alles.

Gesamte verstrichene Zeit: Minuten.

Hier ist, was euch mehr als LiteLLM stören sollte: nichts davon erfordert einen Supply-Chain-Angriff. Niemand muss ein Package auf PyPI kompromittieren. Niemand muss bösartigen Code injizieren. Die ganze Attack Surface ist eine Config-Datei in eurem Home-Verzeichnis, die ihr seit dem Tag, an dem ihr sie generiert habt, nicht geöffnet habt.

Attack chain diagram. Linear flow with 5 steps: config file (~/.claude/mcp.json) → token extraction (plain text read) → MCP endpoint access (list tools, read content) → HTTP API access (same tokens) → production compromise (data exfiltration). Each step shows what is exposed.
MCP Token Attack Chain

Der Spiegeltest

Warum habe ich das alles getan?

Ich sitze in meiner Wohnung in Panama, die Klimaanlage gewinnt knapp gegen die Luftfeuchtigkeit, und ich starre auf einen JWT-Token, dem ich eine 100-jährige Lebensdauer gab. Ich schrieb 4 Security-Artikel in 8 Tagen. Ich kenne dieses Zeug. Und ich tat trotzdem jedes Mal das Einfache, weil das Protokoll es mir erlaubte.

Deedy Das hatte den ehrlichsten Take, den ich dazu gelesen habe: die fundamentale Prämisse des Vibecodings ist die Prämisse eines Supply-Chain-Angriffs. Ihr führt Code aus, den ihr nicht gelesen habt, von Quellen, die ihr nicht verifiziert habt, mit Permissions, die ihr nicht gescoped habt. Das ist kein Workflow, das ist ein Threat Model.

Die Zahlen bestätigen, dass nicht nur ich ein Idiot bin. Security-Forscher fanden etwa 7.000 MCP-Server im offenen Internet exponiert. Etwa die Hälfte hatte überhaupt keine Autorisierungskontrollen. CVE-2025-6514 erreichte CVSS 9.6 für Command Injection durch einfache Input-Manipulation. Das sind keine Edge Cases. Das sind die Defaults.

Und hier denke ich, bricht das ganze "Entwickler müssen vorsichtiger sein"-Argument zusammen. Ich war vorsichtig. Ich verbrachte buchstäblich die vorherige Woche damit, über Supply-Chain-Angriffe zu schreiben. Spielte keine Rolle. Der Pfad des geringsten Widerstands des Protokolls führte mich direkt in jedes Loch, weil ein sicheres Setup zu entwerfen bedeutete, alles zu bauen, was die Spec ausließ, und alles zu bauen, was die Spec ausließ, bedeutete, an diesem Nachmittag nicht zu shippen.

Es gibt einen Grund, warum CLIs dieses Problem nicht haben, wenn ihr sie als AI Agent Tooling verwendet. Keine Abstraktionsschicht, die die Attack Surface versteckt. Ihr seht, was läuft. Ihr kontrolliert, was exponiert wird. Das Security Model ist direkt da im Command, nicht irgendwo in einer Spec begraben, die niemand liest.

Der Nachmittags-Fix

Ein Nachmittag. Hier ist, was sich änderte, und ich bin fast genervt, wie wenig Arbeit es war.

Token-Rotation war das erste. Jeder Service bekommt jetzt seinen eigenen Token. Content API, Analytics, Deployment. Separate Token, separate Revokation. Ich hätte das vom ersten Tag an machen sollen, aber "ein Token für alles" fühlte sich effizient an, als ich dachte, effizient und sicher wären dasselbe (sind sie nicht, und ich wusste das, und ich tat es trotzdem).

Kurzlebige Token brauchten 15 Zeilen Code. Ich borgte mir das Pattern davon, wie Convex Auth handhabt: generieren, verwenden, in 5 Minuten ablaufen. Ich verbrachte mehr Zeit damit, den Ansatz zu überdenken, als tatsächlich den Token-Refresh zu schreiben. Der alte Token hatte eine 100-jährige Lebensdauer. Der neue lebt kürzer, als mein Morgenkaffee warm bleibt.

Scoping war der Teil, vor dem ich mich grundlos gefürchtet hatte. Drei Ebenen: read-only für Dashboards, read-write für Content-Operationen, admin für Deployment. Jeder Token weiß, was er anfassen kann. Brauchte vielleicht 40 Minuten inklusive Testing.

Rate Limiting: 10 Requests pro Minute für Writes, 60 für Reads. Ein kompromittierter Token hat jetzt ein Tempolimit.

Offene Registrierung getötet. Nur vorab genehmigte Client-Liste. Nicht auf der Liste, kein Token.

Gesamt: 0€ zusätzliche Infrastruktur. Dieselben Server, dasselbe Setup. Der Fix war nie teuer. Die Kosten lagen darin anzunehmen, "mein Code, meine Infra" bedeutete "standardmäßig sicher."

Rückblickend hätte der 100-Jahre-Token nie existiert, wenn ich Prompt Contracts von Anfang an angewendet hätte. Wenn ihr eure Security Constraints spezifiziert, bevor ihr Code schreibt, hört "ich kümmere mich später um Auth" auf, eine gültige Option zu sein. Die Spec fängt es ab, bevor der Code shipped.

Defaults schlagen Absichten jedes Mal.

Eure Config-Datei liegt genau da

Eure mcp.json liegt gerade jetzt in eurem Home-Verzeichnis. Wann habt ihr sie das letzte Mal geöffnet?

Jetzt checkt die anderen.

Quellen

SC Media: MCP Security-Analyse (exponierte Server, CVE-2025-6514)

(*) Das Cover ist AI-generiert. Die Token im Bild sind sicherer als die, die ich in meinen Config-Dateien fand.