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.
- 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
stdiode 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.
- 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
stdioqui applique réellement ces décisions avanttools/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
mcpServersutilisés par Claude Desktop, Claude Code, Cursor et VS Code, ainsi que des tables TOMLmcp_serversde 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,AuditoretReaderappliqué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.
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
--provenanceest 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-attestationough attestation verifyavec 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
kubectlni 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.
- Node.js
22.13ou supérieur ; - npm ;
- Git.
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 devOuvrez 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.
- Créez un compte dans Inscription puis vérifiez son adresse.
- Créez l’organisation du premier client ; son créateur devient
Admin. - Ouvrez Paramètres pour inviter les autres membres et leur attribuer
Admin,AuditorouReader. - Activez le MFA dans Paramètres → Sécurité du compte, scannez le QR code et conservez les codes de secours hors ligne.
npm run build- Ouvrez Importer.
- Choisissez un fichier JSON ou collez une configuration.
- Cliquez sur Analyser la configuration.
- Consultez le score et les remédiations prioritaires.
- Ouvrez un serveur pour voir l’impact et copier le correctif recommandé.
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.
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.
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}"
}
}
}
}Depuis le dossier du projet, créez un inventaire assaini :
npm run collectLe 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 -- --probeLe 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 -- --sbomMCP TrustMap reconnaît les lanceurs suivants sans les exécuter :
- npm :
npx,npm exec,pnpm dlx,yarn dlxetbunx; - Python :
uvxetpipx run; - conteneurs :
docker run,podman runetnerdctl 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:sbomLe 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.
Par défaut, le collecteur recherche dans le workspace, jusqu’à six niveaux et 50 lockfiles :
package-lock.jsonetnpm-shrinkwrap.json;pnpm-lock.yaml;yarn.lockclassique (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-lockfilesLes 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.
La vérification explicite suivante couvre tous les composants npm versionnés et rattachés aux serveurs, directs comme transitifs :
npm run collect -- --provenancePour chaque composant, MCP TrustMap :
- exige que l’intégrité SRI du lockfile corresponde à
dist.integrity; - vérifie la signature ECDSA du registre sur
nom@version:dist.integrityavec la clé npm publiée ; - télécharge l’attestation SLSA v1 annoncée par le registre ;
- vérifie cryptographiquement le bundle Sigstore, son certificat et son inclusion dans le journal de transparence ;
- 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.
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/REPOCette 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 ».
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.jsonLe document est versionné et chaque règle possède :
- un
idstable, restitué dans l’inventaire et le SBOM ; - un
imagePrefixsans schéma, tag ni digest ; - une politique
githubliée à un dépôtowner/repository, ou une politiquecosignqui 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.
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
ClusterImagePolicypar 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 explicitementpolicy.sigstore.dev/include: "true";- un README ordonné avec installation,
--dry-run=server, application et configuration explicite deno-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.
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-admissionLe 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.
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:securityLe 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
vulnerabilitiesdu 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.
| 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.
| 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.
- 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
| 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 |
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.
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.sarifLe 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.sarifLes 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.
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.
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é.
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 :
- obtenir l’empreinte
sha256:…du signataire par un canal séparé ; - charger le fichier de politique ;
- saisir cette empreinte comme identité approuvée ;
- 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é.
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.
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.
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 :
- secret de plateforme, utilisé par l’hébergement autonome : une clé d’enveloppe de 32 octets est stockée comme secret du Worker ;
- passerelle KMS externe, qui reçoit des opérations
wrapetunwrapsur 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.
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-danielPour 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 300Le 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.
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.
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 :
denyetreviewbloquent 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-openet--allow-reviewsont des dérogations explicites à réserver à une phase d’observation contrôlée.
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-productionReportez 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_TOKENBETTER_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:standaloneCloudflare 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.
- 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
stdioconfiguré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
stdioet 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=servercontre 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
cosigninstallé localement et la voie GitHub requiert la CLIgh; - 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.
- 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.
Les contributions peuvent être proposées dans une branche dédiée avec :
- une description du risque ou du contrôle ajouté ;
- un exemple de configuration vulnérable et corrigée sans véritable secret ;
- la validation de
npm run build; - une pull request expliquant les éventuels faux positifs.
