Le WordPress d'aujourd'hui, décodé pour les développeurs

Sécurité

Un serveur MCP mal isolé exposait un CRM associatif en écriture

Un outil MCP mal scopé donnait à n'importe quel agent connecté la capacité de modifier des fiches d'un CRM associatif. Diagnostic de l'erreur de conception et correctif par séparation des portées lecture et écriture.

Par Clément Hadrot • 22 janvier 2025 • 5 min de lecture • Aucun commentaire
Un serveur MCP mal isolé exposait un CRM associatif en écriture

list_tools renvoyait une seule entrée pour l’intégralité du CRM associatif : crm_query, un outil unique capable à la fois de lire une fiche adhérent et de la modifier, sans distinction de portée. C’est ce que révélait l’inspection du serveur MCP (Model Context Protocol) mis en place quelques semaines plus tôt pour connecter un assistant conversationnel interne au CRM d’un réseau associatif régional, chargé de gérer les adhésions et les dons de plusieurs structures locales.

Le serveur MCP en question exposait une interface unifiée à tout agent capable de s’y connecter, dans l’idée de simplifier les requêtes courantes formulées par les bénévoles : retrouver la fiche d’un adhérent, vérifier le statut d’une cotisation, consulter l’historique des dons. Rien dans le projet initial ne prévoyait qu’un agent puisse également modifier ces données, mais la conception de l’outil exposé ne distinguait pas ces deux usages.

Symptôme : une modification de fiche déclenchée par une requête de consultation

L’incident a été découvert lorsqu’un bénévole, en demandant simplement à l’assistant conversationnel de « vérifier si Madame X a bien payé sa cotisation », s’est retrouvé face à une fiche adhérent dont le statut de cotisation avait été modifié par l’agent lui-même, qui avait interprété une ambiguïté dans l’échange comme une instruction de mise à jour plutôt que de simple consultation.

Cette modification non désirée, quoique corrigée rapidement une fois repérée, a mis en lumière un défaut de conception bien plus large : rien dans l’architecture du serveur MCP n’empêchait techniquement un agent, correctement instruit ou non, d’écrire dans le CRM à chaque interaction, y compris pour des demandes de simple lecture.

Diagnostic : un outil unique masquant deux niveaux de droits distincts

L’examen de la définition de l’outil exposé par le serveur MCP a confirmé le problème structurel :

L'essentiel à retenir : Repérer un outil MCP unique couvrant lecture et écriture ; Comprendre le risque d'une portée trop large accordée à un agent ; Séparer les serveurs ou les outils par niveau de droit
{
  "name": "crm_query",
  "description": "Interroge ou met à jour une fiche du CRM associatif",
  "inputSchema": {
    "type": "object",
    "properties": {
      "adherent_id": { "type": "string" },
      "action": { "type": "string", "enum": ["lire", "ecrire"] },
      "champs": { "type": "object" }
    }
  }
}

Un seul outil, une seule portée d’autorisation côté serveur MCP, indépendamment de la valeur du paramètre action transmis par l’agent. Aucune distinction de droit n’existait entre les deux usages au niveau du contrôle d’accès : c’était entièrement au modèle de langage de décider, à chaque appel, quelle action réaliser, sans garde-fou structurel l’en empêchant si nécessaire.

Correctif : deux outils distincts, deux portées d’autorisation séparées

La correction a consisté à scinder l’outil unique en deux outils MCP indépendants, avec des portées d’autorisation distinctes côté serveur : crm_lire_fiche, accessible à tout agent connecté avec un jeton de lecture seule, et crm_modifier_fiche, accessible uniquement aux agents disposant d’un jeton explicitement habilité à l’écriture, distribué avec parcimonie.

  1. Créer deux définitions d’outils séparées plutôt qu’un paramètre d’action au sein d’un outil unique.
  2. Associer chaque outil à une portée d’autorisation vérifiée côté serveur MCP, indépendamment de ce que l’agent demande.
  3. Réserver le jeton donnant accès à l’outil d’écriture aux cas d’usage explicitement validés, comme la mise à jour groupée des cotisations en fin d’année.

Prévention : traiter chaque outil MCP comme une capacité, pas comme une fonction

La leçon centrale de cet incident dépasse le cas précis du CRM associatif : un outil MCP ne devrait jamais réunir sous un intitulé unique des capacités de niveaux de risque différents. La conception d’un serveur MCP gagne à s’inspirer du principe de moindre privilège déjà appliqué aux rôles et capacités WordPress, en distinguant systématiquement les outils de lecture, sans risque pour l’intégrité des données, des outils d’écriture, qui exigent une portée d’autorisation restreinte et une justification explicite de leur usage.

  • Documenter, pour chaque outil MCP exposé, le niveau de risque associé à son exécution.
  • Tester systématiquement qu’un agent disposant uniquement du jeton de lecture ne peut techniquement pas invoquer l’outil d’écriture.
  • Journaliser chaque appel à un outil d’écriture avec l’identité de l’agent et le contexte de la demande d’origine.

Un serveur MCP n’est pas plus sûr qu’une API REST mal scopée : la nouveauté du protocole ne dispense d’aucune des disciplines de contrôle d’accès déjà connues, elle les rend simplement plus faciles à oublier tant tout paraît nouveau.

En résumé

Ce cas illustre un piège spécifique à l’adoption rapide du Model Context Protocol : la facilité avec laquelle un outil unique peut recouvrir plusieurs niveaux de droits distincts, sans que cette confusion ne saute immédiatement aux yeux au moment de la conception. Séparer explicitement les outils de lecture et d’écriture, avec des portées d’autorisation vérifiées côté serveur, referme cette porte ouverte sans nécessiter de renoncer aux gains de productivité qu’apporte la connexion d’un agent à un CRM.

Partager :

À propos de l'auteur

Clément Hadrot

Développeur WordPress, passionné par Elementor, le FSE et l’automatisation par IA.

Voir tous ses articles

Dans la même veine

À lire aussi