Considérez un serveur MCP comme du code tiers qui agit avec vos identifiants, et auditez-le avant que l'agent puisse l'appeler. Les vérifications ci-dessous s'appuient sur la spécification d'autorisation MCP (révision 2025-06-18) et sur les bonnes pratiques de sécurité MCP (révision 2025-11-25). Les révisions diffèrent : consultez la spécification en vigueur avant de vous appuyer sur une exigence.
L'autorisation est facultative, vérifiez donc qu'elle existe
Les serveurs sur un transport HTTP devraient suivre la spécification d'autorisation. Ceux sur STDIO ne le devraient pas et récupèrent plutôt leurs identifiants dans l'environnement. Pour un serveur STDIO local, listez les variables d'environnement que la configuration de votre client transmet au processus et demandez-vous si chacune est réellement nécessaire.
Pour un serveur HTTP, envoyez une requête non authentifiée :
curl -i https://mcp.example.com/mcp
Vous devriez obtenir un 401 Unauthorized avec un en-tête WWW-Authenticate indiquant l'URL des métadonnées de la ressource. Récupérez ce document et vérifiez qu'il contient authorization_servers avec au moins une entrée. Si le serveur répond avec des données, arrêtez-vous là.
Confirmez ensuite les points que la spécification déclare obligatoires :
- Le client envoie
Authorization: Bearer <access-token>à chaque requête HTTP, et le jeton n'apparaît jamais dans la query string de l'URI. - Les endpoints du serveur d'autorisation utilisent HTTPS, et les URI de redirection sont en localhost ou en HTTPS.
- Le serveur d'autorisation compare les URI de redirection de façon exacte avec des valeurs préenregistrées.
- Les clients implémentent PKCE.
Les clients devraient aussi vérifier le paramètre state, et les serveurs d'autorisation devraient émettre des jetons d'accès de courte durée.
Audience et scope du jeton
Le client doit envoyer le paramètre resource (RFC 8707) dans les requêtes d'autorisation comme dans les requêtes de jeton, et le serveur doit valider que chaque jeton a été émis spécifiquement pour lui. Sinon, des jetons émis pour d'autres services fonctionnent contre lui.
Le token passthrough est pire : le serveur accepte un jeton qui ne lui était pas destiné et le transmet tel quel en aval. Des contrôles comme le rate limiting et la supervision peuvent dépendre de l'audience du jeton, et les journaux en aval risquent d'attribuer les requêtes à la mauvaise identité, ce qui complique l'investigation.
Pour tester la liaison à l'audience, utilisez un client enregistré afin de demander un jeton pour une autre ressource auprès du token_endpoint indiqué dans les métadonnées du serveur d'autorisation. Rejouez-le ensuite contre le serveur MCP :
curl -i -H "Authorization: Bearer $OTHER_TOKEN" https://mcp.example.com/mcp
Attendez-vous à un 401. Un jeton valide mais dépourvu des permissions nécessaires devrait recevoir un 403. Si le serveur d'autorisation refuse d'émettre un tel jeton, demandez à l'éditeur comment le serveur MCP vérifie l'audience.
Demandez aussi où le serveur stocke les jetons. Les clients publics doivent faire l'objet d'une rotation des refresh tokens, et les jetons mis en cache ou journalisés sur le serveur constituent une cible de vol.
Serveurs proxy et consentement
Si le serveur MCP sert de façade à une API tierce avec un unique client ID statique, lisez la section des bonnes pratiques consacrée au confused deputy. L'attaque requiert un client ID statique, l'enregistrement dynamique de clients, un cookie de consentement du serveur d'autorisation tiers et l'absence de consentement par client au niveau du proxy. Ce dernier point relève de vous : le proxy devrait tenir un registre des valeurs client_id approuvées par utilisateur et afficher le nom du client, les scopes et l'URI de redirection sur sa propre page de consentement, laquelle doit interdire l'intégration en iframe avec frame-ancestors ou X-Frame-Options: DENY.
Mettre les outils en allowlist, puis les réduire
Demandez au serveur la liste de ses outils et comparez-la avec ce que la tâche exige. Tout ce qui dépasse relève de la fonctionnalité excessive au sens de OWASP LLM06:2025. Supprimez-le, ou empêchez l'agent de l'appeler.
Enregistrez la liste comme référence et comparez-la après chaque mise à jour du serveur, afin qu'un outil ajouté lors d'une mise à jour soit examiné avant que l'agent puisse l'appeler. Vérifiez ensuite chacun des outils restants :
- Est-il ouvert, comme « exécuter une commande shell » ou « récupérer une URL » ? Remplacez-le par un outil étroit. L'exemple d'OWASP est un outil d'écriture de fichiers à la place d'un accès shell.
- Quelle identité utilise-t-il en aval ? Un outil qui lit des données doit se connecter avec
SELECTuniquement, pas avecUPDATE,INSERTetDELETE. - Agit-il pour un seul utilisateur ? Il doit alors s'authentifier via OAuth avec le scope minimal, et non via un compte générique à privilèges.
Appliquez les limites dans le système en aval. OWASP parle de complete mediation : ne comptez pas sur le modèle pour décider si une action est autorisée.
Validation humaine pour les actions d'écriture
Les hallucinations et les prompt injections déclenchent fréquemment des actions dommageables, donc les actions à fort impact exigent un humain dans la boucle. OWASP décrit un assistant de messagerie qui résume les messages entrants. Un e-mail piégé le pousse à parcourir la boîte de réception à la recherche d'informations sensibles et à les transférer à l'attaquant.
Une extension en lecture seule, un scope OAuth en lecture seule ou la relecture manuelle de chaque e-mail rédigé avant envoi auraient chacun coupé court à cette attaque. Superposez ces mesures partout où c'est possible.
Tout ce qui supprime, envoie ou publie doit figurer sur la liste des actions soumises à approbation. Placez l'approbation dans l'extension ou dans le système en aval. La journalisation et le rate limiting n'empêchent pas l'autonomie excessive, mais ils facilitent le repérage des actions indésirables.
Si le client s'exécute côté serveur
Pendant la découverte OAuth, le client récupère des URL fournies par le serveur, notamment resource_metadata, authorization_servers et token_endpoint. Un serveur malveillant peut les faire pointer vers des adresses internes ou vers l'endpoint de métadonnées cloud à l'adresse 169.254.169.254.
Exigez HTTPS en production, bloquez les plages privées et réservées, et validez les cibles de redirection ou désactivez les redirections automatiques. N'écrivez pas la validation des adresses IP à la main, car les astuces en octal, en hexadécimal et en IPv6 mappé sur IPv4 mettent en échec les parseurs maison. Envisagez un proxy de sortie tel que Smokescreen.
Testez ensuite. Montez un serveur de test hostile qui renvoie un 401 dont l'en-tête WWW-Authenticate contient une URL resource_metadata pointant vers http://169.254.169.254/, puis recommencez avec une URL qui redirige vers une adresse interne. Le client doit refuser les deux, et un listener placé sur la cible interne ne doit voir aucune requête.
Par où commencer
- Listez tous les serveurs MCP utilisés par vos agents, avec leur transport et leur exploitant. Supprimez ceux dont vous ne pouvez pas justifier la présence.
- Lancez
curl -icontre chaque serveur HTTP et confirmez le401avec un en-têteWWW-Authenticate. Rejouez ensuite un jeton émis pour une autre ressource. - Pour les serveurs proxy avec un client ID statique, examinez le flux de consentement : registre par client, contenu de la page de consentement, protection contre l'intégration en frame.
- Établissez la référence de la liste d'outils de chaque serveur, réduisez-la à ce que la tâche exige, donnez à chaque outil l'identité au moindre privilège et exigez une validation humaine pour les outils d'écriture et de suppression.
- Pour les clients côté serveur, exécutez le test SSRF avec un serveur de test hostile.
- Répétez les étapes 2 à 5 chaque fois qu'un serveur est mis à jour, ajoute un outil ou modifie ses scopes.
Pour une revue externe, découvrez notre service de conseil. Notre service de tests d'intrusion peut exécuter les vérifications des jetons et du consentement sur votre configuration.
