In this article
Sichere MCP-Server entwickeln: Ein Leitfaden für Entwickler zur Vermeidung kritischer Schwachstellen
Das Model Context Protocol (MCP) hat sich schnell zum De-facto-Standard für die Erweiterung von KI-Funktionen entwickelt. Seit Anthropics Ankündigung im November 2024 haben Entwickler in großer Zahl MCP-Server entwickelt, die LLMs mit Datenbanken, Dateisystemen, APIs und Befehlszeilentools verbinden. Doch im Wettlauf um mehr Autonomie für KI wurde Sicherheit oft erst nachträglich berücksichtigt – und das Bewusstsein für die vorhersehbaren Sicherheitsfolgen wächst.
Die Wahrheit ist ernüchternd: MCP-Server sind schlicht zusätzlicher Code. Und mehr Code bedeutet mehr Fehler, eine größere Angriffsfläche und mehr Sicherheitslücken. Besonders gefährlich ist der Kontext, in dem diese Server arbeiten. Sie laufen auf Entwicklerrechnern, auf denen sich API-Schlüssel, Zugangsdaten und geistiges Eigentum befinden. Sie werden von KI-Agenten gesteuert, die sich durch Prompt-Injection (und indirekte Prompt-Injection) manipulieren lassen. Und sie werden oft mit denselben Arten von Schwachstellen ausgeliefert, die Webanwendungen seit Jahrzehnten plagen.
Dieser Leitfaden beleuchtet kritische Sicherheitslücken, von denen MCP-Server heute betroffen sind, darunter Command-Injection, Path-Traversal und SQL-Injection. Dabei betrachten wir reale CVEs und Sicherheitsforschung. Sie erfahren nicht nur, wie diese Schwachstellen aussehen, sondern auch, wie Sie MCP-Server von Grund auf so entwickeln, dass sie ihnen standhalten.

Command-Injection: die am weitesten verbreitete MCP-Schwachstelle
Command-Injection ist eine der am häufigsten entdeckten Schwachstellen in MCP-Servern. Das Muster ist beunruhigend vertraut: Ein MCP-Server startet Systembefehle wie npm, git oder lsof und übernimmt nutzergesteuerte Eingaben ohne angemessene Bereinigung.
Man kann es aus der Perspektive einer Prompt-Injection betrachten: Ein feindseliger Prompt führt letztlich zur Ausführung von Befehlen aus der Ferne.
Die Schwachstelle verstehen
Betrachten wir einen scheinbar harmlosen MCP-Server, der Informationen zu npm-Paketen abruft:
server.tool(
"getNpmPackageInfo",
"Get information about an npm package",
{ packageName: z.string() },
async ({ packageName }) => {
const output = execSync(`npm view ${packageName}`, {
encoding: "utf-8",
});
return {
content: [{ type: "text", text: output }],
};
}
);Die Schwachstelle ist subtil, aber schwerwiegend. Der Parameter packageName wird durch String-Interpolation direkt in einen Shell-Befehl eingefügt. Wenn ein Nutzer seinen KI-Assistenten fragt: „Wann wurde react; touch /tmp/pwned zuletzt veröffentlicht?“, lautet der Befehl:
npm view react; touch /tmp/pwnedDas Semikolon beendet den ersten Befehl, und die Shell führt touch /tmp/pwned problemlos als separaten Befehl aus. Ein Angreifer, der den Prompt kontrolliert, kann nun beliebige Befehle auf dem Rechner des Entwicklers ausführen.
Prompts werden zur realen CVE-Bedrohung
Das ist keine Theorie. Bei mehreren MCP-Servern wurde eine Anfälligkeit für Command-Injection festgestellt:
Der GitHub Kanban MCP Server (GHSA-6jx8-rcjx-vmwf) bereinigte Nutzereingaben nicht und ermöglichte dadurch die Ausführung beliebiger Befehle über Git-Operationen
Der iOS Simulator MCP Server (GHSA-6f6r-m9pv-67jw) wies ähnliche Schwachstellen auf
Das Paket Create MCP Server STDIO enthielt fehlerhafte Tool-Definitionen, wodurch die Systemüberwachung für Injection-Angriffe anfällig war

Die Sicherheitslösung: Verwenden Sie die sichere Node.js-API execFile statt exec
Die Node.js-Funktion exec startet eine Shell und führt darin Befehle aus. Dadurch werden Shell-Metazeichen wie ;, | und $() gefährlich. Die Funktion execFile führt Dateien direkt aus, ohne die Shell-Interpretation:
// VULNERABLE: Uses shell interpolation
execSync(`npm view ${packageName}`);
// SECURE: Arguments passed as array, no shell
execFile('npm', ['view', packageName], (error, stdout) => {
// handle result
});Hier ist die sichere Implementierung:
import { execFile } from 'child_process';
server.tool(
"getNpmPackageInfo",
{ packageName: z.string() },
async ({ packageName }) => {
return new Promise((resolve, reject) => {
execFile('npm', ['view', packageName], { encoding: 'utf-8' },
(error, stdout) => {
if (error) reject(error);
resolve({
content: [{ type: "text", text: stdout }],
});
}
);
});
}
);Mit execFile wird die bösartige Eingabe react; touch /tmp/pwned als einzelnes Argument an npm view übergeben. Der Befehl schlägt kontrolliert fehl, anstatt beliebige Befehle auszuführen.
Weitere Maßnahmen gegen Command-Injection
Eingaben anhand von Allow-Listen validieren: Wenn Paketnamen erwartet werden, validieren Sie diese anhand der npm-Namenskonventionen
Befehle und Argumente voneinander trennen: Verwenden Sie sichere APIs, um Command-Injection zu verhindern, und bevorzugen Sie
execFilegegenüberexecShell-Argumente maskieren: Wenn sich die Shell-Ausführung nicht vermeiden lässt, verwenden Sie Bibliotheken wie
shell-quoteSprachspezifische APIs verwenden: Statt
npmzu starten, verwenden Sie direkt die npm-Registry-APIEingabelängen begrenzen: Ungewöhnlich lange Eingaben deuten oft auf Injection-Versuche hin

Path-Traversal: aus der Sandbox ausbrechen
MCP-Server stellen häufig Dateisystemoperationen bereit, etwa zum Lesen von Konfigurationsdateien, zum Zugriff auf Dokumentation oder zum Bereitstellen statischer Ressourcen. Path-Traversal-Schwachstellen entstehen, wenn Angreifer Dateipfade manipulieren, um auf Dateien außerhalb des vorgesehenen Verzeichnisses zuzugreifen.
Das Schwachstellenmuster im MCP-Server-Code
Ein häufiges Muster in MCP-Ressourcen-Handlern:
server.resource(
"pipeline-workflows",
new ResourceTemplate("pipeline-workflows://{name}", { list: undefined }),
async (uri, { name }) => {
const decodedName = decodeURIComponent(name);
let filePath = path.resolve(
process.cwd(),
'.github/workflows/',
`${decodedName}.yaml`
);
const fileContents = readFileSync(filePath, 'utf-8');
return {
contents: [{ uri: uri.href, text: fileContents }]
};
}
);Ein Angreifer kann pipeline-workflows://../../../../../../etc/passwd anfordern, und der Server liest bereitwillig /etc/passwd aus. Auf dem Rechner eines Entwicklers sind unter anderem folgende Ziele wertvoller:
~/.ssh/id_rsa(private SSH-Schlüssel)~/.aws/credentials(AWS-Zugriffsschlüssel).env-Dateien (Anwendungsgeheimnisse)~/.npmrc(npm-Authentifizierungstokens)
Fallstudie: Im Mastra-AI-Framework wurde eine Path-Traversal-Schwachstelle entdeckt
Das Paket @mastra/mcp-docs-server enthielt eine subtile Path-Traversal-Schwachstelle. Der Code enthielt zwar eine Sicherheitsprüfung, setzte die Ausführung aber auch dann fort, nachdem ein Traversal-Versuch erkannt worden war:
async function readMdxContent(docPath, queryKeywords) {
const fullPath = path.resolve(path.join(docsBaseDir, docPath));
// Security check exists...
if (!fullPath.startsWith(path.resolve(docsBaseDir))) {
logger.error(`Path traversal attempt detected`);
return { found: false };
}
// ...
}
execute: async (args) => {
const result = await readMdxContent(path, queryKeywords);
if (result.found) {
return { /* ... */ };
}
// VULNERABILITY: Executes even after traversal detection!
const directorySuggestions = await findNearestDirectory(path, availablePaths);
// ...
}Die Funktion findNearestDirectory arbeitete mit dem nicht validierten Pfad und gab Verzeichnisauflistungen außerhalb des vorgesehenen Bereichs preis.
Sichere Pfadbehandlung für MCP-Server-Ressourcen
Setzen Sie bei Dateioperationen auf mehrschichtige Sicherheitsmaßnahmen:
import path from 'path';
import { accessSync, readFileSync, constants } from 'fs';
function secureFilePath(baseDir, userPath) {
// Normalize and resolve the full path
const normalizedBase = path.resolve(baseDir);
const requestedPath = path.resolve(baseDir, userPath);
// Verify the path stays within bounds
if (!requestedPath.startsWith(normalizedBase + path.sep)) {
throw new Error('Path traversal detected');
}
// Verify the file exists and is readable
accessSync(requestedPath, constants.R_OK);
return requestedPath;
}
server.resource(
"docs",
new ResourceTemplate("docs://{filename}", { list: undefined }),
async (uri, { filename }) => {
const baseDir = path.resolve(process.cwd(), 'docs');
// Halt execution immediately on invalid paths
const safePath = secureFilePath(baseDir, filename);
const contents = readFileSync(safePath, 'utf-8');
return {
contents: [{ uri: uri.href, text: contents }]
};
}
);Checkliste zur Vermeidung von Path-Traversal
Pfade immer auflösen: Verwenden Sie
path.resolve(), um relative in absolute Pfade umzuwandelnErgebnis validieren: Stellen Sie sicher, dass aufgelöste Pfade mit dem vorgesehenen Basisverzeichnis beginnen
Sofort ablehnen: Setzen Sie die Verarbeitung niemals fort, nachdem ein Traversal-Versuch erkannt wurde
Allow-Listen verwenden: Beschränken Sie den Zugriff nach Möglichkeit auf ausdrücklich freigegebene Dateien
Nutzergesteuerte Dateierweiterungen vermeiden: Lassen Sie Nutzer keine Dateierweiterungen festlegen

SQL-Injection: die Illusion von „schreibgeschützt“
Da MCP-Server zunehmend Datenbankverbindungen bereitstellen, sind SQL-Injection-Schwachstellen zu einem kritischen Problem geworden. Besonders tückisch ist, dass viele MCP-Datenbankserver einen fehlerhaften „schreibgeschützten“ Modus implementieren, der ein falsches Sicherheitsgefühl vermittelt.
Die naive Prüfung auf schreibgeschützten Zugriff
Mehrere MCP-Datenbankserver versuchen, den schreibgeschützten Zugriff durch eine Prüfung darauf durchzusetzen, ob Abfragen mit SELECT beginnen:
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const query = request.params.arguments?.query;
if (!query.trim().toLowerCase().startsWith("select")) {
throw new Error("Only SELECT queries are allowed");
}
const result = await client.query(query);
return { content: [{ type: "text", text: JSON.stringify(result) }] };
});Dieser Ansatz versagt angesichts der zahlreichen integrierten Funktionen von PostgreSQL auf ganzer Linie.
So lassen sich unsichere Einschränkungen für schreibgeschützten MCP-Server-Zugriff umgehen
PostgreSQL stellt administrative Funktionen bereit, die innerhalb von SELECT-Anweisungen aufgerufen werden können:
-- Denial of Service: Terminate database connections
SELECT pg_terminate_backend(pid) FROM pg_stat_activity
WHERE usename != 'admin';
-- Long-running resource exhaustion
SELECT pg_sleep(300);
-- Information disclosure: Expose all running queries
SELECT pid, usename, query FROM pg_stat_activity;
-- Configuration extraction
SELECT name, setting FROM pg_settings WHERE name LIKE '%password%';
-- Force checkpoint (performance disruption)
SELECT pg_start_backup('malicious_backup', true);
Fallstudie: Reale MCP-Schwachstellen, die über SQL-Injection ausgenutzt wurden
Beim Xata's MCP Server, dem keine offizielle CVE zugewiesen wurde, ließ sich die schreibgeschützte Transaktion umgehen:
COMMIT; INSERT INTO users (name) VALUES ('attacker');Durch Beenden der schreibgeschützten Transaktion mit COMMIT konnten Angreifer Schreiboperationen ausführen.
Beim ExecuteAutomation Database Server (CVE-2025-59333) ermöglichten ähnlich fehlerhafte Zugriffskontrollen das Verketten von Abfragen:
SELECT * FROM users; DROP TABLE users; --Wie lässt sich ein sicherer Datenbankzugriff für MCP-Server implementieren?
Ausführung einzelner Abfragen erzwingen:
// Force prepared statement (prevents multi-query)
const result = await client.query({
name: "single-query",
text: userQuery,
values: [],
});Berechtigungen auf Datenbankebene verwenden:
-- Create restricted user
CREATE USER mcp_readonly WITH PASSWORD 'secure_password';
-- Grant only SELECT on specific tables
GRANT SELECT ON public.users TO mcp_readonly;
GRANT SELECT ON public.products TO mcp_readonly;
-- Revoke dangerous function access
REVOKE EXECUTE ON ALL FUNCTIONS IN SCHEMA pg_catalog FROM mcp_readonly;Abfragen per Allow-Liste zulassen:
const ALLOWED_QUERIES = {
"get_users": "SELECT id, name FROM users WHERE active = $1",
"get_products": "SELECT id, name, price FROM products WHERE category = $1"
};
server.tool("query_database", { queryName: z.string(), params: z.array(z.any()) },
async ({ queryName, params }) => {
const query = ALLOWED_QUERIES[queryName];
if (!query) throw new Error("Query not permitted");
return await client.query(query, params);
}
);Gefährliche Funktionen blockieren:
const DANGEROUS_PATTERNS = [
/pg_\w+\(/i, // PostgreSQL system functions
/\bcopy\b/i, // COPY command
/\binto\s+outfile/i, // File operations
/\bload_file\b/i, // File loading
/\bexecute\b/i, // Dynamic execution
/\bsleep\b/i, // Sleep-based DoS
];
function validateQuery(query) {
for (const pattern of DANGEROUS_PATTERNS) {
if (pattern.test(query)) {
throw new Error("Query contains prohibited patterns");
}
}
}MCP Resources für strukturierten Zugriff nutzen:
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
const resourceUrl = new URL(request.params.uri);
const [schema, tableName] = resourceUrl.pathname.split('/').filter(Boolean);
// Validate against allowlist
if (!ALLOWED_TABLES.includes(tableName)) {
throw new Error('Table not permitted');
}
// Use parameterized query
const result = await client.query(
'SELECT * FROM information_schema.columns WHERE table_name = $1',
[tableName]
);
return { contents: [{ uri: request.params.uri, text: JSON.stringify(result) }] };
});
Drittanbieter-Abhängigkeiten absichern
MCP-Server sind bei Datenbanktreibern, HTTP-Clients und Hilfsfunktionen auf npm-Pakete angewiesen. Jede Abhängigkeit stellt ein potenzielles Supply-Chain-Risiko dar:
Verwundbare Abhängigkeiten: Bekannte CVEs in Paketen wie
pg,axiosoderlodashBösartige Pakete: Typosquatting-Angriffe auf Entwickler von MCP-Servern
Transitive Schwachstellen: Sicherheitslücken in Abhängigkeiten von Abhängigkeiten
Maßnahmen zur Risikominderung
Kontinuierlich scannen: Integrieren Sie Snyk oder vergleichbare Tools in Ihre CI/CD-Pipeline, um verwundbare Abhängigkeiten vor der Bereitstellung zu erkennen
Abhängigkeitsversionen fixieren: Verwenden Sie Lockfiles (
package-lock.json) und überprüfen Sie die IntegritätRegelmäßig aktualisieren: Behalten Sie Sicherheitshinweise im Blick und spielen Sie Patches zeitnah ein
Abhängigkeiten minimieren: Jedes Paket vergrößert die Angriffsfläche. Prüfen Sie, ob Sie das Paket in Ihrem MCP-Server wirklich benötigen.
Vor der Nutzung prüfen: Sehen Sie sich die Paketbewertungen zur Wartungsqualität in der Snyk Security Database an
Empfohlene Maßnahmen: sichere MCP-Server entwickeln

Für Entwickler von MCP-Servern
Alle Eingaben validieren: Vertrauen Sie niemals Daten aus von LLMs generierten Tool-Aufrufen
Sichere APIs verwenden: Bevorzugen Sie
execFilegegenüberexecund parametrisierte Abfragen gegenüber String-InterpolationMehrschichtige Sicherheitsmaßnahmen umsetzen: Mehrere Validierungsebenen statt einzelner Prüfungen
SAST-Tools integrieren: Nutzen Sie Snyk Code oder ähnliche Tools, um Schwachstellen bereits während der Entwicklung zu erkennen
Das Prinzip der geringsten Berechtigung anwenden: Beschränken Sie Datenbankbenutzer, Dateisystemzugriff und Netzwerkberechtigungen auf das notwendige Minimum
Sicherheitsmodell dokumentieren: Legen Sie Vertrauensgrenzen und Annahmen klar offen
Für Nutzer von MCP-Servern
Vor der Installation prüfen: Überprüfen Sie den Quellcode, insbesondere die Tool-Handler
Verhalten überwachen: Achten Sie auf unerwartete Dateizugriffe, Netzwerkanfragen oder Befehlsausführungen
Umgebungen isolieren: Führen Sie MCP-Server in Sandbox-Umgebungen aus
Aktuell halten: Spielen Sie Sicherheitspatches zeitnah ein
Schwachstellen melden: Gehen Sie verantwortungsvoll mit der Offenlegung um, wenn Sie Probleme entdecken
Für Unternehmen
MCP-Richtlinien festlegen: Definieren Sie zugelassene Server und Sicherheitsanforderungen
Scans implementieren: Scannen Sie den MCP-Server-Code vor der Bereitstellung automatisch
Entwickler schulen: Vermitteln Sie Teams sichere Entwicklungsmuster für MCP
Überwachen und auditieren: Protokollieren Sie die Aktivitäten von MCP-Servern für Sicherheitsprüfungen
Der Weg nach vorn
Das Model Context Protocol ist ein leistungsstarkes Konzept zur Erweiterung von KI-Funktionen. Doch mit größerer Leistungsfähigkeit wächst auch die Verantwortung. Die von uns betrachteten Schwachstellen – Command-Injection, Path-Traversal und SQL-Injection – sind nicht neu. Es sind dieselben Fehler, die Webanwendungen seit Jahrzehnten plagen und nun in einem neuen Kontext mit potenziell größeren Auswirkungen auftreten.
Die Ironie ist kaum zu übersehen: Im Bestreben, KI leistungsfähiger zu machen, haben wir sie mit Systemen verbunden, die auf denselben fragilen Grundlagen beruhen, die wir seit Jahren vergeblich abzusichern versuchen. Ein LLM mit Zugriff auf einen verwundbaren MCP-Server wird zum unwissentlichen Angriffsvektor, dessen Intelligenz durch einfache String-Manipulation zur Waffe wird.

Für den weiteren Weg müssen wir bei der Entwicklung von MCP-Servern dieselbe Sorgfalt walten lassen wie bei jedem sicherheitskritischen Code. Validieren Sie Eingaben. Verwenden Sie sichere APIs. Setzen Sie auf mehrschichtige Sicherheitsmaßnahmen. Suchen Sie nach Schwachstellen. Und denken Sie daran: „Schreibgeschützt“ ist oft eine gefährliche Illusion.
Die Tools für die Entwicklung sicherer MCP-Server gibt es bereits. Die Frage ist, ob wir sie nutzen, bevor die nächste Welle von Schwachstellen für Schlagzeilen sorgt.
Möchten Sie mehr über neue Angriffswege auf MCP-Server erfahren – von Tool-Poisoning bis hin zu Shadowing und Toxic Flows? Analysieren Sie reale Vorfälle und erfahren Sie im Securing The MCP Servers Ecosystem eBook., wie Sie sich mit praxisnahen, auf Datenflüssen basierenden Strategien vor Angriffen schützen.
Treten Sie bei Fetch the Flag 2026 an!
Stellen Sie Ihr Können unter Beweis, lösen Sie die Herausforderungen und erobern Sie die Bestenliste. Seien Sie vom 12. Februar, 12:00 Uhr ET, bis zum 13. Februar, 12:00 Uhr ET beim ultimativen CTF-Event dabei.