Skip to content

Repository files navigation

MCP TrustMap

CI

Aperçu MCP TrustMap

MCP TrustMap est une application web d’audit de configurations MCP (Model Context Protocol). Elle transforme un inventaire de serveurs difficile à relire en une posture de sécurité claire : score global, risques prioritaires, explication de l’impact et correctifs directement applicables.

Modules produit

  • TrustMap Discover construit la cartographie des serveurs, sources, transports et composants découverts par le collecteur local ou par import.
  • TrustMap Agent exécute cette découverte de façon périodique sur les postes et environnements enrôlés. Il transmet uniquement un graphe d’actifs assaini, avec des jetons d’enrôlement hachés et révocables.
  • AI Asset Graph relie agents, clients IA, serveurs MCP, outils observés, transports, composants, responsables et contrôles pour rendre visibles les chemins de confiance et les concentrations de risque.
  • TrustMap Audit applique le référentiel de sécurité, priorise les écarts, fournit les correctifs, gère les exceptions et conserve l’historique agrégé.
  • TrustMap CI simule une politique sur l’inventaire courant et génère la commande ainsi qu’un workflow GitHub Actions multi-environnements, avec chemins, seuils, SARIF, CycloneDX, OSV et provenance configurables par profil.
  • TrustMap Enterprise mesure la couverture des propriétaires et des preuves, présente la posture par équipe, synchronise le registre chiffré par organisation, applique les rôles et pilote les approbations critiques.
  • TrustMap Runtime fournit un point de décision avant l’appel d’un outil : autorisation, blocage ou validation humaine. Les politiques multi-tenant sont appliquées côté serveur et chaque décision alimente un journal d’exécution.
  • TrustMap Runtime Gateway protège les serveurs MCP stdio de Claude Desktop et des autres clients : l’appel n’atteint le serveur qu’après une décision Runtime, avec un comportement fermé par défaut en cas de panne.

Les vues Enterprise reflètent uniquement les données réellement chargées. MCP TrustMap fournit sa propre identité : inscription, vérification de l’adresse, connexion, récupération du mot de passe et MFA TOTP. Les autorisations et l’appartenance à l’organisation active sont recalculées côté serveur à chaque requête.

Le moteur actuel réalise une analyse statique locale des configurations. Il ne remplace pas un test d’intrusion, une revue des permissions réellement accordées ni une surveillance d’exécution.

Fonctionnalités

  • import d’un fichier JSON ou collage direct d’une configuration ;
  • collecteur local multiplateforme pour inventorier les configurations connues ;
  • agent périodique Windows, macOS et Linux avec enrôlement révocable ;
  • graphe persistant des actifs IA et de leurs relations de confiance ;
  • découverte progressive des outils à partir des décisions Runtime ;
  • politiques Runtime en modes observation et application ;
  • blocage des appels critiques, prévention de l’exfiltration et validation humaine des actions sensibles ;
  • API de décision Runtime utilisable par un sidecar, un proxy ou un agent ;
  • passerelle locale stdio qui applique réellement ces décisions avant tools/call, sans transmettre les arguments ou résultats au service central ;
  • journal des décisions isolé par organisation ;
  • découverte de Claude Desktop, Cursor, VS Code, Windsurf et des workspaces ;
  • masquage des secrets avant la création de l’inventaire ;
  • vérification MCP passive et optionnelle des endpoints HTTPS ;
  • affichage de la version négociée et des capacités annoncées ;
  • inventaire des composants npm, PyPI, OCI et exécutables locaux ;
  • détection des tags d’images mutables et dépendances non verrouillées ;
  • résolution des dépendances transitives depuis les lockfiles npm, pnpm, Yarn, uv et Poetry ;
  • découverte bornée des packages npm/pnpm/Yarn d’un monorepo ;
  • vérification cryptographique des signatures npm et des attestations SLSA avec Sigstore ;
  • vérification des signatures Cosign et des attestations SLSA d’images OCI verrouillées par digest, avec plusieurs politiques sélectionnées par préfixe ;
  • génération hors ligne de politiques d’admission Kubernetes Sigstore à partir des mêmes identités OCI ;
  • validation CI déterministe des bundles Kubernetes générés ;
  • contrôle CI des configurations avec seuil de sévérité et export SARIF ;
  • recherche optionnelle des vulnérabilités connues via OSV.dev ;
  • prise en charge des objets JSON mcpServers utilisés par Claude Desktop, Claude Code, Cursor et VS Code, ainsi que des tables TOML mcp_servers de Codex ;
  • détection locale des secrets présents en clair ;
  • contrôle du chiffrement des transports distants ;
  • détection des shells intermédiaires et options dangereuses ;
  • signalement des dépendances non verrouillées ;
  • contrôle des chemins de fichiers trop larges ;
  • vérification du principe de moindre privilège ;
  • score de sécurité global et par serveur ;
  • priorisation par criticité ;
  • remédiations expliquées avec extraits de configuration copiables ;
  • comptes autonomes avec vérification de l’adresse, récupération du mot de passe et authentification multifacteur TOTP avec codes de secours ;
  • organisations clientes isolées et invitations par courriel ;
  • rôles Admin, Auditor et Reader appliqués côté serveur ;
  • historique persistant des scores et écarts, comparé audit par audit ;
  • export CSV chronologique de la posture et des écarts agrégés ;
  • exceptions de risque motivées, attribuées, datées et révocables ;
  • export de rapports PDF, JSON, SARIF et d’un SBOM CycloneDX 1.7 ;
  • vues dédiées aux serveurs, règles et audits ;
  • interface responsive et accessible au clavier.

Confidentialité

L’analyse statique est effectuée dans le navigateur. La découverte est effectuée par un collecteur local explicite :

  • aucune configuration importée n’est envoyée à un service distant ;
  • une synchronisation manuelle ou TrustMap Agent envoie uniquement les noms d’actifs, catégories, scores, preuves minimales et relations du graphe ;
  • les chemins locaux, arguments de commande, extraits de configuration, URL, en-têtes et valeurs sensibles sont exclus du graphe central ;
  • les valeurs sensibles détectées ne sont jamais affichées ;
  • aucun secret n’est enregistré dans le stockage du navigateur ;
  • une copie locale du registre d’exceptions reste dans le navigateur et le registre partagé stocke uniquement des enveloppes chiffrées dans D1 ;
  • l’historique distant conserve uniquement des compteurs agrégés par règle, associés à un identifiant utilisateur pseudonymisé ;
  • aucun nom de serveur, chemin, configuration, extrait de correction ou secret n’est envoyé avec cet historique ;
  • le rapport PDF est composé et téléchargé localement, sans envoi du contenu ;
  • les secrets concrets sont remplacés par ${REDACTED} avant l’écriture de l’inventaire ;
  • le collecteur ne lance jamais les commandes des serveurs stdio ;
  • les lockfiles sont lus comme des données : npm, pnpm, Yarn, uv et Poetry ne sont jamais exécutés ;
  • le probe n’envoie jamais les en-têtes d’authentification trouvés dans les configurations ;
  • le probe ne contacte que les endpoints HTTPS et n’appelle aucun outil MCP ;
  • l’analyse OSV est désactivée par défaut ; avec --osv, seuls les PURL des composants ayant une version exacte sont envoyés à api.osv.dev ;
  • aucun chemin, configuration, en-tête ou secret n’est envoyé à OSV ;
  • la vérification --provenance est désactivée par défaut ; elle consulte le registre npm public avec le nom et la version du paquet, puis rapproche le digest public de celui du lockfile ;
  • les attestations SLSA sont validées localement avec les racines de confiance et journaux de transparence Sigstore ;
  • la vérification OCI lance uniquement cosign verify, cosign verify-attestation ou gh attestation verify avec une liste d’arguments fixe ; aucun shell, conteneur ou serveur MCP n’est exécuté ;
  • le générateur Kubernetes écrit uniquement des manifestes et valeurs Helm : il ne lance ni kubectl ni Helm et ne contacte aucun cluster ;
  • les données de démonstration peuvent être restaurées à tout moment.

Même avec ces protections, évitez de partager ou de committer une configuration contenant de vrais secrets. Si une valeur sensible a déjà été exposée, révoquez et renouvelez-la.

Démarrage rapide

Prérequis

  • Node.js 22.13 ou supérieur ;
  • npm ;
  • Git.

Installation

git clone https://github.com/mawoole/MCPTrustMap.git
cd MCPTrustMap
npm ci
Copy-Item .env.example .dev.vars
npx wrangler d1 migrations apply DB --local --config wrangler.example.jsonc
npm run dev

Ouvrez ensuite http://localhost:3000. Le fichier .dev.vars est ignoré par Git. Pour recevoir réellement les courriels en local, renseignez RESEND_API_KEY et TRUSTMAP_EMAIL_FROM. Sans fournisseur d’e-mail, TRUSTMAP_DEV_EMAIL_LOG=true écrit les liens de vérification, d’invitation et de récupération dans la console locale.

Premier démarrage

  1. Créez un compte dans Inscription puis vérifiez son adresse.
  2. Créez l’organisation du premier client ; son créateur devient Admin.
  3. Ouvrez Paramètres pour inviter les autres membres et leur attribuer Admin, Auditor ou Reader.
  4. Activez le MFA dans Paramètres → Sécurité du compte, scannez le QR code et conservez les codes de secours hors ligne.

Vérification de production

npm run build

Utilisation

  1. Ouvrez Importer.
  2. Choisissez un fichier JSON ou collez une configuration.
  3. Cliquez sur Analyser la configuration.
  4. Consultez le score et les remédiations prioritaires.
  5. Ouvrez un serveur pour voir l’impact et copier le correctif recommandé.

Exceptions de risque

Une correction qui ne peut pas être appliquée immédiatement peut être placée sous exception depuis le détail de l’écart. MCP TrustMap exige :

  • un motif explicite et, idéalement, une référence de suivi ;
  • un responsable identifié ;
  • une date d’expiration future, limitée à 366 jours.

Une exception critique reste en attente et ne masque jamais le constat avant deux approbations attribuées à deux auditeurs distincts du demandeur. Une même identité ne peut pas voter deux fois ; le demandeur ne peut pas s’auto-approuver et seul un administrateur peut rejeter la demande.

Une exception active retire temporairement l’écart des remédiations prioritaires mais ne réduit pas le score brut : le risque reste visible. À l’échéance ou après révocation, l’écart redevient automatiquement prioritaire.

Le rapport JSON 1.1 inclut les exceptions actives, en attente, rejetées, expirées et révoquées. L’export SARIF conserve le résultat et ajoute une suppression external/accepted documentée pour les seules exceptions actives.

Historique des audits

Chaque import, découverte locale ou relance d’audit ajoute un point de posture dans la base D1 du site. L’historique affiche les 60 points les plus récents et compare le score, le total d’écarts, les corrections résolues et les nouveaux constats depuis le point précédent.

La synchronisation ne transmet que le score, le nombre de serveurs, les compteurs de sévérité et le nombre de constats par code de règle. L’adresse de l’utilisateur authentifié sert uniquement à calculer côté serveur une clé pseudonymisée ; elle n’est pas stockée dans la table. L’utilisateur peut effacer définitivement son historique depuis cette vue.

Rapport PDF

Le menu Exporter > Rapport PDF produit localement un document paginé prêt à partager avec les équipes sécurité et exploitation. Il contient :

  • la synthèse de posture et le score brut ;
  • l’inventaire des serveurs et leurs écarts ;
  • les risques classés par criticité avec leur correction concrète ;
  • les extraits de configuration corrigée ;
  • les exceptions actives, expirées ou révoquées ;
  • la méthodologie, les limites et la pagination.

La bibliothèque PDF est chargée uniquement au moment de l’export afin de ne pas alourdir le chargement initial de l’application.

Exemple minimal :

{
  "mcpServers": {
    "filesystem-project": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-filesystem@1.0.0",
        "/workspace/project"
      ]
    },
    "internal-api": {
      "url": "https://mcp.internal.example/v1",
      "headers": {
        "Authorization": "Bearer ${MCP_ACCESS_TOKEN}"
      }
    }
  }
}

Découverte locale

Depuis le dossier du projet, créez un inventaire assaini :

npm run collect

Le fichier mcp-inventory.json est produit dans le dossier courant. Ouvrez ensuite Découvrir dans l’application et importez ce fichier. L’inventaire local est ignoré par Git afin d’éviter de publier des métadonnées d’infrastructure. Le collecteur détecte automatiquement la configuration Codex ~/.codex/config.toml, Claude Desktop classique ou Microsoft Store, ainsi que les portées utilisateur et locales de Claude Code dans ~/.claude.json.

Pour vérifier également les endpoints MCP distants :

npm run collect -- --probe

Le probe réalise uniquement la négociation MCP initialize, envoie la notification initialized, relève la version et les capacités annoncées, puis ferme la session lorsque le serveur en a créé une. Il n’appelle ni tools/list ni tools/call. Un endpoint qui répond 401 ou 403 est classé comme joignable avec authentification exigée, sans tentative de connexion.

Options utiles :

# Ajouter un fichier non standard
npm run collect -- --path ./config/mcp.json

# Ajouter explicitement une configuration Codex TOML
npm run collect -- --path ~/.codex/config.toml

# Rechercher aussi le .mcp.json d’un autre projet Claude Code
npm run collect -- --workspace ../autre-projet

# Adapter le délai réseau, au maximum 15 secondes
npm run collect -- --probe --timeout 10000

# Choisir le fichier de sortie
npm run collect -- --output ./mcp-inventory-equipe.json

# Produire également un SBOM CycloneDX
npm run collect -- --sbom

Inventaire supply chain et SBOM

MCP TrustMap reconnaît les lanceurs suivants sans les exécuter :

  • npm : npx, npm exec, pnpm dlx, yarn dlx et bunx ;
  • Python : uvx et pipx run ;
  • conteneurs : docker run, podman run et nerdctl run ;
  • exécutables locaux, enregistrés sans chemin personnel ni version inventée.

Une version npm exacte ou une contrainte PyPI == est considérée comme verrouillée. Pour une image OCI, seul un digest SHA-256 complet est immuable : un tag comme 1.4.0 reste modifiable dans le registre.

La commande suivante produit mcp-inventory.json et mcp-sbom.cdx.json :

npm run collect:sbom

Le même SBOM peut être téléchargé depuis le menu Exporter de l’application. Il utilise CycloneDX 1.7, des identifiants Package URL et un graphe reliant chaque serveur MCP à ses composants détectés.

Dépendances transitives et lockfiles

Par défaut, le collecteur recherche dans le workspace, jusqu’à six niveaux et 50 lockfiles :

  • package-lock.json et npm-shrinkwrap.json ;
  • pnpm-lock.yaml ;
  • yarn.lock classique (v1) et moderne (Berry) ;
  • uv.lock ;
  • poetry.lock.

Il lit au maximum 20 Mo et 5 000 composants par lockfile, sans lancer de gestionnaire de paquets. Un graphe n’est rattaché à un serveur que si le nom et la version exacte de son composant direct correspondent à une entrée du lockfile. Chaque serveur est limité à 1 000 composants collectés ; un dépassement est explicitement signalé comme tronqué. Les répertoires de build, les caches, .git et node_modules ne sont pas parcourus.

Pour un monorepo, le collecteur lit les motifs workspaces du package.json racine et packages de pnpm-workspace.yaml, dans une limite de 250 manifests. Il rattache une commande locale au package le plus précis à partir de cwd, du script npm|pnpm|yarn run ou du chemin de l’exécutable. Les importers pnpm et npm conservent les frontières entre packages : les dépendances d’une application voisine ne sont pas ajoutées au serveur MCP.

Pour ajouter un lockfile situé ailleurs ou désactiver cette découverte :

npm run collect -- --lockfile ../serveur/uv.lock
npm run collect -- --no-lockfiles

Les dépendances transitives sont marquées dans l’interface et reliées par leurs vraies arêtes dans CycloneDX. Lorsqu’un avis OSV concerne une dépendance transitive, la remédiation indique la dépendance directe qui l’introduit et demande de régénérer le lockfile.

Provenance SLSA et signatures npm

La vérification explicite suivante couvre tous les composants npm versionnés et rattachés aux serveurs, directs comme transitifs :

npm run collect -- --provenance

Pour chaque composant, MCP TrustMap :

  1. exige que l’intégrité SRI du lockfile corresponde à dist.integrity ;
  2. vérifie la signature ECDSA du registre sur nom@version:dist.integrity avec la clé npm publiée ;
  3. télécharge l’attestation SLSA v1 annoncée par le registre ;
  4. vérifie cryptographiquement le bundle Sigstore, son certificat et son inclusion dans le journal de transparence ;
  5. exige que le sujet Package URL et son digest SHA-512 correspondent au composant verrouillé.

Une simple présence de dist.signatures, dist.attestations ou d’un checksum Yarn ne produit donc jamais le statut « vérifié ». Le checksum de cache Yarn Berry reste affiché comme intégrité enregistrée, mais la preuve npm demeure « non vérifiable » lorsqu’aucun SRI de l’artefact n’est disponible.

La vérification cryptographique ne suffit pas à décider quel dépôt est autorisé à publier. Pour imposer l’identité du workflow attendue, fournissez ensemble l’émetteur OIDC et une expression régulière URI ancrée :

npm run collect -- \
  --provenance \
  --provenance-issuer https://token.actions.githubusercontent.com \
  --provenance-identity '^https://github\.com/ORG/REPO/.github/workflows/release\.yml@refs/tags/.+$'

Sans cette politique, une provenance valide est marquée comme cryptographiquement vérifiée mais l’audit signale concrètement que l’identité source n’est pas contrainte. Une signature invalide, un digest divergent ou une attestation Sigstore invalide produit un constat critique.

Signatures et provenance des images OCI

Seules les images verrouillées sous la forme registre/organisation/image@sha256:... sont éligibles. Un tag, même versionné, reste mutable et n’est jamais présenté comme vérifié.

Pour tous les registres compatibles Cosign, installez Cosign, puis imposez l’émetteur et l’identité attendus :

npm run collect -- \
  --oci-cosign \
  --oci-issuer https://token.actions.githubusercontent.com \
  --oci-identity '^https://github\.com/ORG/REPO/.github/workflows/release\.yml@refs/tags/.+$'

Le collecteur exécute sans shell cosign verify puis cosign verify-attestation --type slsaprovenance1. Il conserve les contrôles de claims et de journal de transparence actifs, puis vérifie à nouveau que le digest de la signature et le sujet de l’attestation correspondent exactement à l’image configurée. --cosign-path chemin/vers/cosign permet d’utiliser un binaire installé hors du PATH.

Pour une image attestée par GitHub, la voie suivante utilise la CLI GitHub et contraint directement le dépôt producteur :

npm run collect -- --oci-github-repo ORG/REPO

Cette commande appelle gh attestation verify oci://IMAGE@sha256:..., valide la preuve signée, la racine de confiance, l’identité du dépôt et le digest. Elle ne prétend pas avoir vérifié une signature d’image Cosign distincte : l’interface affiche alors « GitHub SLSA » plutôt que « Cosign + SLSA ».

Plusieurs politiques OCI

Pour un inventaire qui utilise plusieurs registres ou organisations, partez du fichier examples/oci-policies.json, adaptez ses identités puis lancez :

npm run collect -- --oci-policy-file ./examples/oci-policies.json

Le document est versionné et chaque règle possède :

  • un id stable, restitué dans l’inventaire et le SBOM ;
  • un imagePrefix sans schéma, tag ni digest ;
  • une politique github liée à un dépôt owner/repository, ou une politique cosign qui impose l’émetteur et l’identité du certificat.

La règle au préfixe le plus long est toujours sélectionnée. Par exemple, ghcr.io/acme/critical prend le pas sur ghcr.io/acme. Les identifiants et préfixes dupliqués sont rejetés avant toute vérification. Il n’existe aucun fallback implicite : une image verrouillée qui ne correspond à aucune règle produit un constat critique « Politique absente » et doit être ajoutée explicitement au fichier avant sa mise en service.

Le document est limité à 50 politiques et 256 Ko. --cosign-path reste utilisable avec un fichier mixte pour indiquer l’emplacement du binaire Cosign ; la voie GitHub continue d’utiliser gh.

Les références d’images peuvent être transmises au registre et au service de confiance choisi. Pour un registre privé, cosign ou gh peut réutiliser ses propres identifiants déjà configurés ; MCP TrustMap ne lit ni ne conserve ces identifiants.

Admission Kubernetes

Le même fichier de politiques peut produire un dossier d’admission Kubernetes sans contacter le cluster :

npm run generate:admission -- \
  --policy-file ./examples/oci-policies.json \
  --namespace production \
  --output ./kubernetes-admission

--namespace est répétable et obligatoire afin qu’aucun périmètre d’application ne soit supposé. Le dossier est nouveau : le générateur refuse de l’écraser. Il contient :

  • deux ClusterImagePolicy par règle Cosign, car Sigstore cumule les politiques correspondantes : l’une exige la signature, l’autre la provenance SLSA v1 ;
  • un fichier de valeurs Helm par règle GitHub, avec l’organisation et le dépôt exacts pour le chart officiel trust-policies ;
  • namespaces.yaml, qui active explicitement policy.sigstore.dev/include: "true" ;
  • un README ordonné avec installation, --dry-run=server, application et configuration explicite de no-match-policy: deny.

Le générateur rejette les préfixes imbriqués. Le vérificateur local sait choisir la règle la plus spécifique, mais Kubernetes impose toutes les ClusterImagePolicy qui correspondent à une image ; accepter silencieusement un chevauchement changerait donc la sémantique de sécurité. Utilisez des préfixes disjoints ou une identité commune avant la génération. Les expressions d’identité incompatibles avec le moteur RE2/Go de Kubernetes, comme les références arrière et anticipations, sont également refusées.

Le bundle ne doit pas être appliqué directement en production. Relisez les identités, testez d’abord les commandes kubectl --dry-run=server générées, activez un namespace de préproduction puis vérifiez qu’une image non conforme est bien refusée.

Validation hors ligne et CI

Un bundle existant peut être comparé à sa politique source sans contacter de cluster, de registre ou de service externe :

npm run validate:admission -- \
  --policy-file ./examples/oci-policies.json \
  --namespace production \
  --bundle ./kubernetes-admission

Le validateur refuse les liens symboliques, sous-dossiers, fichiers inattendus, documents YAML invalides et ressources Kubernetes incomplètes. Il régénère ensuite le résultat attendu et compare chaque fichier octet par octet avant de calculer une empreinte SHA-256 du bundle complet.

Le workflow GitHub Actions génère et valide un bundle d’exemple à chaque pull request et mise à jour de main. Une modification du générateur, des identités, des versions épinglées ou des instructions d’application qui rendrait le bundle incohérent fait donc échouer la CI.

Vulnérabilités connues avec OSV

L’analyse OSV est explicite et ne concerne que les composants dont la version est exacte. La commande complète réalise le probe passif, interroge OSV, vérifie la provenance npm et produit également le SBOM :

npm run collect:security

Le collecteur envoie uniquement des PURL versionnés à l’API publique OSV.dev. Il récupère ensuite les avis correspondants, leurs niveaux de sévérité et, lorsqu’elle est publiée, la première version corrigée. Les résultats alimentent :

  • le score et les remédiations de chaque serveur ;
  • le rapport JSON et l’export SARIF ;
  • la section vulnerabilities du SBOM CycloneDX.

Une panne OSV ne produit aucun faux résultat négatif : l’inventaire est écrit avec le statut error, le message précise que l’analyse est incomplète et la commande se termine avec le code 2.

Emplacements reconnus

Client Windows macOS Linux
Codex %USERPROFILE%\.codex\config.toml ~/.codex/config.toml ~/.codex/config.toml
Claude Desktop %APPDATA%\Claude\claude_desktop_config.json ~/Library/Application Support/Claude/claude_desktop_config.json ~/.config/Claude/claude_desktop_config.json
Claude Desktop Microsoft Store %LOCALAPPDATA%\Packages\Claude_pzs8sxrjxfjjc\LocalCache\Roaming\Claude\claude_desktop_config.json
Claude Code utilisateur/local %USERPROFILE%\.claude.json ~/.claude.json ~/.claude.json
Claude Code projet .mcp.json du workspace idem idem
Claude Code administré %ProgramFiles%\ClaudeCode\managed-mcp.json /Library/Application Support/ClaudeCode/managed-mcp.json /etc/claude-code/managed-mcp.json
Cursor ~/.cursor/mcp.json ~/.cursor/mcp.json ~/.cursor/mcp.json
VS Code %APPDATA%\Code\User\mcp.json ~/Library/Application Support/Code/User/mcp.json ~/.config/Code/User/mcp.json
Windsurf ~/.codeium/windsurf/mcp_config.json idem idem
Workspace .vscode/mcp.json, .cursor/mcp.json idem idem

Les fichiers settings.json de VS Code sont aussi inspectés lorsque présents. Les sous-tables Codex, notamment [mcp_servers.<nom>.env] et [mcp_servers.<nom>.http_headers], sont rattachées au serveur puis assainies comme les objets JSON. Pour ~/.claude.json, les chemins des projets servent uniquement à produire des identifiants distincts et ne sont jamais écrits dans l’inventaire. Les chemins personnels sont normalisés avec ~ dans l’inventaire. Sous macOS et Linux, le fichier produit reçoit des permissions 0600.

Les connecteurs distants ajoutés au compte Claude sont gérés dans l’infrastructure Anthropic et ne sont pas présents dans ces fichiers locaux. Ils ne peuvent donc pas être inventoriés par le collecteur hors ligne.

Le probe suit la version stable 2025-11-25 de la spécification MCP et accepte les réponses JSON comme Server-Sent Events définies par le transport Streamable HTTP.

Contrôles de sécurité

Famille Ce qui est vérifié Exemple de correction
Secrets Jetons, mots de passe et clés présents en clair Injection par variable d’environnement ou coffre de secrets
Transport URL HTTP et absence d’authentification visible HTTPS et jeton court lié à l’audience
Exécution Shells intermédiaires et options désactivant la sécurité Appel direct du binaire et sandbox active
Supply chain Paquets non verrouillés, images OCI mutables, avis OSV, signatures et provenance SLSA Version exacte, digest SHA-256, version corrigée et identité de publication attendue
Autorisations Racines de disque, comptes administrateurs et portées larges Chemin dédié, rôle en lecture seule et scopes minimaux
Audit Identité et corrélation insuffisantes Identifiant de session et journalisation de métadonnées

Les contrôles sont volontairement conservateurs. Un signal signifie qu’une revue est nécessaire ; il ne prouve pas à lui seul qu’une vulnérabilité est exploitable.

Architecture

  • Next.js 16 / React 19 pour l’interface ;
  • TypeScript pour le moteur d’analyse et les composants ;
  • vinext / Vite pour la construction ;
  • Better Auth pour les comptes, sessions, organisations, invitations et MFA ;
  • Cloudflare D1 pour l’identité et les données métier isolées par organisation ;
  • Resend pour les courriels transactionnels ;
  • Cloudflare Workers pour l’hébergement autonome et le domaine personnalisé ;
  • aucune API distante requise pour l’analyse statique ; OSV reste optionnel.

Principaux fichiers :

app/
  page.tsx       Garde de session et chargement de l’organisation active
  dashboard.tsx  Interface et orchestration des audits
  globals.css    Système visuel responsive
  layout.tsx     Métadonnées et partage social
  settings/      Membres, rôles, invitations et MFA
  api/auth/      API d’identité autonome
  api/exception-sync/route.ts Synchronisation par organisation
db/
  schema.ts      Identité, organisations, historique et exceptions dans D1
lib/
  auth/            Configuration serveur/client, rôles et courriels
  audit-engine.ts  Règles, scoring et exports JSON/SARIF
  audit-history.ts Agrégation confidentielle et comparaison des audits
  finding-exceptions.ts Registre local et exports des risques acceptés
  trustmap-governance.ts Signature des politiques et bundles d’exceptions chiffrés
  enterprise-sync.ts Chiffrement par clé de données et pseudonymisation
  enterprise-authorization.ts Rôles et double approbation côté serveur
  key-management.ts Enveloppe de clés de l’hébergeur ou passerelle KMS HTTPS
  collector.ts     Découverte, redaction et probe MCP passif
  lockfiles.ts     Graphes package-lock, pnpm, Yarn, uv et Poetry
  kubernetes-admission.ts Génération sûre des politiques d’admission
  kubernetes-admission-validation.ts Validation déterministe des bundles
  oci-provenance.ts Vérification OCI bornée via Cosign ou GitHub
  osv.ts           Client OSV limité aux PURL versionnés
  pdf-report.ts    Composition locale du rapport PDF paginé
  provenance.ts    Signatures npm et attestations SLSA/Sigstore
  supply-chain.ts  Détection des composants et export CycloneDX
  workspaces.ts    Découverte bornée et sélection des packages monorepo
examples/
  oci-policies.json Exemple de routage OCI GitHub/Cosign par préfixe
tools/
  admission.ts     Générateur de bundle Kubernetes sans accès au cluster
  collector.ts     Interface en ligne de commande multiplateforme
tests/
  audit-engine.test.ts     Tests de sécurité du moteur
  enterprise-authorization.test.ts Tests des rôles et approbations critiques
  finding-exceptions.test.ts Tests d’expiration, révocation et exports
  collector.test.ts        Tests du collecteur et du protocole passif
  kubernetes-admission.test.ts Tests YAML, identités et préfixes Kubernetes
  kubernetes-admission-validation.test.ts Tests d’intégrité des bundles
  lockfiles.test.ts        Tests des graphes npm, pnpm, Yarn, uv et Poetry
  oci-provenance.test.ts    Tests Cosign/GitHub, identité et digests OCI
  osv.test.ts              Tests du client OSV et de ses limites réseau
  pdf-report.test.ts       Tests du document PDF et de sa pagination
  provenance.test.ts       Tests ECDSA, digest SLSA et politique Sigstore
  supply-chain.test.ts     Tests npm, PyPI, OCI, PURL et CycloneDX
  enterprise-sync.test.ts Tests de chiffrement par enveloppe et rotation
  trustmap-governance.test.ts Tests des signatures et échanges chiffrés
  workspaces.test.ts       Tests de découverte et d’isolation des monorepos
  rendered-html.test.mjs   Tests du rendu de production
public/
  og.png         Carte d’aperçu du projet

Scripts

Commande Usage
npm run dev Démarre l’application en développement
npm run build Produit et valide la version de production
npm run start Lance la version construite
npm run db:generate Génère une migration Drizzle après un changement de schéma
npm run db:migrate:local Applique les migrations à la base D1 locale
npm run db:migrate:remote Applique les migrations à la base D1 de production
npm run deploy:standalone Construit et déploie le Worker autonome
npm run collect Produit un inventaire local assaini
npm run gateway -- --endpoint <url> --server <nom> -- <commande MCP> Protège un serveur MCP stdio avec les politiques Runtime
npm run audit:ci -- --path <fichier> Bloque la CI sur les constats critiques ou élevés
npm run collect:sbom Produit l’inventaire et le SBOM CycloneDX
npm run collect:security Ajoute le probe, OSV, la provenance npm et le SBOM
npm run collect -- --probe Ajoute une négociation passive des endpoints HTTPS
npm run collect -- --osv Interroge OSV avec les seuls PURL versionnés
npm run collect -- --provenance Vérifie signatures npm et attestations SLSA/Sigstore
npm run collect -- --provenance-issuer <url> --provenance-identity <regexp> Contraint l’identité du workflow de publication
npm run collect -- --oci-cosign --oci-issuer <url> --oci-identity <regexp> Vérifie signature Cosign et provenance SLSA OCI
npm run collect -- --oci-github-repo <owner/repo> Vérifie une attestation OCI GitHub liée au dépôt attendu
npm run collect -- --oci-policy-file <fichier> Applique plusieurs politiques OCI par préfixe, sans fallback implicite
npm run generate:admission -- --policy-file <fichier> --namespace <nom> Génère un bundle Kubernetes Sigstore sans contacter le cluster
npm run validate:admission -- --policy-file <fichier> --namespace <nom> --bundle <dossier> Valide hors ligne un bundle Kubernetes généré
npm run collect -- --lockfile <fichier> Ajoute un lockfile explicite
npm run collect -- --no-lockfiles Désactive la découverte des lockfiles
npm run lint Vérifie les règles de qualité du code
npm run test:unit Teste le moteur, le collecteur et la non-divulgation des secrets
npm run test:rendered Vérifie le HTML produit par l’application
npm test Construit puis exécute l’ensemble des tests

Intégration continue

Le workflow GitHub Actions .github/workflows/ci.yml s’exécute sur chaque pull request et chaque mise à jour de main. Le collecteur et le moteur sont testés sur Linux, Windows et macOS. Un second job lance le lint, construit l’application et vérifie le HTML produit.

Bloquer une configuration MCP à haut risque

Le mode CI audite uniquement les fichiers passés avec --path, exige qu’au moins un serveur soit trouvé et termine avec le code 3 si un constat critique ou élevé est détecté :

npm run audit:ci -- \
  --path ./.mcp.json \
  --sarif ./mcp-trustmap.sarif

Le seuil peut être adapté avec --fail-on critical|high|medium. Utilisez --no-default-paths dans une CI pour ne jamais auditer les fichiers utilisateur du runner ; le script audit:ci l’active déjà. --require-servers empêche un fichier absent ou mal ciblé de produire un faux succès. Le résumé console n’affiche ni extraits de configuration ni secrets.

Exemple GitHub Actions avec publication des constats dans Code Scanning :

permissions:
  contents: read
  security-events: write

steps:
  - uses: actions/checkout@v6
  - uses: actions/setup-node@v6
    with:
      node-version: 22.13
      cache: npm
  - run: npm ci
  - name: Audit MCP
    run: npm run audit:ci -- --path ./.mcp.json --sarif
  - name: Publier le rapport SARIF
    if: always() && hashFiles('mcp-trustmap.sarif') != ''
    uses: github/codeql-action/upload-sarif@v4
    with:
      sarif_file: mcp-trustmap.sarif

Les codes de sortie sont stables : 0 pour un contrôle réussi, 1 pour une erreur d’entrée ou d’exécution, 2 pour une analyse réseau/provenance incomplète et 3 pour une politique CI refusée. Si une analyse distante est incomplète et que le seuil est aussi dépassé, le refus de politique (3) prime.

Politiques par environnement et répertoire

TrustMap CI propose trois profils indépendants et modifiables :

Profil Chemin initial Seuil initial Contrôles réseau
Développement ./.mcp/development.json critique désactivés
Préproduction ./.mcp/staging.json élevé OSV et provenance
Production ./.mcp/production.json modéré OSV et provenance

Chaque profil peut être inclus ou exclu du workflow. Le générateur produit un job GitHub Actions séparé par environnement, des noms d’artefacts distincts et une catégorie SARIF dédiée. Les chemins contenant des caractères de contrôle ou des opérateurs shell sont refusés avant la génération.

Exporter la tendance d’audit

Dans TrustMap Audit → Historique & exceptions, le bouton Exporter CSV produit localement un fichier UTF-8 compatible avec Excel. Les points sont ordonnés chronologiquement et incluent les variations de score, les écarts introduits/résolus ainsi que les compteurs agrégés par règle. Aucun nom de serveur, chemin de configuration, extrait ou secret n’est exporté.

Signer les politiques CI

Dans TrustMap CI → Chaîne de confiance, une équipe peut créer une identité ECDSA P-256, protégée par une phrase secrète et exportée dans un fichier JSON chiffré. La clé privée n’est jamais écrite en clair ni envoyée à un service. Cette identité signe ensuite l’ensemble des profils CI et produit un fichier .signed.json.

Avant de charger les profils, le destinataire doit :

  1. obtenir l’empreinte sha256:… du signataire par un canal séparé ;
  2. charger le fichier de politique ;
  3. saisir cette empreinte comme identité approuvée ;
  4. laisser MCP TrustMap vérifier la clé, la signature ECDSA et le schéma.

Une signature cryptographiquement valide sans empreinte approuvée reste explicitement non fiable et ne modifie pas les profils actifs. Une politique altérée, un profil mal formé ou une clé substituée est refusé.

Échanger les exceptions de manière chiffrée

Dans TrustMap Enterprise → Échange confidentiel, le registre d’exceptions peut être exporté dans un bundle AES-256-GCM. La clé est dérivée localement d’une phrase secrète avec PBKDF2-HMAC-SHA-256 et un sel aléatoire. Le fichier chiffré peut être transmis par le canal documentaire habituel, tandis que la phrase secrète doit être communiquée séparément.

À l’import, l’authenticité du bundle et son schéma sont vérifiés avant la fusion. Les décisions sont rapprochées par identifiant et une révocation gagne toujours sur une version active, ce qui évite de réactiver un risque déjà refusé. Aucune phrase secrète n’est persistée par l’application.

Synchronisation autonome par organisation et KMS

Dans TrustMap Enterprise → Espace partagé, le navigateur se connecte à /api/exception-sync. L’API accepte uniquement une session MCP TrustMap valide et vérifie son appartenance à l’organisation active directement dans D1. Chaque écriture est attribuée à une empreinte SHA-256 pseudonymisée propre au membre et à l’organisation ; l’adresse e-mail n’est pas inscrite dans le registre métier.

Chaque organisation cliente représente un espace de confiance séparé. Un membre ne lit et ne modifie que le registre de son organisation active. La synchronisation :

  • fusionne les décisions sans supprimer celles absentes d’un appareil ;
  • donne toujours priorité à une révocation ;
  • utilise une mise à jour optimiste versionnée pour éviter les écrasements concurrents ;
  • conserve les 500 événements d’écriture les plus récents sans nom de serveur, règle, motif ou autre contenu métier en clair.

Rôles Enterprise et approbation critique

Les rôles sont stockés dans l’appartenance de chaque membre à une organisation. Un Admin les attribue depuis Paramètres → Membres et rôles et peut inviter une adresse vérifiée par courriel.

Rôle Lire Synchroniser/révoquer Approuver Rejeter
reader oui non non non
auditor oui oui oui non
admin oui oui oui oui

Pour une nouvelle exception critique, l’API ignore tout état d’approbation fourni par le navigateur, recalcule une sévérité minimale selon la règle et crée une demande liée à l’empreinte pseudonymisée du demandeur. Deux appels PATCH /api/exception-sync effectués par des auditeurs différents sont requis. Les contrôles sont appliqués côté serveur ; les boutons désactivés de l’interface ne constituent qu’un retour utilisateur.

Chaque exception est chiffrée avec une clé de données AES-256-GCM indépendante. La clé de données est ensuite enveloppée par le fournisseur de clés configuré. D1 ne reçoit que l’enveloppe, une clé d’enregistrement pseudonymisée, la version, la date et l’empreinte de l’acteur.

Deux fournisseurs sont disponibles :

  1. secret de plateforme, utilisé par l’hébergement autonome : une clé d’enveloppe de 32 octets est stockée comme secret du Worker ;
  2. passerelle KMS externe, qui reçoit des opérations wrap et unwrap sur HTTPS avec un identifiant de clé et un jeton conservé comme secret.

La rotation change simultanément TRUSTMAP_KMS_KEY_ID et la clé courante. Le secret JSON TRUSTMAP_KMS_PREVIOUS_KEYS peut contenir au maximum dix anciennes versions le temps de relire les enregistrements existants. Chaque synchronisation réenveloppe automatiquement une décision encore protégée par une ancienne version. Les variables attendues et leurs formes sont documentées dans .env.example sans aucune valeur secrète.

TrustMap Agent et AI Asset Graph

Un administrateur ouvre TrustMap Agent, donne un nom au poste puis crée un jeton d’enrôlement. Le jeton n’est affiché qu’une fois et sa valeur hachée est la seule information conservée dans D1.

Sur le poste à superviser :

$env:TRUSTMAP_AGENT_TOKEN="<jeton-affiché-une-fois>"
npm run agent -- --endpoint https://app.votre-domaine.tld --name poste-daniel

Pour une collecte continue toutes les cinq minutes :

$env:TRUSTMAP_AGENT_TOKEN="<jeton-affiché-une-fois>"
npm run agent -- --endpoint https://app.votre-domaine.tld --name poste-daniel --interval 300

Le jeton doit être injecté par le gestionnaire de secrets ou le mécanisme de service du système. Ne le placez ni dans Git, ni dans les arguments de commande, ni dans un fichier d’inventaire. L’option --probe reste explicite et ne contacte que les endpoints MCP HTTPS selon les protections du collecteur.

Le module AI Asset Graph fusionne les instantanés de l’organisation et les outils réellement observés par Runtime. La synchronisation depuis le navigateur reste explicite ; un rôle Reader peut consulter le graphe mais pas le modifier.

TrustMap Runtime

POST /api/runtime/evaluate est le point de décision à appeler avant l’exécution d’un outil. Il accepte soit la session de l’application, soit le jeton Bearer d’un TrustMap Agent. Exemple de corps assaini :

{
  "server": "Filesystem MCP",
  "tool": "write_file",
  "operation": "write",
  "dataClass": "confidential",
  "destinationTrust": "trusted",
  "risk": 65,
  "containsSensitiveInput": false,
  "correlationId": "appel-unique-123"
}

La réponse contient allow, review, deny ou observe. Une décision deny renvoie aussi le statut HTTP 403, afin qu’un proxy ou sidecar échoue fermé. Le mode observe indique la décision qui aurait été appliquée sans bloquer l’appel. Les arguments et résultats des outils ne doivent jamais être transmis à cette API ; seuls les métadonnées de décision et l’identifiant de corrélation sont journalisés.

Les politiques initiales couvrent :

  • l’exfiltration de données restreintes vers une destination externe ou inconnue ;
  • les appels dont le risque atteint le seuil critique ;
  • la validation humaine des écritures, exécutions et opérations administratives ;
  • l’observation des entrées sensibles pendant la phase d’apprentissage.

Seul un Admin peut modifier les politiques. Un Auditor peut exécuter une simulation et consulter les décisions ; un Reader dispose d’un accès en lecture.

TrustMap Runtime Gateway pour Claude Desktop

La passerelle locale transforme le point de décision en contrôle effectif. Elle relaye le protocole JSON-RPC stdio, mais intercepte chaque tools/call avant qu’il atteigne le serveur. Seuls le nom du serveur, le nom de l’outil, le type d’opération, la classe de données, le niveau de confiance et le score de risque sont envoyés à MCP TrustMap. Les arguments et résultats restent locaux.

Créez d’abord un jeton dans TrustMap Agent, puis lancez un serveur protégé :

$env:TRUSTMAP_AGENT_TOKEN="<jeton-affiché-une-fois>"
npm run gateway -- --endpoint https://app.votre-domaine.tld --server "Filesystem MCP" -- npx -y @modelcontextprotocol/server-filesystem C:\dossier-autorisé

Dans la configuration Claude Desktop, remplacez la commande directe du serveur par npm run gateway et placez ses paramètres avant le séparateur --. Le jeton doit provenir de l’environnement du processus Claude ou d’un gestionnaire de secrets ; la passerelle le retire explicitement de l’environnement du serveur MCP enfant.

Par défaut :

  • deny et review bloquent l’appel avant exécution ;
  • une opération de lecture reçoit un risque de 25, une écriture 60, une exécution 85 et une administration 90 ;
  • une panne, un dépassement de délai ou une réponse invalide bloque l’appel ;
  • --fail-open et --allow-review sont des dérogations explicites à réserver à une phase d’observation contrôlée.

Déploiement autonome avec domaine personnalisé

Le modèle wrangler.example.jsonc déploie MCP TrustMap sur Cloudflare Workers, relie D1 et configure un domaine personnalisé. Le domaine doit appartenir à une zone Cloudflare de votre compte.

Copy-Item wrangler.example.jsonc wrangler.local.jsonc
npx wrangler login
npx wrangler d1 create mcp-trustmap-production

Reportez le database_id retourné dans wrangler.local.jsonc, puis remplacez app.votre-domaine.tld dans routes, BETTER_AUTH_URL et TRUSTMAP_EMAIL_FROM. Les valeurs sensibles restent hors du fichier :

npx wrangler secret put BETTER_AUTH_SECRET
npx wrangler secret put RESEND_API_KEY
npx wrangler secret put TRUSTMAP_KMS_MASTER_KEY
# Seulement si une passerelle KMS externe est utilisée :
npx wrangler secret put TRUSTMAP_KMS_BEARER_TOKEN

BETTER_AUTH_SECRET et TRUSTMAP_KMS_MASTER_KEY doivent chacun être des valeurs aléatoires indépendantes d’au moins 32 octets. Appliquez enfin le schéma avant le premier déploiement :

npm run db:migrate:remote
npm run deploy:standalone

Cloudflare crée le routage DNS et le certificat TLS du domaine personnalisé. Le déploiement de production refuse de démarrer sans BETTER_AUTH_SECRET; la journalisation locale des liens d’e-mail est explicitement désactivée dans le modèle de production.

Limites actuelles

  • la découverte reste explicite sans TrustMap Agent ; l’Agent doit être installé comme service par l’équipe cliente pour une collecte périodique ;
  • TrustMap Runtime Gateway protège les serveurs stdio configurés derrière lui, mais les transports HTTP distants nécessitent encore un proxy ou sidecar qui interroge l’API avant l’exécution ;
  • par sécurité, le collecteur n’exécute pas les serveurs stdio et ne confirme donc pas leur comportement à l’exécution ;
  • le probe distant valide la négociation, pas les permissions effectives de chaque outil ;
  • les résolutions Yarn ambiguës qui associent un même nom à plusieurs versions ne sont pas devinées sans descripteur exact ;
  • les globs de workspace sont bornés à six niveaux et 250 manifests ;
  • les dépendances conditionnelles Python ne sont pas toutes résolues ;
  • les fichiers OCI sont limités à 50 politiques et utilisent des préfixes explicites plutôt que des motifs glob complexes ;
  • le générateur d’admission refuse les préfixes imbriqués et ne remplace pas une validation kubectl --dry-run=server contre les CRD réellement installées ;
  • les versions de charts inscrites dans le bundle sont épinglées et doivent être réévaluées lors d’une mise à niveau de Policy Controller ;
  • la voie Cosign requiert un binaire cosign installé localement et la voie GitHub requiert la CLI gh ;
  • OSV peut ne pas disposer d’un avis ou d’une sévérité normalisée pour tous les écosystèmes ; le statut de l’analyse doit donc être vérifié dans l’inventaire ;
  • elle ne confirme pas les permissions effectives côté GitHub, base de données, OAuth ou système de fichiers ;
  • l’historique est limité à 60 synthèses agrégées et ne permet pas de rouvrir l’inventaire complet d’un audit précédent ;
  • l’envoi des vérifications, invitations et récupérations nécessite une clé Resend et un domaine d’expédition vérifié ;
  • une organisation limitée à une seule identité ne peut pas achever une double approbation : deux auditeurs distincts du demandeur doivent être membres ;
  • la passerelle KMS externe suit le contrat HTTPS MCP TrustMap et nécessite un adaptateur devant AWS KMS, Azure Key Vault, Google Cloud KMS ou un HSM ;
  • l’empreinte d’une identité de signature doit être validée par un canal distinct ; un fichier auto-signé ne constitue pas à lui seul une identité de confiance ;
  • le catalogue de règles devra évoluer avec les spécifications et pratiques MCP.

Prochaines étapes possibles

  • fédération SAML/OIDC et provisionnement SCIM pour les grands comptes ;
  • clés d’accès matérielles WebAuthn en complément du TOTP ;
  • adaptateurs KMS natifs et migration automatique lors de la rotation ;
  • clés de signature gérées par un HSM d’entreprise.

Contribution

Les contributions peuvent être proposées dans une branche dédiée avec :

  1. une description du risque ou du contrôle ajouté ;
  2. un exemple de configuration vulnérable et corrigée sans véritable secret ;
  3. la validation de npm run build ;
  4. une pull request expliquant les éventuels faux positifs.

About

Secure MCP Servers and AI Agents components

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages