MCP Fusion/Security and governance/Pipeline de sécurité
Pipeline de sécurité
Toutes les couches entre un agent et vos données, dans l’ordre : firewall d’entrée, validation stricte, middleware de tenant, Presenters, le moteur de masquage, le limiteur de sortie, le firewall de prompt et le sandbox.
MCP Fusion applique la sécurité comme un pipeline de couches, chacune avec une position claire dans la requête. Cette page est la carte technique : qu’est-ce qui s’exécute, dans quel ordre, avec quelles garanties.
L’ordre, de bout en bout
1 contextFactory tenant and identity resolution
2 rate limiter sliding window, key from ctx
3 input firewall LLM-as-Judge on the arguments
4 validate strict Zod per action, unknown keys rejected
5 middleware chain auth, audit, custom, precompiled and frozen
6 handler your business logic
7 Presenter schema shape → _select → redact → serialize
8 rules and UI computed on the full object, never on the wire copy
9 egress guard byte budget on the text response
10 audit + telemetry every stage emits if a sink is configuredCouche par couche
Rate limiter
rateLimit({ windowMs, limit, keyFn }) est un middleware qui utilise une fenêtre glissante sur des listes d’horodatages. Deux appels comptent : increment() compte sans enregistrer, et record() ne journalise que les requêtes acceptées, donc le trafic rejeté ne peut pas gonfler sa propre fenêtre. keyFn(ctx) est le crochet d’identité : limitez par token, par tenant ou par utilisateur. Le store est une interface ; le store en mémoire est documenté comme mono-processus uniquement, la production utilise votre Redis ou KV derrière la même interface.
Firewall d’entrée
inputFirewall({ judge }) s’exécute après la validation Zod, avant votre handler. Les arguments sont sérialisés dans un prompt de juge (les backticks sont neutralisés pour empêcher l’évasion de fence) et un SemanticProbeAdapter interchangeable renvoie { safe, threats }. Sur !safe, le handler n’est jamais appelé : la réponse est un toolError('INPUT_REJECTED', ...) auto-réparant. Cette couche vise les entrées de type injection : « ignore les instructions précédentes », charges d’exfiltration, chemins de fichiers contrebandés.
Masquage par le Presenter (le firewall d’égress)
.redactPII(paths, censor?) compile des chemins fast-redact en une seule fonction, mise en cache sur le Presenter. L’ordre du pipeline dans Presenter.make() est précis : tronquer, valider, appliquer _select, cloner les données du wire, masquer, les sérialiser en chaîne, puis rendre les blocs d’UI et les règles depuis l’objet complet non masqué. Conséquences :
- le texte du modèle ne contient jamais de champs masqués ;
[REDACTED]n’est même pas sur le wire pour les clés masquées par_select - les blocs
ui.table()conservent les valeurs réelles (ils sont construits depuis l’objet complet en mémoire, et le texte du wire est déjà figé) - si
structuredCloneou le masqueur lève une exception, le pipeline lève aussi :Data withheld to prevent PII leak. Le masquage est fail-closed à ce stade.
fast-redact est un peer optionnel. S’il n’est pas installé, le masqueur se dégrade en no-op avec un avertissement console. Considérez-le comme une dépendance requise pour les connecteurs qui détiennent des données personnelles.
Firewall de prompt
Les règles elles-mêmes sont une surface d’attaque : les règles dynamiques sont générées à partir de données, et les données viennent du monde de l’agent. presenter.promptFirewall({ judge }) envoie les règles système accumulées à un juge avant que l’une d’elles n’atteigne le modèle. La stratégie est fail-closed et par règle : si le juge signale le lot mais nomme certaines règles, celles qui ne sont pas nommées sont bloquées aussi. Le mode consensus (tous les juges sont d’accord) n’a pas de fail-open. Configurer un firewall force le chemin asynchrone : make() lève, makeAsync() est le contrat.
Sandbox
sandboxed() sur un tool annonce la délégation de calcul : l’agent envoie une fonction fléchée JS, SandboxEngine l’exécute dans un contexte isolated-vm neuf avec les données injectées comme copie externe, et seule la valeur renvoyée revient. Valeurs par défaut : timeout de 5s, isolate de 128MB, plafond de sortie de 1MB, plafond de code de 64KB. process, require, fs, globalThis et Buffer n’existent pas dans le contexte ; la garde qui rejette les motifs évidents relève du DX seulement et n’est explicitement pas la frontière. En cas d’annulation, le moteur détruit l’isolate (ou ne libère que le contexte quand d’autres requêtes le partagent) et le recrée à l’appel suivant.
Kill switch et halt
L’arrêt d’urgence vit dans la console, voir Connector policy : le halt global et la politique par connecteur. Sur l’Edge, les connecteurs interrompus cessent de servir les appels sans redéploiement.
Ce que le framework ne fait pas
Honnêteté plutôt que marketing : le middleware d’audit du framework émet des événements vers votre sink (empreintes SHA-256 des arguments, classification de statut, pas de signature, pas de chaîne). La chaîne d’audit signée infalsifiable est une fonction d’hébergement de Vinkius Cloud : déployez avec mcpfusion deploy et la plateforme l’enregistre pour vous. La même répartition s’applique aux stores de rate limit : l’interface est la vôtre, l’Edge l’exécute.
Prochaines étapes
- Runtime architecture : où chaque couche se situe dans le moteur
- Governance : prouver que le pipeline est resté verrouillé
- Tools : attacher des gardes à un tool
