SentinelloSentinello

Un sistema di allerta precoce per le dipendenze che hai smesso di sorvegliare.

Nell’era dell’IA pubblichi più progetti di quanti tu possa mantenerne. Sentinello sorveglia ognuno e rivela i CVE noti nelle loro dipendenze Node.js — così un progetto dimenticato non diventa mai un incidente.

Avvialo con un solo comando:

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

Funziona su linux/amd64 e arm64

Nessun account. Nessun SaaS. Nessuna telemetria. Un'immagine Docker e un file SQLite — il tuo codice e i tuoi risultati non lasciano mai la tua macchina.

Oppure salta del tutto il portale

Gli stessi scanner sono disponibili come CLI. Nessuna installazione, nessun account, nessun database: si avvia, stampa un advisory su cui il tuo agente può agire, ed esce.

npx sentinello

In pipe, stdout trasporta solo il markdown, così l'advisory arriva integro all'agente:

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

Attraversa la cartella

Puntala a una directory e troverà ogni progetto al suo interno, fermandosi alla radice di ciascuno perché un monorepo conti una volta e non cinquanta. .gitignore e .sentinelloignore vengono rispettati.

Consulta tre fonti

Risolve le versioni esatte installate dal lockfile e le confronta offline con una cache locale di advisory. Nessuna chiamata di rete per progetto, e nulla del tuo codice viene caricato.

Scrive un advisory

Un file markdown datato con i risultati e un prompt di remediation allegato: fare triage prima di toccare qualsiasi cosa, preferire l'aggiornamento del pacchetto padre agli override, verificare le correzioni nel lockfile.

In cosa differisce da npm audit

Non sostituisce npm audit: esegue npm audit e poi aggiunge due fonti di advisory che npm audit non può vedere, sopprimendo ciò che duplicano.

npm auditnpx sentinello
AmbitoL'unico progetto in cui ti trovi.Ogni progetto sotto una cartella, in un solo passaggio e un solo report.
Fonti di advisoryIl feed di advisory del tuo registry.Quello, più OSV e GitLab gemnasium. I duplicati vengono soppressi, quindi ogni fonte aggiuntiva aggiunge solo risultati nuovi.
Pacchetti malevoliNon coperto.I record MAL- di OSV segnalano pacchetti pubblicati con malware — typosquat, payload negli script di installazione — confrontati con le specifiche versioni compromesse.
OutputUna tabella, o JSON da interpretare.Un advisory markdown con un prompt di remediation allegato, pronto da consegnare a un agente.
ConfrontoUna chiamata al registry per progetto.Offline, contro una cache locale. La prima esecuzione la scarica e chiede prima; quelle successive trasferiscono quasi nulla.

Le fonti aggiuntive non sono una formalità. Sul repository di Sentinello stesso, npm audit e OSV riportano tre risultati ciascuno e concordano su tutti, mentre l'unico risultato critico proviene da gemnasium, che nessuna delle altre due contiene.

Funzionalità

Tutto in un portale self-hosted — nessun servizio esterno, nessun dato che lascia la tua rete.

Coda di triage unica

Vedi e fai il triage dei CVE di tutto il tuo portafoglio in un solo posto — invece di npm audit sparso su una dozzina di copie.

Sfoglia per progetto o libreria

Entra in qualsiasi repository per vederne i risultati, le versioni di correzione e la cronologia — oppure passa a un pacchetto vulnerabile per vedere ogni progetto interessato e silenziarlo ovunque in una volta sola.

Risultati che concordano

Quando più fonti segnalano la stessa vulnerabilità resta un unico risultato — con l’indicazione di quali hanno concordato, valutato con la severità peggiore che una qualsiasi di esse gli ha dato.

Scansione continua

Un processo in background riscansiona secondo una pianificazione, così i nuovi avvisi compaiono senza che tu debba ricordarti di controllare.

Più fonti

Oltre a npm audit: confronto con OSV e con gemnasium di GitLab per una copertura CVE più ampia e il rilevamento di pacchetti dannosi noti.

Notifiche e webhook

Ricevi avvisi di errori e risultati via Slack, Telegram o un semplice webhook — definiti per root o per progetto, nella lingua che scegli. Payload JSON o in testo semplice per un agente di auto-correzione.

Server MCP

Collega Claude Desktop, Cursor e altri client MCP per interrogare risultati, progetti e librerie — e avviare scansioni — senza lasciare la chat.

Esportazione avvisi

Esporta i risultati di un progetto o di una libreria come Markdown, con un prompt di remediation personalizzabile per il tuo team o un LLM.

Un'immagine, un file

Un'immagine Docker e un file SQLite. Nessun server di database, nessuna coda di messaggi, nessuna dipendenza dal cloud.

Roots auto-registrati

Tutto ciò che è montato sotto /roots viene registrato e scansionato all'avvio — il nome della directory diventa la sua etichetta.

Node per progetto

Rispetta il .nvmrc di ogni progetto, installando e mettendo in cache una sola volta la versione di Node che fissa.

10 lingue

L'interfaccia del portale, i codici motivo di scansione e gli stati sono tradotti in 10 lingue.

Screenshot

Guardalo in azione — il portale mentre scansiona alcuni progetti dimostrativi. Clicca su qualsiasi immagine per ingrandirla.

Come si confronta

Sentinello non è un Dependency-Track più pesante né uno Snyk più economico. Occupa un’altra nicchia: la coda lunga di progetti che nessuno ha collegato a una pipeline.

SentinelloDependency-TrackSnykDependabot
Senza configurazione — punta a una cartella~~
Nessun SBOM / passaggio CI richiesto
Analizza lockfile risolti reali~
Rilevamento pacchetti dannosi
Self-hosted, niente SaaS
Una sola immagine + SQLite
Nativo per l’IA (MCP + export)~
Poliglotta (Python, Go, …)
Policy aziendale / VEX~~

Dependency-Track vede solo i progetti che qualcuno ha strumentato con una pipeline SBOM. Sentinello trova quelli che hai dimenticato. Sono più forti sulla policy aziendale — se li usi già su una pipeline matura, tienili. Sentinello è per il resto del tuo portafoglio che nessuno sta osservando.

Perché l'abbiamo creato

Nell'era dell'IA, pubblichi più di quanto tu possa mantenere.

Oggi chi sviluppa da solo avvia, consegna e si lascia alle spalle una dozzina di progetti all'anno — il sito vetrina, la dashboard del cliente, il progetto personale finito in produzione in sordina. Un tempo, tenerli al sicuro significava collegarsi in SSH a ogni checkout per lanciare npm audit a mano, oppure scoprire un CVE di Next.js da un titolo di giornale giorni dopo che era uscito. Nessuno tiene quel ritmo su una dozzina di repository, quindi alla fine non lo fa proprio nessuno.

Basta una sola dipendenza dimenticata con una falla critica di esecuzione di codice remoto. Il sito più semplice che hai smesso di sorvegliare diventa la via d'accesso.

«Perché non usare semplicemente Snyk o Dependabot?» Quelli vivono dentro la pipeline CI che hai cablato — e la coda lunga non ne ha mai avuta una. Sentinello è il sistema di allerta precoce per tutto il resto: puntalo a una cartella e sorveglia ogni progetto che hai dimenticato, facendo emergere ogni nuovo CVE in un'unica coda prima che diventi un incidente.

Come funziona

Tre passi. Nessun agente da installare nei tuoi progetti, nessun account da creare.

Puntalo al tuo codice

Monta i tuoi repository sotto /roots, oppure aggiungili da Impostazioni → Roots. Ogni directory viene registrata e individuata automaticamente all'avvio.

Scansiona di continuo

Un processo in background confronta le tue dipendenze con i CVE noti secondo una pianificazione, installando la versione di Node che ogni progetto fissa quando serve.

Triage in un'unica coda

Ogni risultato di ogni progetto arriva in un'unica coda che puoi filtrare per gravità — con avvisi opzionali verso Slack, Telegram o un webhook.

A chi è rivolto

Sentinello è per tutti coloro che hanno più in produzione di quanto riescano a sorvegliare — chi sviluppa da solo, il piccolo team, l'agenzia che destreggia il lavoro dei clienti.

  • Pubblichi progetti personali e siti dei clienti che devono restare sicuri a lungo dopo il lancio.
  • Vuoi una vista sull'intero portafoglio senza cablare la CI in ogni repository.
  • Preferisci il self-hosting piuttosto che affidare l'inventario del tuo codice a un SaaS.

Se sei una grande organizzazione con Snyk o Dependabot già integrati in una pipeline matura, tienili — Sentinello non cerca di sostituire lo SCA enterprise. È qui per il resto del tuo portafoglio che nessuno sorveglia. È open source e con licenza MIT, così puoi leggere esattamente cosa fa.

Note di rilascio

Sentinello viene aggiornato spesso: ecco cosa ha portato ogni versione.

Un pannello in cui una sola fonte parlava per l’intero progetto

v3.5.0 · 20 ago 2026
  • La colonna <strong>Stato</strong> del pannello riportava una sola fonte e scartava le altre. Ogni scansione scrive una riga per fonte e finiscono a millisecondi di distanza, quindi la colonna mostrava quella che finiva per ultima — in pratica sempre OSV. Ogni progetto leggeva «Database OSV non ancora scaricato» mentre npm audit li aveva analizzati correttamente trovando vulnerabilità reali. Ora Stato porta un badge per ogni fonte che non ha potuto rispondere, ciascuno con il nome della fonte, e non mostra nulla quando tutte le fonti attive stanno bene. La cronologia delle scansioni ha guadagnato una colonna <strong>Fonte</strong> per lo stesso motivo: una passata scriveva tre righe identiche senza modo di distinguerle.
  • Impostazioni → Fonti sosteneva che una cache fosse aggiornata mentre veniva ricostruita. Lo stato letto dal portale veniva scritto solo alla fine di una sincronizzazione, quindi per tutta una ricostruzione di minuti continuava a mostrare il conteggio precedente — mentre ogni scansione rifiutava giustamente la cache mezza cancellata. Non portava nemmeno la versione del normalizzatore, che lo scanner richiede, così un cambio di versione produceva la stessa falsa affermazione senza alcuna ricostruzione. La riga ora dice <strong>Ricostruzione…</strong> con il conteggio precedente attenuato, oppure <strong>Ricostruzione in sospeso</strong> quando una cache è inutilizzabile e nulla se ne sta occupando.
  • Una cache che finiva di scaricarsi lasciava ogni progetto fermo sul verdetto ottenuto mentre mancava. Nulla rieseguiva la scansione, quindi <code>osv_db_not_seeded</code> restava lì fino alla passata programmata successiva, o finché non te ne accorgevi e premevi Scansiona. Sentinello ora mette in coda una scansione completa non appena una cache torna utilizzabile. Un aggiornamento incrementale non mette in coda nulla. L’aggiornamento conta: se questa versione arriva su un’istanza i cui progetti portano ancora quel verdetto da prima che la cache finisse, il worker nota la discordanza al primo avvio e la sistema per te — nessuna scansione da ricordarsi di lanciare.

Un avviso che segnalava la versione che lo correggeva

v3.4.0 · 18 ago 2026
  • gemnasium scrive un piccolo numero di avvisi con uno spazio tra il comparatore e la sua versione — <code>&lt; 0.5.2</code> anziché <code>&lt;0.5.2</code> — e l’analizzatore leggeva quella coppia come due token distinti. Il <code>&lt;</code> rimasto orfano prendeva un limite vuoto, e la versione lasciata sola veniva memorizzata come versione esatta. Così l’avviso di <code>fresh</code> segnalava la 0.5.2 come vulnerabile quando 0.5.2 è proprio la versione che l’ha corretto, e la segnalava senza alcuna correzione disponibile, perché una versione fissata non porta con sé alcun obiettivo di aggiornamento. Sono 19 gli avvisi scritti così e tutti venivano analizzati male: 15 perdevano del tutto il proprio intervallo e 7 fissavano una versione che il record stesso indica come correzione; <code>pg</code> ne fissava undici.
  • Sentinello ha smesso di interpretare da sé la sintassi degli intervalli di npm e ora affida ogni intervallo all’implementazione di npm, il che manda in pensione in un colpo solo un’intera famiglia di letture sbagliate. Per npm <code>&lt;=3.3</code> significa «fino alla fine della linea 3.3» — letto alla lettera si fermava alla 3.3.0 e mancava la 3.3.1, che è un avviso reale di <code>converse.js</code> — e <code>=103</code> indica l’intera linea 103 anziché un singolo punto, cosa che <code>binaryen</code> dichiara otto volte. Ora vengono letti anche gli intervalli con accento circonflesso, tilde, <code>1.x</code> e trattino, mentre prima un record scritto in uno qualsiasi di essi veniva scartato senza dire nulla. Verificato su tutti i 4.696 intervalli di versioni distinti che gemnasium pubblica per npm: interpretarli per conto nostro divergeva da npm su 9, delegare non diverge su nessuno. Riguarda solo npm: in Python <code>==1.0</code> è una versione esatta e non un jolly, quindi applicare lì la regola di npm inventerebbe risultati.
  • Tre cose che la lettura di npm azzecca quando installa un pacchetto e sbaglia in un avviso vengono trattenute. Un intervallo che non nomina alcuna versione — <code>*</code>, <code>x</code>, un campo vuoto — significa «qualsiasi versione» quando npm installa qualcosa e «nessuno ha compilato questo campo» in un avviso, quindi viene rifiutato anziché trasformato in un risultato contro ogni versione mai pubblicata. Un <code>||</code> vagante in coda non può più allargare a tutto l’intervallo che lo precede. E <code>&gt;0</code> continua a significare tutte le versioni, perché <code>pandora-doomsday</code> dichiara così il suo pacchetto malevolo e la lettura di npm scagionerebbe l’intera 0.x. A parte questo, a un avviso la cui correzione dichiarata si trovi all’inizio del proprio intervallo interessato o al di sotto non viene più sostituito quel limite — produceva un intervallo che non corrispondeva a nulla, cioè un risultato che smette di segnalare in silenzio — e la regola per scartare un intervallo simile è ora condivisa con la sorgente OSV invece di essere scritta una volta per sorgente, che è proprio il motivo per cui le due avevano finito per non concordare.
  • I test che continuavano a non accorgersi di tutto questo ora generano i propri input invece di elencarli. Ogni intervallo di versioni distinto che gemnasium pubblica per npm viene verificato contro l’implementazione di npm a ogni build, insieme all’intero prodotto cartesiano della grammatica degli intervalli e a ogni ordinamento degli eventi di intervallo di OSV. Eseguita sulla versione precedente, quella scansione fallisce su 28 intervalli, mentre i dieci esempi scritti a mano che sostituisce passavano tutti. Una grafia inventata a monte da qui in avanti fa fallire la build alla prima importazione, e non quando qualcuno nota il risultato che ha prodotto.
  • Ogni riga del codice dietro questi risultati è ora eseguita dalla suite di test: istruzioni, rami, funzioni e righe al 100%, senza alcuna esenzione nell’intero repository. È la risposta diretta al modo in cui sono sfuggiti i bug delle ultime versioni: ognuno era un ramo che nulla eseguiva e che segnalava successo senza fare nulla. Chiudere gli ultimi 109 ne ha rivelati diversi registrati come controlli di sicurezza irraggiungibili e semplicemente non testati, oltre a una regola di copertura che da mesi non verificava più nulla perché il file che nominava era stato spostato. Quella regola e le 500 righe di eccezioni attorno a essa sono sostituite da una sola, così il codice non testato ora fa fallire la build invece di abbassare una media.
  • Sono state chiuse anche le ultime lacune difensive: un limite superiore OSV illeggibile lascia aperto l’intervallo valido, i limiti di fallback vengono verificati dopo l’applicazione e un limite npm di prerelease esplicito come <code>&lt;1.2.3-0</code> conserva il suo significato esatto.

Avvisi che dichiaravano vulnerabile ogni versione

v3.3.2 · 17 ago 2026
  • Un avviso il cui intervallo interessato non ha fine corrisponde a ogni versione, per sempre: un rilievo che nessun aggiornamento può chiudere e che sulla pagina non si distingue da una vulnerabilità davvero priva di patch. Due avvisi di <code>xlsx</code> sono arrivati così e segnalavano una 0.20.3 completamente corretta come severità alta e senza soluzione disponibile, su 11 progetti contemporaneamente, mentre <code>npm audit</code> riportava correttamente quegli stessi due avvisi come risolti in 0.19.3 e 0.20.2. La causa è a monte ed è deliberata: GitHub non indica una versione corretta che il registro non distribuisce con quel nome di pacchetto — SheetJS pubblica la 0.19.3 e le successive solo dal proprio CDN — e quindi dichiara l’intervallo come «tutto a partire da 0», annotando il limite reale in un altro campo che Sentinello non leggeva. Ora lo legge. Erano interessati 15 avvisi npm, tra cui <code>babel-traverse</code> e <code>sandbox</code>. I 480 realmente privi di correzione continuano a dirlo, e un record che dichiara già il proprio limite non viene mai sovrascritto
  • Un avviso gemnasium che lasciava aperto il proprio intervallo pur elencando le versioni che lo correggono è ora delimitato dalla più alta di esse. Un intervallo senza fine afferma che anche le versioni future sono vulnerabili, e nessun record che nomini una correzione può volerlo dire
  • gemnasium scrive gli intervalli di versione di Python come intersezioni PEP 440 — <code>&gt;=5.0,&lt;5.8</code> — e il parser separava i token solo sugli spazi, per cui il tutto diventava uno solo: un limite inferiore illeggibile e nessun limite superiore. Intervalli così non corrispondono a nulla, e non corrispondere a nulla significa non segnalare nulla. Erano in questo stato 2.830 dei 7.159 record PyPI in cache. Era uno dei tre motivi per cui Python, Go e Rust sono stati ritirati nella 3.3.0; gli altri due restano aperti, quindi restano ritirati

La stessa release della 3.3.0, con un’immagine Docker che si costruisce

v3.3.1 · 15 ago 2026
  • La 3.3.0 è stata pubblicata su npm e GitHub, ma la sua immagine container non si è costruita: al momento del rilascio su GHCR e Docker Hub non esisteva una 3.3.0. Il Dockerfile elenca ogni pacchetto del workspace che installa, e uno di essi — quello per il confronto delle versioni — non era mai stato elencato. Fino a questa release nulla nell’immagine lo importava, quindi l’omissione non aveva mai avuto effetto. Da allora è stata pubblicata un’immagine 3.3.0 corretta, costruita dal codice applicativo della 3.3.0 stessa, così <code>docker pull sentinello:3.3.0</code> funziona di nuovo. La 3.3.1 porta la stessa correzione nell’albero dei sorgenti. Se usi la CLI, la 3.3.0 era già corretta.

Solo gli ecosistemi che funzionano davvero — e notifiche di cui fidarsi

v3.3.0 · 15 ago 2026
  • Una notifica poteva arrivare vuota. Un operatore ha ricevuto un messaggio Telegram che annunciava vulnerabilità in un progetto senza elencarne nessuna. L’invio è delimitato per progetto ma girava una volta per scanner: il passaggio di npm audit si è visto consegnare due eventi OSV in sospeso, non ne ha fatto corrispondere nessuno e ha comunque reso il titolo sopra un elenco vuoto. Poi ha segnato entrambi gli eventi come consegnati — quindi i due risultati mai nominati sono stati registrati come notificati, e nulla ritorna su un evento consegnato. Ora un evento viene inviato solo se può essere descritto; altrimenti resta in sospeso e viene riconsiderato alla scansione successiva
  • Un risultato è segnalato con il voto peggiore che una qualsiasi fonte gli ha dato, e quell’escalation raggiungeva la dashboard, i totali per progetto e il cancello <code>--fail-on</code> della CLI — ma non le soglie di notifica. La notifica girava prima della corroborazione, quindi l’evento portava il voto della fonte sopravvissuta e non veniva mai riscritto. Su un’istanza reale, 135 risultati aperti portavano una severità dell’evento inferiore a quella vera, <strong>41 dei quali registravano un critico come basso, alto o moderato</strong>. Un destinatario filtrato su critico e alto non sarebbe mai stato allertato per nessuno di essi, in modo permanente
  • Le scansioni pianificate si fermavano a mezzanotte invece di proseguire. “Ogni 3 ore dalle 07:00” girava alle 07, 10, 13, 16, 19 e 22 e poi solo alle 07:00 — sei scansioni al giorno invece di otto, con una finestra cieca di nove ore ogni notte — mentre le Impostazioni continuavano a riportare l’intervallo scelto. “Ogni 6 ore dalle 20:00” arrivava a una scansione al giorno. Ora gli orari proseguono oltre il cambio di giorno
  • <strong>Python, Go e Rust sono stati ritirati.</strong> Non è prudenza verso qualche spigolo: i loro difetti si riportavano come puliti. La derivazione delle correzioni e l’ordinamento delle versioni sono solo semver, così un advisory OSV su Django consigliava di “aggiornare a 3.2.23” contro un 4.2 installato; i nomi dei pacchetti PyPI di OSV non sono canonicalizzati secondo PEP 503 e quindi non incontravano mai quelli del resolver; e il parser di intervalli di gemnasium non sa leggere le intersezioni con virgola di PEP 440. Una fonte che risponde “nessuna vulnerabilità” per i motivi sbagliati è peggio di una che non viene offerta, quindi sono sparite del tutto dalla superficie del prodotto — nessun interruttore, nessuna scoperta, nessun download. <strong>I risultati già raccolti con esse restano visibili e silenziabili; nulla viene eliminato.</strong> L’ecosistema npm ora si chiama <strong>Node.js</strong>, che nomina l’ecosistema di pacchetti realmente analizzato anziché un linguaggio
  • <strong>Impostazioni → Fonti</strong> è stata ricostruita intorno a questo. Ogni fonte ripeteva la propria spiegazione accanto al proprio interruttore, e ognuna basata su cache portava un pannello di stato di cinque righe con un proprio pulsante “Aggiorna ora” a grandezza piena — anche se quel pulsante accoda un unico segnale condiviso per fonte, per quante volte appaia. Gli interruttori ora dicono solo se una fonte è attiva; cosa aggiunge ciascuna, cosa scarica e da dove, e quando viene eseguita sono passati in un’unica tabella di riferimento sotto di essi, e lo stato di sincronizzazione si è ridotto a una riga
  • Pacchetti che il lockfile di npm stesso dichiara raggiungibili dalla produzione venivano declassati a solo sviluppo. Un lockfile che omette <code>dev: true</code> è npm che afferma che il pacchetto È raggiungibile dalla produzione — un’affermazione più forte di quella che il manifest radice può fare — ma il resolver la sovrascriveva ogni volta che il nome compariva anche sotto <code>devDependencies</code>, cioè esattamente quando npm aveva ragione. Misurato su 130 progetti reali: 142 pacchetti declassati in 97 di essi — lodash, semver, postcss, tailwindcss, @babel/runtime — nascondendo sette risultati aperti dal filtro solo-produzione su un’istanza
  • Qualsiasi pacchetto fissato a una versione come <code>0.0.0-20180523222229-09b5706aa936</code> non corrispondeva a <strong>nessun advisory</strong>, nemmeno a uno aperto, e la scansione riportava ok con zero risultati. Un limite di advisory <code>introduced: 0</code> veniva confrontato come la release 0.0.0, e in semver una prerelease si ordina sotto la sua release. 330 dei 19.085 intervalli confrontabili di una cache reale erano memorizzati come intervalli che nulla poteva soddisfare
  • Una sincronizzazione OSV interrotta poteva cancellare un advisory in modo permanente. Il percorso incrementale eliminava le righe di un advisory e solo dopo recuperava la sostituzione dentro un try/catch, quindi qualsiasi timeout, 5xx o spegnimento lo rimuoveva del tutto — e poi faceva avanzare comunque il cursore, lasciando l’id permanentemente indietro. La perdita era silenziosa, sopravviveva fino al successivo riseed completo e avveniva in una sincronizzazione che riportava successo. La cache di <code>npx sentinello</code> si erodeva allo stesso modo a ogni esecuzione instabile. Entrambe ora recuperano prima e sostituiscono poi
  • Il <code>--dep-type dev</code> della CLI significava “raggiungibile da dev in qualche modo”, mentre il portale intende “raggiungibile <em>solo</em> da dev”, quindi un pacchetto raggiungibile da entrambi compariva in una vista e non nell’altra — 177 risultati aperti differiscono tra le due letture su un’istanza. La CLI ora usa la regola del portale e rispetta il campo <code>withdrawn</code> di OSV, che era strutturalmente incapace di leggere: 585 righe di una cache npm reale ne portano uno, e tutte venivano riportate come risultati attivi
  • Un advisory di gemnasium che dice che una vulnerabilità inizia <em>dopo</em> una versione — <code>&gt;1.2.8</code> anziché <code>&gt;=1.2.8</code> — veniva letto come se la versione di confine fosse essa stessa interessata. Il dirottamento del pacchetto <code>rc</code> nel 2021 è scritto proprio così, e 1.2.8 è la sua ultima versione pulita: esattamente quella che la nota di rimedio dell’advisory stesso invita a mantenere. Ogni progetto con <code>rc</code> installato vedeva un rilevamento critico di malware, senza correzione disponibile, contro una versione mai compromessa. Ora i limiti vengono mantenuti esattamente come l’advisory li dichiara e i falsi critici di questa forma spariscono
  • Lo stesso arrotondamento agiva nella direzione opposta e nascondeva rilevamenti reali. Un advisory delimitato da <code>&lt;=2.0.0</code> veniva memorizzato come «sotto 2.0.0», così 2.0.0 — la versione su cui è più esplicito — non veniva segnalata, e un advisory che nominava esattamente una versione interessata diventava un intervallo vuoto e veniva scartato del tutto. Aspettati qualche nuovo rilevamento che c’era da sempre, semplicemente invisibile
  • Gli intervalli scritti con sintassi che Sentinello non implementa — <code>^1.0.0</code>, <code>~1.0.0</code> — venivano memorizzati come versione esatta fissata sul testo letterale, incapace di corrispondere a qualsiasi cosa finché restava in cache: un advisory dall’aspetto attivo ma che non poteva scattare. Ora quei record vengono rifiutati invece di essere conservati in una forma che non può funzionare, e gli advisory il cui limite superiore non porta una versione corretta pulita ricevono finalmente un suggerimento di aggiornamento
  • L’helper che maschera un URL di webhook o un token di bot prima che finisca in una riga di log stampava per intero quelli corti. Rifiutava valori di sei caratteri o meno, ma poi teneva una testa di otto caratteri e una coda di quattro, e nulla verificava che quelle due metà non si toccassero — così ogni segreto tra 7 e 12 caratteri tornava completo. Ora nasconde almeno otto caratteri oppure oscura del tutto il valore

I risultati mostrano quali fonti concordano e gli advisory ritirati non vengono più segnalati

v3.2.0 · 15 ago 2026
  • Quando più database di advisory segnalano la stessa vulnerabilità, Sentinello ha sempre mantenuto UN solo risultato: segnalare tre volte lo stesso difetto perché lo conoscono tre database è rumore. Finora però scartava tutto ciò che riguardava le fonti accorpate, così una vulnerabilità confermata in modo indipendente da npm audit, OSV e GitLab gemnasium appariva identica a una che un solo database avesse mai segnalato. Su un’istanza reale si tratta di due terzi dei risultati. Ora ogni risultato porta con sé le altre fonti che lo hanno segnalato, e i loro badge compaiono accanto a quello sopravvissuto
  • Un risultato viene segnalato con la severità PIÙ ALTA assegnata da una qualsiasi fonte. I database non concordano davvero — gemnasium calcola la severità dal vettore CVSS mentre npm audit adotta la categoria di GitHub — e per uno scanner la lettura prudente è quella su cui agire. Non è un dettaglio estetico: un risultato innalzato cambia categoria nella dashboard, nei totali di progetto, nel gate <code>--fail-on</code> della CLI e nelle soglie di notifica. Aspettati che alcuni conteggi si spostino alla prima scansione dopo l’aggiornamento: non è stato rilevato nulla di nuovo, gli stessi risultati vengono valutati con più prudenza
  • Dove le fonti divergono, il risultato mostra accanto alla severità un controllo che apre ciò che ciascuna ha effettivamente detto: il proprio identificativo di advisory e la propria valutazione. Compare solo quando c’è un disaccordo da spiegare, così un risultato valutato allo stesso modo da tutti resta pulito
  • OSV registra un ritiro in un campo dedicato e GitHub rimuove gli advisory ritirati prima che <code>npm audit</code> li veda, ma GitLab gemnasium non ha quel campo nel proprio schema. Ritira un advisory riscrivendo il record: il titolo diventa «False Positive», «Withdrawn Advisory: …» o «Duplicate Advisory: …», mentre le versioni che indicava restano al loro posto. Sentinello leggeva quelle versioni e segnalava risultati che GitLab aveva esplicitamente ritirato: 383 record tra JavaScript, Python, Go e Rust, incluso uno che segnalava <code>express</code> con il titolo «False Positive». Ora vengono tutti scartati, il che elimina anche un’intera classe di risultati duplicati, dato che 278 dei 383 sono advisory ritirati perché duplicati di un altro
  • Il controllo confronta i marcatori di ritiro in modo esatto anziché cercare le parole ovunque, così un advisory autentico che parla *di* un falso positivo continua a essere segnalato: il CVE-2026-39395 di Cosign, intitolato «Cosign’s verify-blob-attestation reports false positive when payload parsing fails», non è interessato
  • La cache di gemnasium si ricostruisce da sola alla prima sincronizzazione dopo questo aggiornamento e gli advisory ritirati spariscono. Non c’è nulla da fare: avviene con la sincronizzazione quotidiana, o subito da Impostazioni → Sorgenti → Aggiorna

Gli intervalli di versione degli advisory sono corretti in entrambe le direzioni

v3.1.1 · 14 ago 2026
  • Alcuni advisory di GitLab gemnasium non contengono alcun intervallo di versioni leggibile dalla macchina — 698 dei 10.777 per JavaScript. Sentinello colmava quel vuoto assumendo che tutte le versioni precedenti alla prima correzione elencata fossero interessate, ma quell’elenco non è ordinato e contiene una correzione per ramo di rilascio, così l’ipotesi finiva spesso sul ramo sbagliato. protobufjs 7.6.5 veniva segnalato come esecuzione di codice remoto critica benché quel ramo fosse stato corretto in 7.5.5, e tre advisory distinti sostenevano ciascuno che ogni versione di vite inferiore a 8.0.5 fosse vulnerabile. Sentinello non inventa più intervalli: recupera quello reale dallo stesso advisory pubblicato con l’altro identificatore, dalla descrizione dell’advisory stesso oppure — solo se hai OSV attivo — dalla copia di OSV già presente sulla tua macchina, e scarta il record anziché tirare a indovinare quando nessuna di queste vie risponde. Aspettati che alcuni critici spariscano
  • OSV descrive un advisory corretto su più rami di rilascio come una voce separata per ciascun ramo, e Sentinello teneva la prima scartando le altre — 1.927 intervalli di versioni vulnerabili per il solo JavaScript, ognuno una vulnerabilità reale diventata invisibile. L’advisory di minimatch copre otto rami e ne sopravviveva uno solo, così un minimatch 3.0.4 o 9.0.0 installato non veniva segnalato; next e ua-parser-js perdevano rami allo stesso modo. Ora vengono mantenuti tutti. Aspettati la comparsa di nuovi risultati: quelle vulnerabilità c’erano da sempre, erano solo invisibili
  • Entrambe le cache degli advisory si ricostruiscono da sole alla prima sincronizzazione dopo questo aggiornamento, perché gli intervalli che contengono sono stati prodotti dal codice precedente. Non c’è nulla da fare: avviene con la sincronizzazione quotidiana, o subito da Impostazioni → Sorgenti → Aggiorna se preferisci non aspettare

I risultati silenziati si tolgono di mezzo, e il database smette di crescere all’infinito

v3.1.0 · 13 ago 2026
  • Un risultato silenziato è una decisione che hai già preso, quindi ora sparisce del tutto dalla pagina del progetto invece di restare lì in grigio. Non è solo ordine: ogni numero della pagina — il conteggio nel titolo, i badge di entrambe le schede, la paginazione, i totali per libreria, il pulsante di esportazione — viene calcolato dalle stesse righe, così la pagina finalmente concorda con la dashboard, con gli strumenti MCP e con l’esportazione degli advisory, che già escludevano i risultati silenziati. Un interruttore «Mostra silenziati» li riporta quando ti servono, anche su un progetto i cui risultati sono *tutti* silenziati
  • Digitare in una finestra di dialogo non fa più perdere il focus dopo un solo carattere. Quel difetto rendeva di fatto impossibile compilare il campo Motivo della finestra di silenziamento — obbligatorio, e l’unica cosa che rende un silenziamento verificabile mesi dopo. La stessa finestra ha inoltre smesso di ereditare l’allineamento della riga di tabella da cui veniva aperta: è il motivo per cui silenziare un risultato dava una finestra allineata a destra mentre silenziare un progetto no
  • La cronologia delle scansioni non cresce più senza fine. Niente aveva mai eliminato una riga di scansione in base all’età, quindi un progetto rimasto su disco accumulava una riga per fonte a ogni passaggio, all’infinito — un’istanza reale ha raggiunto 2,2 GB in meno di tre mesi. Impostazioni → Avanzate ora offre un periodo di conservazione, 90 giorni per impostazione predefinita, e il worker ripulisce ogni ora ciò che lo supera, mantenendo sempre le 100 scansioni più recenti di ogni progetto. Risultati, silenziamenti e cronologia delle notifiche non vengono mai toccati; solo il registro delle scansioni. A 90 giorni un’istanza che si aggiorna non cancella nulla al primo passaggio: la pulizia inizia solo quando la cronologia supera davvero quel periodo, o quando sei tu ad abbassarlo
  • Gran parte di quella crescita era l’output grezzo di `npm audit`, salvato per intero a ogni scansione riuscita e letto da nulla — il 98,7% del database di quell’istanza. Le scansioni ora registrano un breve riepilogo, portando una riga da circa 79 KB a un centinaio di byte, con un tetto massimo perché nessuno scanner possa ripetere la cosa
  • Su MCP, `get_dashboard_summary` ora dichiara che un progetto che hai silenziato esce dai suoi totali mentre `list_projects` continua a restituirlo. I due contano popolazioni diverse di proposito, e un agente che li confrontava lo leggeva come un difetto. Anche `list_scans` ha smesso di restituire l’output grezzo dello scanner per ogni scansione, che in una sola risposta poteva raggiungere circa 16 MB

Il download di gemnasium funziona di nuovo — e la CLI restituisce il terminale

v3.0.1 · 4 ago 2026
  • Il download di GitLab gemnasium falliva nella 3.0.0 con `HTTP 406`, per tutti. Il fetch integrato di Node aggiunge un header `Sec-Fetch-Mode: cors` che un programma non può rimuovere, e GitLab rifiuta qualsiasi richiesta di archivio del repository che lo contenga — quindi non è mai dipeso dalla vostra rete, dal vostro IP o da quanti tentativi avete fatto. Ora il download usa una normale richiesta HTTPS e riesce
  • L’archivio viene scaricato per id di commit anziché per nome del branch, così chi aggiorna dallo stesso commit condivide una copia in cache invece di chiedere a GitLab di generare un archivio da 60 MB ciascuno. Un primo download che richiedeva quasi sette minuti ora finisce in pochi secondi
  • La CLI completava tutto il lavoro — report scritto, riepilogo stampato — e poi non restituiva mai il terminale. La connessione del download restava aperta dietro di essa, tenendo vivo il processo; ora viene chiusa non appena l’archivio è stato letto
  • Una sorgente che rifiuta un download non resta più ferma tre minuti prima di dirlo. Lo segnala in pochi secondi e, in un terminale, propone di riprovare — ritentando solo la sorgente che ha davvero fallito
  • `--fail-on` è onesto in entrambe le direzioni. Rifiuta un’esecuzione la cui sorgente di avvisi non è stata consultabile, invece di riportare una scansione pulita mai eseguita; e non fa più fallire un’esecuzione per una sorgente che avete disattivato voi con `SENTINELLO_OSV_FEED_URL=off` o `SENTINELLO_GEMNASIUM_FEED_URL=off` e mai scaricato

Sentinello ora funziona anche senza portale

v3.0.0 · 3 ago 2026
  • Gli scanner arrivano come CLI su npm. `npx sentinello` attraversa una cartella, trova ogni progetto al suo interno, li confronta con npm audit, OSV e GitLab gemnasium, e scrive un advisory markdown con un prompt di remediation allegato — nessuna installazione, nessun account, nessun database, e nulla del tuo codice lascia la macchina
  • In pipe, l’advisory è l’unica cosa su stdout, così `npx sentinello | claude -p "$(cat -)"` consegna a un agente un elenco di lavoro completo senza che nulla corrompa il documento
  • Una prima esecuzione non perde più la fonte gemnasium per un download rifiutato. GitLab rifiuta il suo archivio per uno o due minuti alla volta, e il vecchio retry si arrendeva dopo tredici secondi; ora la CLI aspetta che passi, spiega perché sta aspettando, e accetta `--feed-wait` se i tre minuti predefiniti non vanno bene
  • Entrambe le stime di download sono state misurate anziché ipotizzate: l’export npm di OSV è indicato a 204 MB invece di 196, e l’archivio gemnasium a 52 MB invece di 80. Il prompt di consenso segna una stima con una tilde perché non venga mai scambiata per una dimensione dichiarata dal server
  • Un valore che sembra un’opzione ora viene rifiutato invece di essere preso alla lettera — `--out --` scriveva un advisory in un file chiamato `--` dentro il tuo progetto e riportava successo
  • Il pannello Novità non esce più dal fondo della finestra quando una release ha molto da dire

Il documento degli avvisi arriva davvero — e conta ciò che serve

v2.6.0 · 29 lug 2026
  • get_project_advisory ora restituisce il documento vero e proprio. Finora i client collegati ricevevano solo i suoi metadati — un nome file e un conteggio — e mai il documento, benché lo strumento lo descrivesse come un elenco di lavoro completo
  • L’export degli avvisi contiene ora una voce per ogni avviso distinto, con le fonti unite, invece di una per riga dello scanner: una vulnerabilità segnalata sia da npm audit sia da OSV è un unico elemento di lavoro con entrambi gli identificativi, non due quasi identici. Vale anche per il pulsante Scarica .md del portale, e il conteggio ora coincide con quello della dashboard
  • Un progetto troppo grande per stare in una sola risposta MCP viene ora paginato: il documento dichiara di essere incompleto e indica la chiamata esatta per ottenere il resto, invece di essere troncato in silenzio dove un agente leggerebbe il resto come pulito
  • Ogni parametro di ogni strumento MCP ha ora una descrizione, e il nuovo strumento list_mutes espone gli identificativi di silenziamento richiesti da unmute — prima ottenibili solo creando il silenziamento nella stessa sessione
  • Corretta una falla nei conteggi di gravità: un rilevamento la cui gravità non era uno dei cinque valori noti veniva contato ma non finiva in alcuna categoria, così un progetto con quel solo rilevamento appariva completamente pulito

L’export degli avvisi, direttamente via MCP

v2.5.0 · 28 lug 2026
  • I client MCP collegati possono scaricare l’avviso Markdown completo di un progetto con il nuovo strumento get_project_advisory — lo stesso documento del pulsante Scarica .md del portale, senza copiarlo dal browser
  • I risultati silenziati non sono più inclusi nell’export degli avvisi del progetto, quindi a un agente non viene mai affidato un lavoro il cui rischio hai già accettato
  • Nota: poiché l’avviso contiene il tuo prompt di export, un client MCP può ora leggere ciò che hai scritto in Impostazioni → Export

Popup non più tagliati e un prompt di esportazione più severo

v2.4.3 · 26 lug 2026
  • I menu a discesa, il popover del percorso delle dipendenze e il menu di esportazione degli avvisi non vengono più tagliati dalla tabella o dalla finestra di dialogo che li contiene: sono disegnati sopra la pagina e si aprono verso l’alto quando sotto non c’è spazio
  • Il prompt predefinito di esportazione degli avvisi ora chiede all’agente di pianificare prima di modificare qualsiasi cosa, di raggruppare i risultati che condividono la stessa correzione e di descrivere l’impatto sul codice di ogni cambio di versione; punta a zero risultati escludendo le scorciatoie verso uno zero fittizio — silenziare, allargare gli intervalli o restringere l’ambito dell’analisi — e lascia ciò che è davvero irrisolvibile in una tabella dei residui con data

Il branch in una colonna dedicata

v2.4.2 · 25 lug 2026
  • Il branch git su cui è stato analizzato un progetto ha ora una colonna dedicata nell’elenco dei progetti — testo semplice, senza icona — invece di comparire sotto il nome del progetto

Arresti puliti

v2.4.1 · 25 lug 2026
  • Riavviare il container non interrompe più un’analisi a metà scrittura e il worker parte subito invece di riprovare per ~30 secondi
  • Imposta stop_grace_period: 60s (o --stop-timeout 60) nel tuo file compose per dargli spazio: il README e la documentazione Docker ora lo spiegano

Analisi poliglotta — Python, Go e Rust si aggiungono a npm

v2.4.0 · 25 lug 2026
  • Sentinello ora analizza progetti Python, Go e Rust oltre a npm — i lockfile sono risolti interamente offline e ogni progetto dichiara la propria copertura di analisi (completa, parziale o non verificabile), così le lacune sono visibili invece che silenziose
  • Il database gemnasium di GitLab si affianca a npm audit e OSV come sorgente di avvisi offline, deduplicata rispetto alle altre tramite alias CVE/GHSA; Impostazioni → Sorgenti è ora una matrice Linguaggi × Sorgenti con ambito di notifica per cella, e npm audit stesso può essere disattivato purché resti attiva una sorgente
  • I risultati registrano ora il branch git da cui provengono, mostrato nell’elenco dei progetti, nell’intestazione del progetto e in ogni notifica
  • Le righe dei progetti hanno azioni proprie — analizza ora, copia o scarica l’avviso, silenzia o riattiva e modifica i tag — così un giro di triage non richiede più di entrare in ogni progetto
  • La dashboard dei progetti è passata da ~3,3 s a ~0,03 s e la navigazione mostra ora stati di caricamento invece di sembrare bloccata
  • Sicurezza: risolti 25 avvisi sulle dipendenze, inclusi CVE di libvips attivi nell’ottimizzatore di immagini del portale e nove avvisi Next.js che riguardavano il portale distribuito
  • Il prompt predefinito di esportazione degli avvisi copre ora l’età minima di pubblicazione, la verifica del lockfile e gli override obsoleti

Configurazione MCP più semplice, senza variabili d’ambiente

v2.3.0 · 9 giu 2026
  • Configura MCP interamente in Impostazioni → MCP: genera un token per attivare l’endpoint /api/mcp, cancellalo per disattivarlo — le variabili d’ambiente SENTINELLO_MCP_ENABLED e SENTINELLO_MCP_API_TOKEN non esistono più (un token d’ambiente esistente viene importato una volta durante l’aggiornamento)
  • Frammenti di connessione pronti da incollare per Claude Code, Codex, Cursor e Claude Desktop, già compilati con il tuo token
  • Quando SENTINELLO_PORTAL_BASE_URL è impostata nell’ambiente, viene mostrata in sola lettura in Impostazioni → Avanzate, poiché resta autoritativa e viene riapplicata a ogni avvio

Meno falsi allarmi e risultati che si ripuliscono da soli

v2.2.0 · 9 giu 2026
  • Gli avvisi di malware ora corrispondono alla versione compromessa esatta — una versione pulita o già corretta di un pacchetto un tempo compromesso non viene più segnalata
  • I risultati duplicati ora si risolvono da soli alla scansione successiva, così le voci vecchie o orfane vengono eliminate automaticamente
  • Le etichette di produzione e sviluppo ora vengono calcolate in un unico modo coerente su tutte le sorgenti (npm e OSV)

Un’intestazione di progetto più pulita e filtri coerenti

v2.1.0 · 6 giu 2026
  • Intestazione di progetto semplificata — rinomina accanto al titolo, con silenzia e tag come icone
  • Filtra i risultati per fonte (npm / OSV) da un nuovo menu a discesa accanto al filtro per tipo di dipendenza
  • Menu a discesa unificati e coerenti in tutta l’app, con ricerca durante la digitazione per elenchi lunghi come i fusi orari

Indicazioni di aggiornamento più chiare

v2.0.1 · 4 giu 2026
  • Passaggi di aggiornamento ampliati per le modifiche incompatibili della 2.0
  • Il README segnala il binding della porta solo su localhost

Scansione multi-sorgente e un’installazione rafforzata e sicura per impostazione predefinita

v2.0.0 · 4 giu 2026
  • OSV come seconda sorgente opzionale (Impostazioni → Fonti, disattivata per impostazione predefinita) con rilevamento di pacchetti dannosi, confrontata con il database pubblico OSV in una cache locale
  • I risultati ora vengono uniti tra le sorgenti — una riga per vulnerabilità, ogni sorgente etichettata, la migliore correzione disponibile e l’unione dei percorsi di dipendenza, con un filtro per sorgente e un popover del percorso di dipendenza
  • Rafforzamento della sicurezza: l’endpoint MCP è disattivato per impostazione predefinita e richiede un token, la consegna dei webhook è protetta da SSRF, un gate di accesso opzionale al portale, e il contenitore viene eseguito come utente senza privilegi
  • Impostazioni è ora una sezione di primo livello con barra laterale e una pagina Profilo

Integrazione MCP e novità

v1.4.0 · 29 mag 2026
  • Server MCP su /api/mcp per Claude Desktop, Cursor e altri client
  • Nuova sezione Impostazioni → MCP con URL del server e gestione dei token
  • Badge delle novità e una cronologia delle note di rilascio

Correzione della versione nel piè di pagina

v1.3.1 · 28 mag 2026
  • La versione in esecuzione viene mostrata correttamente nel piè di pagina

Miglioramenti alle notifiche

v1.3.0 · 28 mag 2026
  • Filtra le notifiche per ambiente
  • Modulo di modifica delle destinazioni più semplice
  • Duplica una destinazione di notifica esistente

Pagine Progetti e Librerie

v1.2.0 · 24 mag 2026
  • La schermata iniziale è divisa in pagine dedicate Progetti e Librerie

Ricaricamento della pianificazione in tempo reale

v1.1.2 · 24 mag 2026
  • Il worker ricarica la pianificazione della scansione non appena salvi le modifiche nel portale

Eliminazioni più sicure e un avviso di aggiornamento più chiaro

v1.1.0 · 23 mag 2026
  • Conferma prima di eliminare radici e destinazioni di notifica
  • L’avviso di aggiornamento diventa un banner superiore richiudibile
  • Il worker rimuove le radici obsolete quando il loro mount scompare

Correzioni di precisione dello scanner

v1.0.1 · 23 mag 2026
  • Scarta i risultati la cui versione installata non è realmente nell’intervallo vulnerabile
  • Consente di eliminare una destinazione di notifica con cronologia di invio

Prima versione open source

v1.0.0 · 23 mag 2026
  • La prima versione pubblica di Sentinello

Roadmap

Oggi Sentinello sorveglia le tue dipendenze su più linguaggi. Ecco dove sta andando — e cosa puoi richiedere.

Priorità più intelligente

Pianificato

Ordina i risultati per sfruttabilità e per l’effettiva raggiungibilità del codice vulnerabile — gestisci prima ciò che conta.

Più integrazioni

Pianificato

Più canali di notifica e modi per collegare Sentinello agli strumenti che il tuo team già usa.

Analisi statica (SAST)

Pianificato

Individua schemi di codice rischiosi nel tuo codice, non solo i CVE noti nelle dipendenze.

Scansione di segreti e licenze

Pianificato

Segnala segreti committati e problemi di licenza nello stesso portafoglio, nella stessa coda.

Richiedi un'integrazione o una fonte

Dicci cosa integreresti o analizzeresti dopo — apri una issue su GitHub e aiuta a definire la roadmap.