SentinelloSentinello

Un système d'alerte précoce pour les dépendances que vous ne surveillez plus.

À l’ère de l’IA, vous livrez plus de projets que vous ne pouvez en maintenir. Sentinello surveille chacun d’eux et révèle les CVE connues dans leurs dépendances Node.js — pour qu’un projet oublié ne devienne jamais un incident.

Lancez-le en une seule commande :

docker run -d \
  --name sentinello \
  -p 127.0.0.1:3870:3000 \
  --stop-timeout 60 \
  -v sentinello-data:/app/data \
  -v sentinello-nvm:/home/sentinello/.nvm \
  -v ~/Developer:/roots/personal:ro \
  ghcr.io/walkofcode/sentinello:latest

Fonctionne sur linux/amd64 et arm64

Pas de compte. Pas de SaaS. Pas de télémétrie. Une image Docker et un fichier SQLite — votre code et vos résultats ne quittent jamais votre machine.

Ou passez-vous complètement du portail

Les mêmes scanners existent en CLI. Aucune installation, aucun compte, aucune base de données : elle s'exécute, imprime un avis exploitable par votre agent, puis se termine.

npx sentinello

En pipe, stdout ne transporte que le markdown, si bien que l'avis parvient intact à l'agent :

npx sentinello | claude -p "$(cat -)"

Parcourt le dossier

Pointez-la sur un répertoire et elle trouve chaque projet en dessous, en s'arrêtant à la racine de chacun pour qu'un monorepo compte une fois et non cinquante. .gitignore et .sentinelloignore sont respectés.

Interroge trois sources

Elle résout les versions exactes installées depuis le lockfile et les compare hors ligne à un cache d'avis local. Aucun appel réseau par projet, et rien de votre code n'est envoyé.

Écrit un avis

Un fichier markdown daté contenant les découvertes et un prompt de remédiation : trier avant de toucher à quoi que ce soit, préférer la mise à jour du parent aux overrides, vérifier les correctifs dans le lockfile.

En quoi elle diffère de npm audit

Elle ne remplace pas npm audit : elle exécute npm audit, puis ajoute deux sources d'avis que npm audit ne peut pas voir, en supprimant ce qu'elles dupliquent.

npm auditnpx sentinello
PortéeLe seul projet dans lequel vous vous trouvez.Tous les projets d'un dossier, en une passe et un seul rapport.
Sources d'avisLe flux d'avis de votre registre.Celui-ci, plus OSV et GitLab gemnasium. Les doublons sont supprimés : chaque source supplémentaire n'ajoute que des découvertes inédites.
Paquets malveillantsNon couvert.Les enregistrements MAL- d'OSV signalent les paquets publiés avec du code malveillant — typosquats, charges dans les scripts d'installation — comparés aux versions précisément compromises.
SortieUn tableau, ou du JSON à interpréter.Un avis markdown accompagné d'un prompt de remédiation, prêt à être confié à un agent.
CorrespondanceUn appel au registre par projet.Hors ligne, contre un cache local. La première exécution le télécharge après vous avoir demandé ; les suivantes ne transfèrent presque rien.

Ces sources supplémentaires ne sont pas une formalité. Sur le dépôt de Sentinello lui-même, npm audit et OSV rapportent chacun trois découvertes et s'accordent sur toutes, tandis que l'unique découverte critique provient de gemnasium, que ni l'un ni l'autre ne contient.

Fonctionnalités

Tout dans un portail auto-hébergé — aucun service externe, aucune donnée ne quitte votre réseau.

File de triage unique

Voyez et triez les CVE de tout votre parc de projets à un seul endroit — au lieu d'un npm audit éparpillé sur une dizaine de copies.

Parcourir par projet ou par bibliothèque

Plongez dans n'importe quel dépôt pour ses résultats, ses versions de correction et son historique — ou basculez vers un paquet vulnérable pour voir tous les projets qu'il affecte et le mettre en sourdine partout d'un coup.

Des résultats qui concordent

Quand plusieurs sources signalent la même vulnérabilité, cela reste un seul résultat — indiquant lesquelles concordent, noté au pire niveau attribué par l’une d’elles.

Analyse continue

Un processus en arrière-plan réanalyse selon une planification, pour que les nouveaux avis apparaissent sans que vous ayez à penser à vérifier.

Sources multiples

Au-delà de npm audit : comparaison avec OSV et gemnasium de GitLab pour une couverture CVE plus large et la détection de paquets malveillants connus.

Notifications et webhooks

Recevez des alertes d'échecs et de résultats via Slack, Telegram ou un simple webhook — ciblées par root ou par projet, dans la langue de votre choix. Payloads JSON ou texte brut pour un agent d'auto-correction.

Serveur MCP

Connectez Claude Desktop, Cursor et d'autres clients MCP pour interroger les résultats, projets et bibliothèques — et lancer des analyses — sans quitter le chat.

Export d'avis

Exportez les résultats d'un projet ou d'une bibliothèque en Markdown, avec une invite de remédiation personnalisable pour votre équipe ou un LLM.

Une image, un fichier

Une image Docker et un fichier SQLite. Pas de serveur de base de données, pas de file de messages, aucune dépendance au cloud.

Roots auto-enregistrés

Tout ce qui est monté sous /roots est enregistré et analysé au démarrage — le nom du répertoire devient son libellé.

Node par projet

Respecte le .nvmrc de chaque projet, en installant et en mettant en cache une seule fois la version de Node qu'il fixe.

10 langues

L'interface du portail, les codes de motif d'analyse et les statuts sont traduits en 10 langues.

Captures

Voyez-le en action — le portail analysant quelques projets de démonstration. Cliquez sur une capture pour l'agrandir.

Comparaison

Sentinello n’est ni un Dependency-Track plus lourd ni un Snyk moins cher. Il occupe une autre niche : la longue traîne des projets que personne n’a reliés à un pipeline.

SentinelloDependency-TrackSnykDependabot
Sans configuration — pointez vers un dossier~~
Aucun SBOM / étape CI requis
Analyse les lockfiles résolus réels~
Détection de paquets malveillants
Auto-hébergé, sans SaaS
Une image + SQLite
Natif pour l’IA (MCP + export)~
Polyglotte (Python, Go, …)
Politique d’entreprise / VEX~~

Dependency-Track ne voit que les projets que quelqu'un a instrumentés avec un pipeline SBOM. Sentinello trouve ceux que vous avez oubliés. Ils sont plus forts sur la politique d’entreprise — si vous les utilisez déjà sur un pipeline mature, gardez-les. Sentinello est là pour le reste de votre parc de projets que personne ne surveille.

Pourquoi nous l'avons créé

À l'ère de l'IA, vous livrez plus que vous ne pouvez maintenir.

Aujourd'hui, un dev en solo lance, livre et passe à autre chose sur une dizaine de projets par an — le site vitrine, le tableau de bord client, le projet perso passé discrètement en production. Les protéger, ça voulait dire se connecter en SSH à chaque copie pour lancer npm audit à la main, ou découvrir une CVE Next.js dans les gros titres plusieurs jours après sa sortie. Personne ne tient le rythme sur une dizaine de dépôts, alors ça n'arrive tout simplement jamais.

Il suffit d'une seule dépendance oubliée présentant une faille critique d'exécution de code à distance. Le site le plus simple, celui que vous avez cessé de surveiller, devient la porte d'entrée.

« Pourquoi ne pas simplement utiliser Snyk ou Dependabot ? » Ceux-là vivent à l'intérieur du pipeline CI que vous avez mis en place — et la longue traîne n'en a jamais eu. Sentinello est le système d'alerte précoce pour tout le reste : pointez-le vers un dossier et il surveille chaque projet que vous avez oublié, faisant remonter chaque nouvelle CVE dans une seule file avant qu'elle ne devienne un incident.

Comment ça marche

Trois étapes. Aucun agent à installer dans vos projets, aucun compte à créer.

Pointez-le vers votre code

Montez vos dépôts sous /roots, ou ajoutez-les depuis Paramètres → Roots. Chaque répertoire est enregistré et découvert automatiquement au démarrage.

Il analyse en continu

Un processus en arrière-plan compare vos dépendances aux CVE connues selon une planification, en installant la version de Node que chaque projet fixe lorsque c'est nécessaire.

Triage dans une seule file

Chaque résultat de chaque projet arrive dans une seule file que vous pouvez filtrer par gravité — avec des alertes optionnelles vers Slack, Telegram ou un webhook.

À qui ça s'adresse

Sentinello s'adresse à tous ceux qui ont plus en production qu'ils ne peuvent surveiller — la personne qui développe seule, la petite équipe, l'agence qui jongle avec le travail client.

  • Vous livrez des projets perso et des sites clients qui doivent rester sûrs longtemps après le lancement.
  • Vous voulez une vue d'ensemble du parc de projets sans câbler la CI dans chaque dépôt.
  • Vous préférez l'auto-hébergement plutôt que de confier l'inventaire de votre code à un SaaS.

Si vous êtes une grande organisation avec Snyk ou Dependabot déjà intégrés dans un pipeline mature, gardez-les — Sentinello ne cherche pas à remplacer le SCA d'entreprise. Il est là pour le reste de votre parc de projets que personne ne surveille. Il est open source et sous licence MIT, vous pouvez donc lire exactement ce qu'il fait.

Notes de version

Sentinello évolue régulièrement — voici ce qu'a apporté chaque version.

Un tableau de bord où une seule source parlait pour tout le projet

v3.5.0 · 20 août 2026
  • La colonne <strong>État</strong> du tableau de bord rapportait une seule source et jetait les autres. Chaque analyse écrit une ligne par source et elles se terminent à quelques millisecondes d’intervalle, donc la colonne affichait celle qui finissait en dernier — en pratique toujours OSV. Tous les projets affichaient « Base de données OSV pas encore téléchargée » alors que npm audit les avait analysés correctement et avait trouvé de vraies vulnérabilités. État porte désormais un badge par source incapable de répondre, chacun nommant la source, et n’affiche rien quand toutes les sources activées vont bien. L’historique des analyses a gagné une colonne <strong>Source</strong> pour la même raison : un balayage écrivait trois lignes identiques sans moyen de les distinguer.
  • Paramètres → Sources prétendait qu’un cache était à jour pendant sa reconstruction. L’état lu par le portail n’était écrit qu’à la fin d’une synchronisation, donc pendant toute une reconstruction de plusieurs minutes il continuait d’afficher le décompte d’avant — alors que chaque analyse refusait à juste titre le cache à moitié effacé. Il ne portait pas non plus la version du normaliseur, que le scanner exige, donc un changement de version produisait la même fausse affirmation sans aucune reconstruction. La ligne indique maintenant <strong>Reconstruction…</strong> avec le décompte précédent atténué, ou <strong>Reconstruction en attente</strong> quand un cache est inutilisable et que rien n’y remédie.
  • Un cache qui finissait de se télécharger laissait chaque projet bloqué sur le verdict obtenu pendant son absence. Rien ne relançait d’analyse, donc <code>osv_db_not_seeded</code> restait là jusqu’au balayage planifié suivant, ou jusqu’à ce que vous le remarquiez et lanciez une analyse. Sentinello met désormais en file une analyse complète dès qu’un cache redevient utilisable. Une mise à jour incrémentale ne met rien en file. La mise à jour compte : si cette version arrive sur une instance dont les projets portent encore ce verdict d’avant la fin du téléchargement, le worker repère la contradiction à son premier démarrage et la corrige pour vous — aucune analyse à penser à lancer.

Un avis qui signalait la version qui le corrigeait

v3.4.0 · 18 août 2026
  • gemnasium écrit un petit nombre d’avis avec une espace entre le comparateur et sa version — <code>&lt; 0.5.2</code> au lieu de <code>&lt;0.5.2</code> — et l’analyseur lisait cette paire comme deux jetons distincts. Le <code>&lt;</code> orphelin recevait une borne vide, et la version restée seule était mise en cache comme version exacte. L’avis <code>fresh</code> signalait donc la 0.5.2 comme vulnérable alors que 0.5.2 est justement la version qui l’a corrigé, et le signalait sans correctif disponible, puisqu’une version épinglée ne porte aucune cible de mise à jour. 19 avis sont écrits ainsi et tous étaient mal analysés : 15 perdaient entièrement leur plage, et 7 épinglaient une version que l’enregistrement lui-même donne comme correctif — <code>pg</code> en épinglait onze.
  • Sentinello a cessé d’interpréter lui-même la syntaxe des plages npm et confie désormais chaque plage à l’implémentation de npm, ce qui élimine d’un coup toute une famille de mauvaises lectures. Pour npm, <code>&lt;=3.3</code> signifie « jusqu’à la fin de la ligne 3.3 » — lu au pied de la lettre, il s’arrêtait à 3.3.0 et manquait la 3.3.1, ce qui correspond à un avis réel de <code>converse.js</code> — et <code>=103</code> désigne toute la ligne 103 plutôt qu’un point unique, ce que <code>binaryen</code> énonce huit fois. Les plages avec accent circonflexe, tilde, <code>1.x</code> et trait d’union sont désormais lues elles aussi, alors qu’auparavant un enregistrement écrit dans l’une d’elles était écarté sans un mot. Vérifié sur les 4 696 plages de versions distinctes que gemnasium publie pour npm : les interpréter nous-mêmes divergeait de npm sur 9, déléguer ne diverge sur aucune. Seul npm est concerné — en Python, <code>==1.0</code> est une version exacte et non un joker, si bien qu’y appliquer la règle de npm inventerait des résultats.
  • Trois choses que la lecture de npm réussit pour installer un paquet et rate pour un avis sont retenues. Une plage ne nommant aucune version — <code>*</code>, <code>x</code>, un champ vide — signifie « n’importe quelle version » quand npm installe quelque chose et « personne n’a rempli ceci » dans un avis : elle est donc refusée plutôt que transformée en un résultat contre toutes les versions jamais publiées. Un <code>||</code> traînant ne peut plus élargir à tout la plage qui le précède. Et <code>&gt;0</code> continue de signifier toutes les versions, car <code>pandora-doomsday</code> déclare ainsi son paquet malveillant et la lecture de npm laverait tout le 0.x. Par ailleurs, un avis dont le correctif annoncé se situe au niveau du début de sa propre plage affectée ou en dessous ne se voit plus substituer cette borne — cela produisait un intervalle ne correspondant à rien, autrement dit un résultat qui cesse silencieusement de signaler — et la règle écartant un tel intervalle est désormais partagée avec la source OSV au lieu d’être écrite une fois par source, ce qui est précisément la raison de leur désaccord initial.
  • Les tests qui passaient à côté de tout cela génèrent désormais leurs entrées au lieu de les énumérer. Chaque plage de versions distincte que gemnasium publie pour npm est vérifiée contre l’implémentation de npm à chaque compilation, aux côtés du produit cartésien complet de la grammaire des plages et de tous les ordonnancements des événements de plage d’OSV. Exécuté sur la version précédente, ce balayage échoue sur 28 plages, alors que les dix exemples écrits à la main qu’il remplace passaient tous. Toute graphie inventée en amont à partir de maintenant fera échouer la compilation dès son premier import, et non le jour où quelqu’un remarquera le résultat qu’elle a produit.
  • Chaque ligne du code qui produit ces résultats est désormais exercée par la suite de tests : instructions, branches, fonctions et lignes à 100 %, sans aucune exemption dans le dépôt. C’est la réponse directe à la façon dont les bogues des dernières versions sont passés : chacun était une branche que rien n’exécutait, signalant un succès sans rien faire. Fermer les 109 derniers en a révélé plusieurs classés comme garde-fous inatteignables alors qu’ils n’étaient tout simplement pas testés, ainsi qu’une règle de couverture qui ne vérifiait plus rien depuis que le fichier qu’elle nommait avait été déplacé. Cette règle et les 500 lignes d’exceptions qui l’entouraient sont remplacées par une seule, si bien qu’un code non testé fait maintenant échouer la compilation au lieu d’abaisser une moyenne.
  • Les dernières lacunes défensives sont également fermées : une borne supérieure OSV illisible laisse l’intervalle valide ouvert, les bornes de secours sont vérifiées après leur application et une borne de préversion npm explicite comme <code>&lt;1.2.3-0</code> conserve son sens exact.

Des avis qui déclaraient toutes les versions vulnérables

v3.3.2 · 17 août 2026
  • Un avis dont la plage affectée n’a pas de fin correspond à toutes les versions, indéfiniment : un résultat qu’aucune mise à jour ne peut lever et que rien ne distingue, à l’écran, d’une vulnérabilité réellement non corrigée. Deux avis <code>xlsx</code> se présentaient ainsi et signalaient une version 0.20.3 pourtant entièrement corrigée comme sévérité haute et sans correctif, sur 11 projets à la fois, alors que <code>npm audit</code> rapportait correctement ces deux mêmes avis comme corrigés en 0.19.3 et 0.20.2. La cause est en amont et délibérée : GitHub ne nomme pas une version corrigée que le registre ne distribue pas sous ce nom de paquet — SheetJS ne publie 0.19.3 et les suivantes que depuis son propre CDN — et écrit donc la plage comme « tout à partir de 0 », en consignant la vraie borne dans un autre champ que Sentinello ne lisait pas. Il le lit désormais. 15 avis npm étaient concernés, dont <code>babel-traverse</code> et <code>sandbox</code>. Les 480 qui sont réellement sans correctif le disent toujours, et un enregistrement qui énonce déjà sa propre borne n’est jamais écrasé
  • Un avis gemnasium qui laissait sa plage ouverte tout en énumérant les versions qui le corrigent est désormais borné par la plus élevée d’entre elles. Une plage sans fin affirme que les versions à venir sont vulnérables elles aussi, ce qu’aucun enregistrement nommant un correctif ne peut vouloir dire
  • gemnasium écrit les plages de versions Python sous forme d’intersections PEP 440 — <code>&gt;=5.0,&lt;5.8</code> — et l’analyseur ne découpait les jetons que sur les espaces : l’ensemble n’en formait plus qu’un, avec une borne inférieure illisible et aucune borne supérieure. Une telle plage ne correspond à rien, et ne correspondre à rien revient à ne rien signaler. 2 830 des 7 159 enregistrements PyPI en cache étaient dans cet état. C’était l’une des trois raisons du retrait de Python, Go et Rust en 3.3.0 ; les deux autres restent ouvertes, ils demeurent donc retirés

La même version que 3.3.0, avec une image Docker qui se construit

v3.3.1 · 15 août 2026
  • 3.3.0 a été publiée sur npm et GitHub, mais son image de conteneur n’a pas pu être construite : au moment de la sortie, il n’y avait donc pas de 3.3.0 sur GHCR ni sur Docker Hub. Le Dockerfile énumère chaque paquet du workspace qu’il installe, et l’un d’eux — celui de comparaison de versions — n’y avait jamais figuré. Rien dans l’image ne l’importait avant cette version, si bien que l’oubli n’avait jamais eu de conséquence. Une image 3.3.0 corrigée a depuis été publiée, construite à partir du code applicatif de 3.3.0 lui-même : <code>docker pull sentinello:3.3.0</code> fonctionne de nouveau. La 3.3.1 porte le même correctif dans l’arbre des sources. Si vous utilisez la CLI, 3.3.0 était déjà correcte.

Uniquement les écosystèmes qui fonctionnent vraiment — et des notifications fiables

v3.3.0 · 15 août 2026
  • Une notification pouvait arriver vide. Un opérateur a reçu un message Telegram annonçant des vulnérabilités dans un projet, sans en lister aucune. L’envoi est délimité par projet mais s’exécutait une fois par scanner : la passe de npm audit s’est vu remettre deux événements OSV en attente, n’en a fait correspondre aucun, et a tout de même affiché le titre au-dessus d’une liste vide. Elle a ensuite marqué les deux événements comme livrés — les deux résultats jamais nommés ont donc été enregistrés comme notifiés, et rien ne revient sur un événement livré. Un événement n’est désormais envoyé que s’il peut être décrit ; sinon il reste en attente et est réexaminé au prochain scan
  • Un résultat est signalé au pire niveau attribué par une source, et cette escalade atteignait le tableau de bord, les totaux par projet et la barrière <code>--fail-on</code> de la CLI — mais pas les seuils de notification. La notification s’exécutait avant la corroboration : l’événement portait donc le niveau de la source survivante et n’était jamais réécrit. Sur une instance réelle, 135 résultats ouverts portaient une sévérité d’événement inférieure à la vraie, <strong>dont 41 enregistrant un critique en faible, élevé ou moyen</strong>. Une cible filtrée sur critique et élevé n’aurait jamais été alertée pour aucun d’entre eux, définitivement
  • Les analyses planifiées s’arrêtaient à minuit au lieu de repartir. « Toutes les 3 heures à partir de 07:00 » s’exécutait à 07, 10, 13, 16, 19 et 22, puis plus rien jusqu’à 07:00 — six analyses par jour au lieu de huit, avec une fenêtre aveugle de neuf heures chaque nuit — pendant que les Paramètres continuaient d’afficher l’intervalle choisi. « Toutes les 6 heures à partir de 20:00 » n’en faisait qu’une par jour. Les créneaux repassent désormais au jour suivant
  • <strong>Python, Go et Rust ont été retirés.</strong> Ce n’est pas de la prudence face à des aspérités : leurs défaillances se signalaient comme « sain ». La dérivation des correctifs et l’ordonnancement des versions sont uniquement semver, si bien qu’un avis OSV sur Django recommandait « passer à 3.2.23 » contre un 4.2 installé ; les noms de paquets PyPI d’OSV ne sont pas canonicalisés selon PEP 503 et ne rejoignaient donc jamais ceux du résolveur ; et l’analyseur de plages de gemnasium ne sait pas lire les intersections à virgule de PEP 440. Une source qui répond « aucune vulnérabilité » pour de mauvaises raisons est pire qu’une source non proposée : elles ont donc entièrement disparu de la surface du produit — pas de bouton, pas de découverte, pas de téléchargement. <strong>Les résultats déjà collectés avec elles restent visibles et peuvent être mis en sourdine ; rien n’est supprimé.</strong> L’écosystème npm s’appelle désormais <strong>Node.js</strong>, ce qui nomme l’écosystème de paquets réellement analysé plutôt qu’un langage
  • <strong>Paramètres → Sources</strong> a été refait en conséquence. Chaque source répétait sa propre explication à côté de son propre interrupteur, et chaque source à cache portait un panneau d’état de cinq lignes avec son propre bouton « Actualiser » en pleine taille — alors que ce bouton met en file un unique signal partagé par source, quel que soit le nombre d’occurrences. Les interrupteurs ne disent plus que si une source est active ; ce que chacune apporte, ce qu’elle télécharge et depuis où, et quand elle s’exécute sont passés dans un tableau de référence unique en dessous, et l’état de synchronisation tient désormais sur une ligne
  • Des paquets que le lockfile de npm lui-même déclare atteignables depuis la production étaient rétrogradés en dev seulement. Un lockfile qui omet <code>dev: true</code>, c’est npm affirmant que le paquet EST atteignable depuis la production — une affirmation plus forte que ce que le manifeste racine peut dire — mais le résolveur l’écrasait dès que le nom apparaissait aussi sous <code>devDependencies</code>, c’est-à-dire précisément quand npm avait raison. Mesuré sur 130 projets réels : 142 paquets rétrogradés dans 97 d’entre eux — lodash, semver, postcss, tailwindcss, @babel/runtime — masquant sept résultats ouverts au filtre production seule sur une instance
  • Tout paquet épinglé à une version comme <code>0.0.0-20180523222229-09b5706aa936</code> ne correspondait à <strong>aucun avis</strong>, pas même un avis ouvert, et l’analyse signalait « ok » avec zéro résultat. Une borne d’avis <code>introduced: 0</code> était comparée à la release 0.0.0, et en semver une préversion se classe sous sa release. 330 des 19 085 plages comparables d’un cache réel étaient stockées comme des intervalles que rien ne pouvait satisfaire
  • Une synchronisation OSV interrompue pouvait effacer un avis définitivement. Le chemin incrémental supprimait les lignes d’un avis puis récupérait le remplacement dans un try/catch : le moindre timeout, 5xx ou arrêt le supprimait purement et simplement — puis le curseur avançait quand même, laissant l’identifiant définitivement derrière lui. La perte était silencieuse, survivait jusqu’au prochain réamorçage complet, et se produisait lors d’une synchronisation signalée comme réussie. Le cache de <code>npx sentinello</code> s’érodait de la même façon à chaque exécution instable. Les deux récupèrent maintenant avant de remplacer
  • Le <code>--dep-type dev</code> de la CLI signifiait « atteignable depuis dev, d’une manière ou d’une autre », alors que le portail signifie « atteignable <em>uniquement</em> depuis dev » : un paquet atteignable depuis les deux apparaissait dans une vue et pas dans l’autre — 177 résultats ouverts diffèrent entre les deux lectures sur une instance. La CLI applique désormais la règle du portail, et respecte le champ <code>withdrawn</code> d’OSV, qu’elle était structurellement incapable de lire : 585 lignes d’un cache npm réel en portent un, et toutes étaient signalées comme des résultats actifs
  • Un avis gemnasium indiquant qu’une vulnérabilité commence <em>après</em> une version — <code>&gt;1.2.8</code> et non <code>&gt;=1.2.8</code> — était lu comme si la version limite elle-même était touchée. Le détournement du paquet <code>rc</code> en 2021 est écrit exactement ainsi, et 1.2.8 en est la dernière version saine : précisément celle que la note de remédiation de l’avis vous dit de conserver. Tout projet ayant <code>rc</code> installé voyait une alerte critique de malware, sans correctif disponible, sur une version qui n’a jamais été compromise. Les bornes sont désormais conservées telles que l’avis les énonce, et les faux critiques de cette forme disparaissent
  • Le même arrondi jouait dans l’autre sens et masquait de vraies détections. Un avis borné par <code>&lt;=2.0.0</code> était stocké comme « en dessous de 2.0.0 », donc 2.0.0 — la version sur laquelle il est le plus explicite — n’était pas signalée, et un avis ne nommant qu’une seule version affectée devenait un intervalle vide et était rejeté en entier. Attendez-vous à quelques détections nouvelles, présentes depuis toujours mais invisibles
  • Les plages écrites avec une syntaxe que Sentinello n’implémente pas — <code>^1.0.0</code>, <code>~1.0.0</code> — étaient stockées comme une version exacte figée sur le texte littéral, incapable de correspondre à quoi que ce soit tant qu’elle restait en cache : un avis d’apparence active mais qui ne pouvait jamais se déclencher. Ces enregistrements sont désormais refusés plutôt que conservés sous une forme inopérante, et les avis dont la borne supérieure n’a pas de version corrigée nette reçoivent enfin une suggestion de mise à niveau
  • L’assistant qui masque une URL de webhook ou un jeton de bot avant qu’il n’atteigne une ligne de log affichait les courts en entier. Il rejetait les valeurs de six caractères ou moins, mais conservait ensuite une tête de huit caractères et une queue de quatre, et rien ne vérifiait que ces deux moitiés ne se rejoignaient pas — tout secret de 7 à 12 caractères revenait donc complet. Il masque désormais au moins huit caractères, ou expurge la valeur entièrement

Les résultats indiquent quelles sources concordent, et les avis retirés ne sont plus signalés

v3.2.0 · 15 août 2026
  • Lorsque plusieurs bases d’avis signalent la même vulnérabilité, Sentinello n’a jamais conservé qu’un seul résultat : signaler trois fois la même faille parce que trois bases la connaissent, c’est du bruit. Mais tout ce qui concernait les sources fusionnées était jusqu’ici écarté, si bien qu’une vulnérabilité confirmée indépendamment par npm audit, OSV et GitLab gemnasium ressemblait exactement à une que seule une base avait jamais signalée. Sur une instance réelle, cela représente deux tiers des résultats. Chaque résultat porte désormais les autres sources qui l’ont signalé, et leurs badges apparaissent à côté de celui qui a survécu
  • Un résultat est signalé avec la sévérité LA PLUS ÉLEVÉE attribuée par une source. Les bases divergent réellement — gemnasium calcule la sévérité à partir du vecteur CVSS tandis que npm audit reprend la catégorie de GitHub — et pour un scanner, c’est la lecture prudente qu’il faut retenir. Ce n’est pas cosmétique : un résultat réévalué change de catégorie sur le tableau de bord, dans les totaux du projet, dans la barrière <code>--fail-on</code> de la CLI et dans les seuils de notification. Attendez-vous à des décomptes différents lors du premier scan après la mise à jour ; rien de nouveau n’a été détecté, les mêmes résultats sont simplement évalués avec plus de prudence
  • Là où les sources divergent, le résultat affiche à côté de sa sévérité un contrôle qui ouvre ce que chacune a réellement dit : son propre identifiant d’avis et sa propre évaluation. Il n’apparaît que lorsqu’il y a un désaccord à expliquer, de sorte qu’un résultat évalué de la même façon par tous reste épuré
  • OSV consigne un retrait dans un champ dédié et GitHub supprime les avis retirés avant même que <code>npm audit</code> ne les voie, mais GitLab gemnasium n’a pas ce champ dans son schéma. Il retire un avis en réécrivant l’enregistrement : le titre devient « False Positive », « Withdrawn Advisory: … » ou « Duplicate Advisory: … », tandis que les versions qu’il désignait restent en place. Sentinello lisait ces versions et signalait des résultats que GitLab avait explicitement retirés : 383 enregistrements pour JavaScript, Python, Go et Rust, dont un qui signalait <code>express</code> sous le titre « False Positive ». Tous sont désormais écartés, ce qui supprime aussi toute une catégorie de doublons, puisque 278 des 383 sont des avis retirés parce qu’ils faisaient doublon
  • La détection compare les marqueurs de retrait exactement plutôt que de chercher les mots n’importe où, si bien qu’un avis authentique portant *sur* un faux positif continue d’être signalé : le CVE-2026-39395 de Cosign, intitulé « Cosign’s verify-blob-attestation reports false positive when payload parsing fails », n’est pas affecté
  • Le cache gemnasium se reconstruit de lui-même à sa première synchronisation après cette mise à jour ; les avis retirés disparaissent alors. Rien à faire : cela se produit lors de la synchronisation quotidienne, ou immédiatement depuis Paramètres → Sources → Actualiser

Les plages de versions des avis sont justes dans les deux sens

v3.1.1 · 14 août 2026
  • Certains avis GitLab gemnasium ne fournissent aucune plage de versions exploitable — 698 des 10 777 avis JavaScript. Sentinello comblait ce vide en supposant que toutes les versions antérieures au premier correctif listé étaient touchées, mais cette liste n’est pas triée et contient un correctif par branche de publication : la supposition tombait donc souvent sur la mauvaise branche. protobufjs 7.6.5 était signalé comme exécution de code à distance critique alors que cette branche avait été corrigée en 7.5.5, et trois avis distincts affirmaient chacun que toutes les versions de vite antérieures à 8.0.5 étaient vulnérables. Sentinello n’invente plus de plage : il récupère la vraie depuis le même avis publié sous son autre identifiant, depuis la description de l’avis, ou — uniquement si OSV est activé — depuis la copie OSV déjà présente sur votre machine, et il écarte l’enregistrement plutôt que de deviner lorsque aucune de ces sources ne répond. Attendez-vous à voir disparaître certains critiques
  • OSV décrit un avis corrigé sur plusieurs branches par une entrée distincte pour chaque branche, et Sentinello gardait la première en écartant les autres — 1 927 plages de versions vulnérables pour le seul JavaScript, chacune une vulnérabilité réelle devenue invisible. L’avis minimatch couvre huit branches et une seule survivait : un minimatch 3.0.4 ou 9.0.0 installé n’était pas signalé ; next et ua-parser-js perdaient des branches de la même façon. Toutes les branches sont désormais conservées. Attendez-vous à voir apparaître de nouveaux résultats — ces vulnérabilités étaient déjà là, simplement invisibles
  • Les deux caches d’avis se reconstruisent d’eux-mêmes à leur première synchronisation après cette mise à jour, car les plages qu’ils contiennent ont été produites par l’ancien code. Rien à faire : cela se produit lors de la synchronisation quotidienne, ou immédiatement depuis Paramètres → Sources → Actualiser si vous préférez ne pas attendre

Les résultats masqués s’effacent, et la base de données cesse de grossir sans fin

v3.1.0 · 13 août 2026
  • Un résultat masqué est une décision que vous avez déjà prise : il quitte donc entièrement la page du projet au lieu d’y rester grisé. Ce n’est pas qu’une question de propreté — tous les chiffres de la page (le total du titre, les badges des deux onglets, la pagination, les totaux par bibliothèque, le bouton d’export) sont calculés à partir des mêmes lignes, si bien que la page s’accorde enfin avec le tableau de bord, les outils MCP et l’export d’avis, qui excluaient déjà les résultats masqués. Une case « Afficher les masqués » les ramène quand vous le souhaitez, y compris sur un projet dont *tous* les résultats sont masqués
  • Taper dans une boîte de dialogue ne fait plus perdre le focus au bout d’un seul caractère. Ce défaut rendait le champ Motif du dialogue de masquage — obligatoire, et seul élément qui rende un masquage vérifiable des mois plus tard — pratiquement impossible à remplir. Ce même dialogue n’hérite plus non plus de l’alignement de la ligne de tableau depuis laquelle il était ouvert, ce qui explique qu’un masquage de vulnérabilité s’affichait aligné à droite alors qu’un masquage de projet non
  • L’historique des analyses ne grossit plus indéfiniment. Rien n’avait jamais supprimé une ligne d’analyse selon son âge : un projet resté sur le disque accumulait donc une ligne par source et par passage, sans limite — une instance réelle a atteint 2,2 Go en moins de trois mois. Paramètres → Avancé propose désormais une durée de conservation, 90 jours par défaut, et le worker purge au-delà toutes les heures en gardant toujours les 100 analyses les plus récentes de chaque projet. Les résultats, les masquages et l’historique des notifications ne sont jamais touchés ; seul le journal d’analyse l’est. À 90 jours, une instance qui se met à jour ne supprime rien lors de son premier passage : la purge ne commence que lorsque l’historique dépasse réellement cette durée, ou lorsque vous l’abaissez vous-même
  • L’essentiel de cette croissance venait de la sortie brute de `npm audit`, conservée intégralement à chaque analyse réussie et lue par absolument rien : 98,7 % de la base de données de cette instance. Les analyses enregistrent désormais un court résumé, ce qui fait passer une ligne d’environ 79 Ko à une centaine d’octets, avec un plafond strict pour qu’aucun scanner ne puisse recommencer
  • Côté MCP, `get_dashboard_summary` précise maintenant qu’un projet que vous avez masqué sort de ses totaux alors que `list_projects` le renvoie toujours. Les deux comptent volontairement des populations différentes, et un agent qui les comparait y voyait un défaut. `list_scans` a également cessé de renvoyer la sortie brute du scanner pour chaque analyse, qui pouvait atteindre environ 16 Mo dans une seule réponse

Le téléchargement gemnasium fonctionne de nouveau, et la CLI rend la main

v3.0.1 · 4 août 2026
  • Le téléchargement de GitLab gemnasium échouait en 3.0.0 avec `HTTP 406`, pour tout le monde. Le fetch intégré de Node ajoute un en-tête `Sec-Fetch-Mode: cors` qu’un programme n’a pas le droit de retirer, et GitLab refuse toute requête d’archive de dépôt qui le porte — cela n’a donc jamais eu de rapport avec votre réseau, votre IP ou le nombre de tentatives. Le téléchargement utilise désormais une simple requête HTTPS, et aboutit
  • L’archive est récupérée par identifiant de commit plutôt que par nom de branche : tous ceux qui partent du même commit amont partagent une copie mise en cache au lieu de demander chacun à GitLab de construire une archive de 60 Mo. Un premier téléchargement qui prenait près de sept minutes se termine maintenant en quelques secondes
  • La CLI terminait tout son travail — rapport écrit, résumé affiché — puis ne rendait jamais le terminal. La connexion du téléchargement restait ouverte derrière elle et maintenait le processus en vie ; elle est désormais fermée dès que l’archive a été lue
  • Une source qui refuse un téléchargement ne bloque plus trois minutes avant de le signaler. Elle le signale en quelques secondes et, dans un terminal, propose de réessayer — en ne réessayant que la source réellement en échec
  • `--fail-on` est honnête dans les deux sens. Il refuse une exécution dont une source d’avis n’a pas pu être consultée, au lieu d’annoncer une analyse propre qu’il n’a jamais faite ; et il ne fait plus échouer une exécution à cause d’une source que vous avez vous-même désactivée avec `SENTINELLO_OSV_FEED_URL=off` ou `SENTINELLO_GEMNASIUM_FEED_URL=off` et jamais téléchargée

Sentinello fonctionne désormais sans portail du tout

v3.0.0 · 3 août 2026
  • Les scanners sont publiés en CLI sur npm. `npx sentinello` parcourt un dossier, trouve tous les projets qu’il contient, les confronte à npm audit, OSV et GitLab gemnasium, et écrit un avis markdown accompagné d’un prompt de remédiation — sans installation, sans compte, sans base de données, et rien de votre code ne quitte la machine
  • En pipe, l’avis est la seule chose sur stdout : `npx sentinello | claude -p "$(cat -)"` remet à un agent une liste de travail complète sans que rien ne corrompe le document
  • Une première exécution ne perd plus la source gemnasium à cause d’un téléchargement refusé. GitLab refuse son archive une à deux minutes d’affilée, et l’ancienne logique abandonnait au bout de treize secondes ; la CLI patiente désormais, explique pourquoi, et accepte `--feed-wait` si les trois minutes par défaut ne conviennent pas
  • Les deux estimations de téléchargement ont été mesurées plutôt que devinées : l’export npm d’OSV est annoncé à 204 Mo au lieu de 196, et l’archive gemnasium à 52 Mo au lieu de 80. L’invite de consentement marque une estimation d’un tilde pour qu’elle ne soit jamais prise pour une taille annoncée par le serveur
  • Une valeur ressemblant à une option est désormais rejetée plutôt que prise au pied de la lettre — `--out --` écrivait un avis dans un fichier nommé `--` au sein de votre projet, en signalant une réussite
  • Le panneau Nouveautés ne déborde plus du bas de la fenêtre quand une version a beaucoup à dire

Le document d’avis arrive enfin — et compte ce qu’il faut

v2.6.0 · 29 juil. 2026
  • get_project_advisory renvoie désormais le document lui-même. Les clients connectés ne recevaient jusqu’ici que ses métadonnées — un nom de fichier et un décompte — et jamais le document, alors que l’outil le présentait comme une liste de travail complète
  • L’export d’avis contient désormais une entrée par avis distinct, sources fusionnées, au lieu d’une par ligne de scanner : une vulnérabilité signalée à la fois par npm audit et OSV devient un seul élément de travail portant les deux identifiants, et non deux quasi identiques. Cela vaut aussi pour le bouton Télécharger .md du portail, et le décompte correspond maintenant à celui du tableau de bord
  • Un projet trop volumineux pour tenir dans une seule réponse MCP est désormais paginé : le document indique qu’il est incomplet et donne l’appel exact pour récupérer la suite, au lieu d’être tronqué en silence là où un agent lirait le reste comme sain
  • Chaque paramètre de chaque outil MCP est désormais décrit, et le nouvel outil list_mutes expose les identifiants de mise en sourdine dont unmute a besoin — auparavant accessibles uniquement en créant la mise en sourdine dans la même session
  • Correction d’une faille dans les décomptes de gravité : un signalement dont la gravité ne faisait pas partie des cinq valeurs connues était compté comme signalement mais rangé dans aucune catégorie, si bien qu’un projet dont c’était le seul signalement paraissait parfaitement sain

L’export d’avis, directement via MCP

v2.5.0 · 28 juil. 2026
  • Les clients MCP connectés peuvent récupérer l’avis Markdown complet d’un projet avec le nouvel outil get_project_advisory — le même document que le bouton Télécharger .md du portail, sans le copier depuis le navigateur
  • Les découvertes masquées sont désormais exclues de l’export d’avis du projet : un agent ne se voit donc jamais confier un travail dont vous avez déjà accepté le risque
  • Remarque : comme l’avis contient votre prompt d’export, un client MCP peut désormais lire ce que vous avez écrit dans Paramètres → Export

Des popups qui ne sont plus rognés et un prompt d’export plus strict

v2.4.3 · 26 juil. 2026
  • Les menus déroulants, le popover de chemin de dépendance et le menu d’export d’avis ne sont plus rognés par le tableau ou la boîte de dialogue qui les contient : ils s’affichent au-dessus de la page et basculent vers le haut lorsqu’il n’y a pas de place en dessous
  • Le prompt d’export d’avis par défaut demande désormais à l’agent de planifier avant toute modification, de regrouper les résultats qui partagent un même correctif et de détailler l’impact sur le code de chaque montée de version ; il vise zéro résultat tout en écartant les raccourcis vers un faux zéro — mise en sourdine, élargissement des plages ou réduction du périmètre d’analyse — et fait figurer ce qui reste réellement bloqué dans un tableau de résidus daté

La branche dans sa propre colonne

v2.4.2 · 25 juil. 2026
  • La branche git sur laquelle un projet a été analysé occupe désormais sa propre colonne dans la liste des projets — texte brut, sans icône — au lieu d’être placée sous le nom du projet

Arrêts propres

v2.4.1 · 25 juil. 2026
  • Redémarrer le conteneur n’interrompt plus une analyse en cours d’écriture, et le worker démarre immédiatement au lieu de réessayer pendant environ 30 secondes
  • Définissez stop_grace_period : 60s (ou --stop-timeout 60) dans votre fichier compose pour lui laisser la place — le README et la documentation Docker l’expliquent désormais

Analyse polyglotte — Python, Go et Rust rejoignent npm

v2.4.0 · 25 juil. 2026
  • Sentinello analyse désormais les projets Python, Go et Rust en plus de npm — les fichiers de verrouillage sont résolus entièrement hors ligne, et chaque projet indique sa couverture d’analyse (complète, partielle ou non auditable) afin que les lacunes soient visibles plutôt que silencieuses
  • La base gemnasium de GitLab rejoint npm audit et OSV comme source d’avis hors ligne, dédupliquée par rapport aux autres via les alias CVE/GHSA ; Paramètres → Sources devient une matrice Langages × Sources avec une portée de notification par cellule, et npm audit peut désormais être désactivé tant qu’une source reste active
  • Les résultats enregistrent désormais la branche git dont ils proviennent, affichée dans la liste des projets, l’en-tête du projet et chaque notification
  • Les lignes de projet portent leurs propres actions — analyser maintenant, copier ou télécharger l’avis, mettre en sourdine ou réactiver, et modifier les tags — si bien qu’une passe de triage n’oblige plus à ouvrir chaque projet
  • Le tableau de bord des projets est passé d’environ 3,3 s à 0,03 s, et la navigation affiche désormais des états de chargement au lieu de paraître figée
  • Sécurité : 25 avis de dépendances corrigés, dont des CVE libvips actives dans l’optimiseur d’images du portail et neuf avis Next.js affectant le portail livré
  • Le prompt d’export d’avis par défaut couvre désormais l’âge minimal de publication, la vérification du fichier de verrouillage et les overrides obsolètes

Configuration MCP simplifiée, sans variables d’environnement

v2.3.0 · 9 juin 2026
  • Configurez MCP entièrement dans Paramètres → MCP : générez un jeton pour activer le point de terminaison /api/mcp, effacez-le pour le désactiver — les variables d’environnement SENTINELLO_MCP_ENABLED et SENTINELLO_MCP_API_TOKEN ont disparu (un jeton d’environnement existant est importé une fois lors de la mise à niveau)
  • Extraits de connexion prêts à coller pour Claude Code, Codex, Cursor et Claude Desktop, pré-remplis avec votre jeton
  • Lorsque SENTINELLO_PORTAL_BASE_URL est définie dans l’environnement, elle s’affiche en lecture seule dans Paramètres → Avancé, car elle reste prioritaire et est réappliquée à chaque démarrage

Moins de fausses alertes et des résultats qui se nettoient seuls

v2.2.0 · 9 juin 2026
  • Les avis de malware correspondent désormais à la version compromise exacte — une version saine ou déjà corrigée d’un paquet autrefois compromis n’est plus signalée
  • Les résultats en double se résolvent désormais d’eux-mêmes au prochain scan, si bien que les entrées anciennes ou orphelines disparaissent automatiquement
  • Les étiquettes production et développement sont désormais calculées d’une seule façon cohérente pour toutes les sources (npm et OSV)

Un en-tête de projet plus épuré et des filtres cohérents

v2.1.0 · 6 juin 2026
  • En-tête de projet simplifié — renommez à côté du titre, avec la mise en sourdine et les tags en icônes
  • Filtrez les résultats par source (npm / OSV) depuis un nouveau menu déroulant à côté du filtre de type de dépendance
  • Menus déroulants unifiés et cohérents dans toute l’application, avec recherche instantanée sur les longues listes comme les fuseaux horaires

Conseils de mise à niveau plus clairs

v2.0.1 · 4 juin 2026
  • Étapes de mise à niveau détaillées pour les changements incompatibles de la 2.0
  • Le README indique la liaison du port en localhost uniquement

Analyse multi-source et une installation renforcée, sécurisée par défaut

v2.0.0 · 4 juin 2026
  • OSV comme deuxième source optionnelle (Paramètres → Sources, désactivée par défaut) avec détection des paquets malveillants, comparée à la base de données publique OSV dans un cache local
  • Les résultats sont désormais fusionnés entre sources — une ligne par vulnérabilité, chaque source étiquetée, le meilleur correctif disponible et l’union des chemins de dépendances, avec un filtre par source et une infobulle de chemin de dépendance
  • Renforcement de la sécurité : le point de terminaison MCP est désactivé par défaut et requiert un jeton, la livraison des webhooks est protégée contre le SSRF, une page de connexion optionnelle au portail, et le conteneur s’exécute en utilisateur non privilégié
  • Les Paramètres forment désormais une section de premier niveau avec une barre latérale et une page Profil

Intégration MCP et nouveautés

v1.4.0 · 29 mai 2026
  • Serveur MCP sur /api/mcp pour Claude Desktop, Cursor et d’autres clients
  • Nouvelle section Paramètres → MCP avec URL du serveur et gestion des jetons
  • Pastille de nouveautés et historique des notes de version

Correction de la version dans le pied de page

v1.3.1 · 28 mai 2026
  • La version en cours s’affiche correctement dans le pied de page

Améliorations des notifications

v1.3.0 · 28 mai 2026
  • Filtrer les notifications par environnement
  • Formulaire d’édition des cibles simplifié
  • Dupliquer une cible de notification existante

Pages Projets et Bibliothèques

v1.2.0 · 24 mai 2026
  • La vue d’accueil est divisée en pages Projets et Bibliothèques dédiées

Rechargement du planning en direct

v1.1.2 · 24 mai 2026
  • Le worker recharge le planning d’analyse dès que vous enregistrez des modifications dans le portail

Suppressions plus sûres et bannière de mise à jour plus claire

v1.1.0 · 23 mai 2026
  • Confirmation avant la suppression de racines et de cibles de notification
  • L’avis de mise à jour devient une bannière supérieure que l’on peut fermer
  • Le worker supprime les racines obsolètes quand leur montage disparaît

Corrections de précision du scanner

v1.0.1 · 23 mai 2026
  • Écarte les résultats dont la version installée n’est pas réellement dans la plage vulnérable
  • Permet de supprimer une cible de notification ayant un historique d’envois

Première version open source

v1.0.0 · 23 mai 2026
  • La première version publique de Sentinello

Feuille de route

Aujourd'hui, Sentinello surveille vos dépendances sur plusieurs langages. Voici où il va — et ce que vous pouvez demander.

Priorisation plus intelligente

Prévu

Classez les résultats selon leur exploitabilité et selon que le code vulnérable est réellement atteignable — triez d’abord l’essentiel.

Plus d'intégrations

Prévu

Plus de canaux de notification et de façons de connecter Sentinello aux outils que votre équipe utilise déjà.

Analyse statique (SAST)

Prévu

Repérez les motifs de code risqués dans votre propre code, pas seulement les CVE connues de vos dépendances.

Analyse des secrets et licences

Prévu

Signalez les secrets commités et les problèmes de licence sur le même parc de projets, dans la même file.

Demander une intégration ou une source

Dites-nous ce que vous intégreriez ou analyseriez ensuite — ouvrez un ticket sur GitHub et aidez à façonner la feuille de route.