Aller au contenu
← Tous les articles

13 oct. 2026
4 min de lecture

  • Open Source
  • Security
  • TypeScript
  • MCP
  • AI Agents

Les assistants IA de programmation peuvent désormais lancer des commandes sur votre ordinateur. Memnox décide de ce qu'ils ont le droit de faire — avec des règles fixes et un bouton « annuler ». Ce que c'est, les failles que j'ai fermées, et ce que j'ai appris.

Le projet

En une phrase : Memnox est un garde du corps pour les assistants IA de programmation : avant que l'assistant exécute une commande sur votre ordinateur, Memnox décide si elle est autorisée, si elle demande votre accord, ou si elle est bloquée.

Les assistants IA comme Claude Code, Cursor ou Codex ne se contentent plus de suggérer du code — ils lancent des commandes, installent des paquets, poussent sur GitHub et modifient des fichiers seuls. La plupart du temps, c'est formidable. Mais une seule mauvaise commande peut effacer du travail, divulguer un mot de passe ou envoyer du code cassé en production. Aujourd'hui, la protection se résume souvent à « faire confiance à l'IA » ou « cliquer sur approuver cent fois par jour ».

Memnox se place entre les deux. Vous écrivez des règles simples (« ne jamais forcer un push sur main », « me demander avant de supprimer des fichiers », « ne jamais envoyer mes clés d'API nulle part »), et il les applique à chaque action de chaque assistant, garde un journal de ce qui s'est passé, et crée un point de restauration avant toute action destructrice pour pouvoir revenir en arrière.

Ce qui le rend innovant

  • Des règles, pas des suppositions. Certains outils de sécurité demandent à une autre IA si une action semble dangereuse. Memnox suit des règles fixes : la même action reçoit toujours la même réponse.
  • Les mêmes règles pour tous les assistants. Quel que soit l'outil d'IA utilisé, les mêmes protections s'appliquent.
  • Plusieurs couches de protection. Si une action échappe à une vérification, une autre la rattrape.
  • Un bouton « annuler ». Avant toute action destructrice, il enregistre un point de restauration, et chaque décision est inscrite dans un journal consultable.

En bref : ma contribution et ce que j'en retiens

Ma part : 11 de mes 13 améliorations ont été acceptées. Chacune fermait un moyen de contourner les règles : une commande écrite sur deux lignes pouvait échapper à une règle « ne jamais faire ceci », plusieurs actions envoyées ensemble pouvaient sauter complètement les vérifications, et des mots de passe pouvaient finir écrits en clair dans l'historique des sessions. J'ai aussi fait en sorte que davantage de commandes dangereuses créent d'abord un point de restauration.

Ce que j'en retiens : dans un outil de sécurité, les cas bizarres sont le travail — le saut de ligne auquel personne ne pense est exactement ce qu'un attaquant essaie. Et un problème de sécurité mérite d'être signalé discrètement aux mainteneurs d'abord, même quand la correction est minuscule.


La suite de l'article entre dans les détails techniques, pour les développeurs.

Sous le capot

Un monorepo TypeScript (Apache-2.0) avec plus de 8 000 tests : hooks d'agents, proxy MCP, intercepteurs dans le PATH, proxy réseau local, journal d'audit et points de restauration basés sur git.

En détail : ce que j'ai apporté

Ma contribution en chiffres : 13 pull requests, 11 mergées.

Quand le rôle d'un projet est la sécurité, chaque bug est un contournement.

Un saut de ligne qui passait sous les règles de refus

Les jokers des politiques étaient compilés en .* sans le drapeau s — et en JavaScript, . ne correspond pas à \n. Une commande shell sur plusieurs lignes pouvait échapper à une règle de refus. La correction tient en un drapeau de regex. Je l'ai traitée comme une vulnérabilité : PR en brouillon, description publique minimale, et l'analyse complète envoyée en privé comme le demande la politique de sécurité.

Les lots JSON-RPC contournaient le pare-feu MCP

#89 : un message entrant était lu comme un seul objet JSON-RPC. Un lot est un tableau, il n'a pas de method, et il était simplement transmis — un tools/call dans un lot arrivait au serveur sans verdict et sans trace dans le journal. Les lots sont maintenant découpés, chaque appel est jugé dans l'ordre (pour que les demandes d'approbation arrivent dans l'ordre d'envoi), les appels autorisés repartent ensemble et les refusés reviennent en refus. La revue a montré que des lots imbriqués [[…]] passaient encore ; une vérification de type répond désormais -32600 Invalid Request.

Des requêtes prises pour des résultats

Client et serveur numérotent leurs ids indépendamment, mais les réponses étaient associées par id seulement. Une requête du serveur avec l'id 1 pouvait clôturer l'appel ouvert id 1 du client, et même effacer la liste des outils. Désormais, une réponse est un message sans method avec un result ou une error :

const isResponse = (m: JsonRpcMessage) =>
  m.method === undefined && (m.result !== undefined || m.error !== undefined);

Secrets et crashs

  • --password="correct horse battery staple" n'était masqué que jusqu'au premier espace.
  • Les transcriptions de session stockaient la sortie de l'agent en clair. Elles passent maintenant par un flux qui masque — ligne par ligne, parce que les découpages en chunks coupent les tokens, et avec un masque par flux (en partager un seul laissait fuir un morceau de mot de passe, comme l'a montré la revue).
  • N'importe quel processus local pouvait faire planter le proxy réseau avec %zz dans un en-tête ou une adresse IPv6.
  • shred, truncate ou git stash drop s'exécutaient sans point de restauration ; des clients de base de données comme mariadb, pgcli et redis-cli FLUSHALL n'étaient pas reconnus comme destructeurs.

Les leçons techniques

  • Dans un outil de sécurité, les cas limites sont le produit. Un saut de ligne, un tableau imbriqué, une collision d'ids : chacun permettait de contourner les règles. Je lis maintenant chaque format d'entrée en me demandant : « que fait le parseur avec la version bizarre ? ».
  • Connaître les comportements par défaut de son langage. Que . ne corresponde pas à \n est documenté, ancien, et facile à oublier. Les bugs les plus dangereux se cachent dans ce que tout le monde « sait ».
  • Lire le protocole, pas seulement le code. JSON-RPC autorise les lots ; les ids sont propres à chaque côté. La spécification m'a dit où chercher.
  • Signaler de façon responsable, même pour une ligne. Un petit correctif peut décrire un contournement. En dire moins en public et plus en privé ne coûte rien.
  • Dire ce que sa PR ne fait pas. Chacune de mes PR se terminait par une section « limites ». Elle répond aux premières questions du relecteur avant qu'il les pose — et m'oblige à être honnête sur ce qu'un test prouve vraiment.