Un sistema de alerta temprana para las dependencias que dejaste de vigilar.
En la era de la IA publicas más proyectos de los que puedes mantener. Sentinello vigila cada uno y revela los CVE conocidos en sus dependencias de Node.js, para que un proyecto olvidado nunca se convierta en un incidente.
Ejecútalo 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:latestFunciona en linux/amd64 y arm64
Sin cuenta. Sin SaaS. Sin telemetría. Una imagen de Docker y un archivo SQLite: tu código y tus hallazgos nunca salen de tu máquina.
O prescinde del portal por completo
Los mismos escáneres se distribuyen como CLI. Sin instalación, sin cuenta, sin base de datos: se ejecuta, imprime un informe sobre el que tu agente puede actuar, y termina.
npx sentinelloCanalizado, stdout lleva solo el markdown, de modo que el informe llega íntegro al agente:
npx sentinello | claude -p "$(cat -)"Recorre la carpeta
Apúntalo a un directorio y encontrará todos los proyectos que contenga, deteniéndose en la raíz de cada uno para que un monorepo cuente una vez y no cincuenta. Respeta .gitignore y .sentinelloignore.
Consulta tres fuentes
Resuelve las versiones exactas instaladas desde el lockfile y las compara sin conexión con una caché local de avisos. Ninguna llamada de red por proyecto, y nada de tu código se sube.
Escribe un informe
Un archivo markdown fechado con los hallazgos y un prompt de remediación adjunto: triar antes de tocar nada, preferir actualizar el paquete padre a usar overrides, verificar las correcciones en el lockfile.
En qué se diferencia de npm audit
No sustituye a npm audit: ejecuta npm audit y luego añade dos fuentes de avisos que npm audit no puede ver, suprimiendo todo lo que dupliquen.
| npm audit | npx sentinello | |
|---|---|---|
| Alcance | El único proyecto en el que te encuentras. | Todos los proyectos de una carpeta, en una pasada y un solo informe. |
| Fuentes de avisos | El feed de avisos de tu registro. | Ese, más OSV y GitLab gemnasium. Los duplicados se suprimen, así que cada fuente adicional solo añade hallazgos nuevos. |
| Paquetes maliciosos | No cubierto. | Los registros MAL- de OSV señalan paquetes publicados con malware —typosquats, cargas en scripts de instalación— comparados con las versiones comprometidas concretas. |
| Salida | Una tabla, o JSON que tienes que interpretar. | Un informe markdown con un prompt de remediación adjunto, listo para entregar a un agente. |
| Comparación | Una llamada al registro por proyecto. | Sin conexión, contra una caché local. La primera ejecución la descarga y pregunta antes; las siguientes apenas transfieren nada. |
Las fuentes adicionales no son un formalismo. En el propio repositorio de Sentinello, npm audit y OSV informan cada uno de tres hallazgos y coinciden en todos, mientras que el único hallazgo crítico proviene de gemnasium, que ninguna de las otras dos incluye.
Características
Todo en un portal autoalojado — sin servicios externos, sin que los datos salgan de tu red.
Cola de triaje única
Ve y tría los CVE de todo tu portafolio en un solo lugar, en vez de npm audit disperso en una docena de copias.
Explora por proyecto o por librería
Entra en cualquier repositorio para ver sus hallazgos, versiones de corrección e historial — o cambia a un paquete vulnerable para ver todos los proyectos a los que afecta y silenciarlo en todos a la vez.
Hallazgos que coinciden
Cuando varias fuentes reportan la misma vulnerabilidad sigue siendo un solo hallazgo — indicando cuáles coincidieron y calificado con la peor severidad que le haya dado cualquiera de ellas.
Escaneo continuo
Un proceso en segundo plano vuelve a escanear según una programación, así los nuevos avisos aparecen sin que tengas que acordarte de revisar.
Múltiples fuentes
Más allá de npm audit: compara con OSV y con gemnasium de GitLab para mayor cobertura de CVEs y detección de paquetes maliciosos conocidos.
Notificaciones y webhooks
Recibe alertas de fallos y hallazgos por Slack, Telegram o un webhook simple — acotadas por root o por proyecto, en el idioma que elijas. Payloads en JSON o texto plano para un agente de auto-reparación.
Servidor MCP
Conecta Claude Desktop, Cursor y otros clientes MCP para consultar hallazgos, proyectos y librerías, y lanzar escaneos, sin salir del chat.
Exportación de avisos
Exporta los hallazgos de un proyecto o una librería como Markdown, con un prompt de remediación personalizable para tu equipo o un LLM.
Una imagen, un archivo
Una imagen de Docker y un archivo SQLite. Sin servidor de base de datos, sin cola de mensajes, sin dependencia de la nube.
Roots autorregistrados
Todo lo que montes bajo /roots se registra y se escanea al arrancar; el nombre del directorio se vuelve su etiqueta.
Node por proyecto
Respeta el .nvmrc de cada proyecto, instalando y cacheando una sola vez la versión de Node que fija.
10 idiomas
La interfaz del portal, los códigos de motivo de escaneo y los estados están traducidos a 10 idiomas.
Capturas
Míralo en acción — el portal escaneando un puñado de proyectos de demostración. Haz clic en cualquier captura para ampliarla.
Cómo se compara
Sentinello no es un Dependency-Track más pesado ni un Snyk más barato. Ocupa otro nicho: la larga cola de proyectos que nadie conectó a un pipeline.
| Sentinello | Dependency-Track | Snyk | Dependabot | |
|---|---|---|---|---|
| Sin configuración — apuntá a una carpeta | ~ | ~ | ||
| No requiere SBOM ni paso de CI | ||||
| Escanea lockfiles resueltos reales | ~ | |||
| Detección de paquetes maliciosos | ||||
| Autoalojado, sin SaaS | ||||
| Una imagen + SQLite | ||||
| Nativo para IA (MCP + export) | ~ | |||
| Polilingüe (Python, Go, …) | ||||
| Política empresarial / VEX | ~ | ~ |
Dependency-Track solo ve los proyectos que alguien instrumentó con un pipeline de SBOM. Sentinello encuentra los que olvidaste. Son más sólidas en políticas empresariales — si ya los corres en un pipeline maduro, consérvalos. Sentinello es para el resto de tu portafolio que nadie está mirando.
Por qué lo creamos
En la era de la IA, publicas más de lo que puedes mantener.
Hoy una sola persona desarrolladora levanta, entrega y deja atrás una docena de proyectos al año: el sitio de marketing, el panel del cliente, el proyecto personal que llegó a producción sin hacer ruido. Mantenerlos seguros solía significar entrar por SSH a cada copia para correr npm audit a mano, o enterarte de un CVE de Next.js por un titular días después de que salió. Nadie sostiene eso en una docena de repos, así que directamente no pasa.
Basta con una sola dependencia olvidada con una falla crítica de ejecución remota de código. El sitio más simple que dejaste de vigilar se vuelve la puerta de entrada.
«¿Por qué no usar Snyk o Dependabot y ya?» Esos viven dentro del pipeline de CI que armaste — y la larga cola nunca tuvo uno. Sentinello es el sistema de alerta temprana para todo lo demás: apúntalo a una carpeta y vigilará cada proyecto que olvidaste, revelando cada nuevo CVE en una sola cola antes de que se convierta en un incidente.
Cómo funciona
Tres pasos. Sin agentes que instalar en tus proyectos, sin cuentas que crear.
Apúntalo a tu código
Monta tus repositorios bajo /roots, o agrégalos desde Configuración → Roots. Cada directorio se registra y se descubre automáticamente al iniciar.
Escanea de forma continua
Un proceso en segundo plano compara tus dependencias con los CVE conocidos según una programación, instalando la versión de Node que cada proyecto fija cuando hace falta.
Triaje en una sola cola
Cada hallazgo de cada proyecto llega a una sola cola que puedes filtrar por severidad, con alertas opcionales a Slack, Telegram o un webhook.
Para quién es
Sentinello es para todos los que tienen más en producción de lo que pueden vigilar: la persona que desarrolla en solitario, el equipo pequeño, la agencia que hace malabares con trabajo de clientes.
- Publicas proyectos personales y sitios de clientes que deben seguir seguros mucho después del lanzamiento.
- Quieres una vista de todo el portafolio sin cablear CI en cada repositorio.
- Prefieres autoalojar antes que entregar el inventario de tu código a un SaaS.
Si eres una organización grande con Snyk o Dependabot ya integrados en un pipeline maduro, consérvalos: Sentinello no intenta reemplazar el SCA empresarial. Está aquí para el resto de tu portafolio que nadie vigila. Es de código abierto y con licencia MIT, así que puedes leer exactamente qué hace.
Notas de la versión
Sentinello se actualiza con frecuencia: esto es lo que aportó cada versión.
Un panel que dejaba que una sola fuente hablara por todo el proyecto
v3.5.0 · 20 ago 2026- La columna <strong>Estado</strong> del panel informaba de una sola fuente y descartaba el resto. Cada análisis escribe una fila por fuente y terminan con milisegundos de diferencia, así que la columna mostraba la que terminaba última — en la práctica siempre OSV. Todos los proyectos decían «Base de datos OSV aún no descargada» cuando npm audit los había analizado bien y había encontrado vulnerabilidades reales. Ahora Estado lleva una etiqueta por cada fuente que no pudo responder, nombrando la fuente, y no muestra nada cuando todas las fuentes activas están bien. El historial de análisis ganó una columna <strong>Fuente</strong> por el mismo motivo: un barrido escribía tres filas idénticas sin forma de distinguirlas.
- Ajustes → Fuentes afirmaba que una caché estaba al día mientras se reconstruía. El estado que lee el portal solo se escribía al terminar una sincronización, así que durante toda una reconstrucción de varios minutos seguía mostrando el recuento anterior — mientras cada análisis rechazaba correctamente la caché medio borrada. Tampoco llevaba nunca la versión del normalizador, que el escáner exige, así que un cambio de versión producía la misma afirmación falsa sin reconstrucción alguna. Ahora la fila dice <strong>Reconstruyendo…</strong> con el recuento anterior atenuado, o <strong>Reconstrucción pendiente</strong> cuando una caché no es utilizable y nada la está arreglando.
- Una caché que terminaba de descargarse dejaba a todos los proyectos con el veredicto que obtuvieron mientras faltaba. Nada volvía a analizarlos, así que <code>osv_db_not_seeded</code> se quedaba ahí hasta el siguiente barrido programado, o hasta que lo notabas y pulsabas Analizar. Sentinello ahora encola un análisis completo en cuanto una caché vuelve a ser utilizable. Una actualización incremental no encola nada. La actualización cuenta: si esta versión llega a una instancia cuyos proyectos aún arrastran ese veredicto de antes de que la caché terminara, el worker detecta la discrepancia en su primer arranque y la resuelve por ti — sin que tengas que acordarte de lanzar un análisis.
Un aviso que señalaba la versión que lo corregía
v3.4.0 · 18 ago 2026- gemnasium escribe unos pocos avisos con un espacio entre el comparador y su versión —<code>< 0.5.2</code> en lugar de <code><0.5.2</code>— y el analizador leía ese par como dos tokens distintos. El <code><</code> huérfano se quedaba con un límite vacío y la versión que quedaba suelta se guardaba como una versión exacta. Así, el aviso de <code>fresh</code> señalaba la 0.5.2 como vulnerable cuando 0.5.2 es precisamente la versión que lo corrigió, y además sin solución disponible, porque una versión fijada no lleva ningún destino de actualización. Hay 19 avisos escritos así y todos se analizaban mal: 15 perdían su rango por completo y 7 fijaban una versión que el propio registro nombra como corrección; <code>pg</code> fijaba once.
- Sentinello ha dejado de interpretar por su cuenta la sintaxis de rangos de npm y ahora entrega cada rango a la propia implementación de npm, lo que retira de golpe toda una familia de malas lecturas. Para npm, <code><=3.3</code> significa «hasta el final de la línea 3.3» —leído al pie de la letra se detenía en la 3.3.0 y se perdía la 3.3.1, que es un aviso real de <code>converse.js</code>— y <code>=103</code> significa toda la línea 103 en vez de un único punto, algo que <code>binaryen</code> declara ocho veces. Ahora también se leen los rangos con circunflejo, con tilde, <code>1.x</code> y con guion, cuando antes un registro escrito en cualquiera de ellos se descartaba sin decir nada. Comprobado sobre los 4696 rangos de versiones distintos que gemnasium publica para npm: interpretarlos nosotros discrepaba de npm en 9, delegar no discrepa en ninguno. Solo afecta a npm: en Python <code>==1.0</code> es una versión exacta y no un comodín, así que aplicar allí la regla de npm inventaría hallazgos.
- Se contienen tres cosas que la lectura de npm acierta al instalar un paquete y falla en un aviso. Un rango que no nombra ninguna versión —<code>*</code>, <code>x</code>, un campo vacío— significa «cualquier versión» cuando npm instala algo y «nadie rellenó esto» en un aviso, así que se rechaza en lugar de convertirse en un hallazgo contra todas las versiones publicadas. Un <code>||</code> suelto al final ya no puede ampliar a todo el rango que lo precede. Y <code>>0</code> sigue significando todas las versiones, porque <code>pandora-doomsday</code> declara así su paquete malicioso y la lectura de npm dejaría limpia toda la rama 0.x. Aparte, a un aviso cuya corrección declarada quede en el inicio de su propio rango afectado o por debajo ya no se le sustituye ese límite —producía un intervalo que no coincidía con nada, es decir, un hallazgo que deja de informar en silencio— y la regla para descartar un intervalo así ahora se comparte con la fuente OSV en lugar de escribirse una vez por fuente, que es justo como ambas llegaron a discrepar.
- Las pruebas que seguían sin detectar nada de esto ahora generan sus entradas en lugar de enumerarlas. Cada rango de versiones distinto que gemnasium publica para npm se comprueba contra la propia implementación de npm en cada compilación, junto con todo el producto cartesiano de la gramática de rangos y todas las ordenaciones de los eventos de rango de OSV. Ejecutado contra la versión anterior, ese barrido falla en 28 rangos, mientras que los diez ejemplos escritos a mano a los que sustituye pasaban todos. Cualquier grafía que se invente aguas arriba a partir de ahora romperá la compilación al importarse por primera vez, y no cuando alguien se fije en el hallazgo que produjo.
- Cada línea del código que produce estos hallazgos está ahora cubierta por el conjunto de pruebas: sentencias, ramas, funciones y líneas al 100%, sin exenciones en todo el repositorio. Es la respuesta directa a cómo se escaparon los fallos de las últimas versiones: cada uno era una rama que nada ejecutaba, que informaba de éxito sin hacer nada. Cerrar las 109 restantes reveló varias que figuraban como comprobaciones de seguridad inalcanzables y simplemente no estaban probadas, además de una regla de cobertura que llevaba meses sin comprobar nada porque el archivo que nombraba se había movido. Esa regla y las 500 líneas de excepciones que la rodeaban se sustituyen por una sola, de modo que el código sin pruebas ahora hace fallar la compilación en lugar de bajar una media.
- También se cierran las últimas brechas defensivas: un límite superior OSV ilegible deja abierto el intervalo válido, los límites de respaldo se validan después de aplicarse y un límite npm de preversión explícito como <code><1.2.3-0</code> conserva su significado exacto.
Avisos que declaraban vulnerable cualquier versión
v3.3.2 · 17 ago 2026- Un aviso cuyo rango afectado no tiene fin coincide con todas las versiones para siempre: un hallazgo que ninguna actualización puede cerrar y que en la página no se distingue de una vulnerabilidad realmente sin parchear. Dos avisos de <code>xlsx</code> llegaron así y señalaron una versión 0.20.3 completamente parcheada como de severidad alta y sin solución, en 11 proyectos a la vez, mientras <code>npm audit</code> informaba correctamente de esos mismos dos avisos como corregidos en 0.19.3 y 0.20.2. La causa está aguas arriba y es deliberada: GitHub no nombra una versión corregida que el registro no sirva bajo ese nombre de paquete —SheetJS publica 0.19.3 y posteriores solo desde su propio CDN—, así que declara el rango como «todo desde 0» y guarda el límite real en otro campo que Sentinello nunca leía. Ahora sí lo lee. Había 15 avisos de npm afectados, entre ellos <code>babel-traverse</code> y <code>sandbox</code>. Los 480 que de verdad no tienen arreglo lo siguen diciendo, y un registro que ya declara su propio límite nunca se sobrescribe
- Un aviso de gemnasium que dejaba su rango abierto mientras enumeraba las versiones que lo corrigen queda ahora acotado por la más alta de ellas. Un rango sin fin afirma que también las versiones futuras son vulnerables, y eso no puede significarlo ningún registro que nombre una corrección
- gemnasium escribe los rangos de versiones de Python como intersecciones PEP 440 —<code>>=5.0,<5.8</code>— y el analizador separaba los tokens solo por espacios, de modo que todo quedaba en uno: un límite inferior ilegible y ningún límite superior. Un rango así no coincide con nada, y no coincidir con nada significa no informar de nada. Afectaba a 2.830 de los 7.159 registros de PyPI en caché. Esta era una de las tres razones por las que Python, Go y Rust se retiraron en la 3.3.0; las otras dos siguen abiertas, así que continúan retirados
La misma versión que 3.3.0, con una imagen de Docker que sí compila
v3.3.1 · 15 ago 2026- 3.3.0 se publicó en npm y GitHub, pero su imagen de contenedor falló al compilar, así que al momento del lanzamiento no había 3.3.0 en GHCR ni en Docker Hub. El Dockerfile enumera cada paquete del workspace que instala, y uno de ellos —el de comparación de versiones— nunca había estado en la lista. Nada dentro de la imagen lo importaba hasta esta versión, así que la omisión jamás había importado. Desde entonces se publicó una imagen 3.3.0 corregida, construida con el mismo código de aplicación de 3.3.0, así que <code>docker pull sentinello:3.3.0</code> vuelve a funcionar. 3.3.1 lleva esa misma corrección en el árbol de código. Si usás la CLI, 3.3.0 ya estaba bien.
Solo los ecosistemas que realmente funcionan — y notificaciones en las que podés confiar
v3.3.0 · 15 ago 2026- Una notificación podía llegar vacía. Un operador recibió un mensaje de Telegram que anunciaba vulnerabilidades en un proyecto y no listaba ninguna. El envío está delimitado por proyecto pero corría una vez por escáner, así que la pasada de npm audit recibió dos eventos pendientes de OSV, no coincidió con ninguno y aun así renderizó el encabezado sobre una lista vacía. Después marcó ambos eventos como entregados — así que los dos hallazgos que nunca nombró quedaron registrados como notificados, y nada vuelve a revisar un evento entregado. Ahora un evento solo se envía si puede describirse, y el que no puede queda pendiente y se reconsidera en el siguiente escaneo
- Un hallazgo se reporta con la peor calificación que le haya dado cualquier fuente, y esa escalada llegaba al panel, a los totales por proyecto y a la compuerta <code>--fail-on</code> de la CLI — pero no a los umbrales de notificación. La notificación corría antes de la corroboración, así que el evento quedaba sellado con la calificación de la fuente sobreviviente y nunca se reescribía. En una instancia real, 135 hallazgos abiertos tenían una severidad de evento por debajo de la real, <strong>41 de ellos registrando un crítico como bajo, alto o moderado</strong>. Un destino filtrado a crítico y alto nunca habría sido alertado por ninguno de ellos, de forma permanente
- Los escaneos programados se detenían a medianoche en lugar de continuar. “Cada 3 horas desde las 07:00” corría a las 07, 10, 13, 16, 19 y 22 y después recién a las 07:00 — seis escaneos por día en lugar de ocho, con una ventana ciega de nueve horas cada noche — mientras Configuración seguía informando el intervalo que elegiste. “Cada 6 horas desde las 20:00” lograba un escaneo por día. Ahora los horarios continúan al día siguiente
- <strong>Python, Go y Rust fueron retirados.</strong> No es cautela ante asperezas: sus fallas se reportaban como limpio. La derivación de correcciones y el ordenamiento de versiones son solo semver, así que un aviso de OSV sobre Django recomendaba “actualizar a 3.2.23” contra un 4.2 instalado; los nombres de paquetes PyPI de OSV no están canonicalizados según PEP 503, así que nunca coincidían con los del resolutor; y el parser de rangos de gemnasium no puede leer intersecciones con coma de PEP 440. Una fuente que responde “sin vulnerabilidades” por los motivos equivocados es peor que una que no se ofrece, así que desaparecieron por completo de la superficie del producto — sin interruptor, sin descubrimiento, sin descarga. <strong>Los hallazgos que ya recolectaste con ellos siguen visibles y se pueden silenciar; no se borra nada.</strong> El ecosistema npm ahora se llama <strong>Node.js</strong>, que nombra el ecosistema de paquetes realmente escaneado en lugar de un lenguaje
- <strong>Configuración → Fuentes</strong> se rediseñó en torno a eso. Cada fuente repetía su propia explicación junto a su propio interruptor, y cada una respaldada por caché llevaba un panel de estado de cinco filas con su propio botón “Actualizar ahora” de tamaño completo — aunque ese botón encola una sola señal compartida por fuente sin importar cuántas veces aparezca. Ahora los interruptores solo dicen si una fuente está activa; qué aporta cada una, qué descarga y desde dónde, y cuándo se ejecuta pasó a una única tabla de referencia debajo, y el estado de sincronización se redujo a una línea
- Paquetes que el propio lockfile de npm declara alcanzables desde producción estaban siendo degradados a solo desarrollo. Un lockfile que omite <code>dev: true</code> es npm afirmando que el paquete SÍ es alcanzable desde producción — una afirmación más fuerte que la que puede hacer el manifiesto raíz — pero el resolutor la sobrescribía cada vez que el nombre también aparecía en <code>devDependencies</code>, que es justo cuando npm tenía razón. Medido en 130 proyectos reales: 142 paquetes degradados en 97 de ellos — lodash, semver, postcss, tailwindcss, @babel/runtime — ocultando siete hallazgos abiertos del filtro de solo producción en una instancia
- Cualquier paquete fijado a una versión como <code>0.0.0-20180523222229-09b5706aa936</code> no coincidía con <strong>ningún aviso</strong>, ni siquiera con uno abierto, y el escaneo reportaba ok con cero hallazgos. Un límite de aviso <code>introduced: 0</code> se comparaba como la release 0.0.0, y bajo semver una prerelease ordena por debajo de su release. 330 de los 19.085 rangos comparables de una caché real estaban almacenados como intervalos que nada podía satisfacer
- Una sincronización de OSV interrumpida podía borrar un aviso de forma permanente. La ruta incremental eliminaba las filas de un aviso y después buscaba el reemplazo dentro de un try/catch, así que cualquier timeout, 5xx o apagado lo quitaba por completo — y luego avanzaba el cursor igual, dejando el id permanentemente atrás. La pérdida era silenciosa, sobrevivía hasta el siguiente resembrado completo y ocurría en una sincronización que reportaba éxito. La caché de <code>npx sentinello</code> se erosionaba igual en cada ejecución inestable. Ahora ambas buscan primero y reemplazan después
- El <code>--dep-type dev</code> de la CLI significaba “alcanzable desde dev en absoluto” mientras que el portal significa “alcanzable <em>solo</em> desde dev”, así que un paquete alcanzable desde ambos aparecía en una vista y no en la otra — 177 hallazgos abiertos difieren entre ambas lecturas en una instancia. La CLI ahora usa la regla del portal, y respeta el campo <code>withdrawn</code> de OSV, que antes era estructuralmente incapaz de leer: 585 filas de una caché npm real llevan uno, y todas se reportaban como hallazgos vigentes
- Un aviso de gemnasium que indica que una vulnerabilidad empieza <em>después</em> de una versión — <code>>1.2.8</code> en lugar de <code>>=1.2.8</code> — se leía como si la versión del límite estuviera afectada. El secuestro del paquete <code>rc</code> en 2021 está escrito justo así, y 1.2.8 es su última versión limpia: precisamente la que la propia nota de remediación del aviso te dice que conserves. Todo proyecto con <code>rc</code> instalado veía un hallazgo crítico de malware, sin solución disponible, contra una versión que nunca estuvo comprometida. Ahora los límites se conservan tal y como los declara el aviso, y los falsos críticos de esta forma desaparecen
- El mismo redondeo actuaba en sentido contrario y ocultaba hallazgos reales. Un aviso limitado por <code><=2.0.0</code> se guardaba como «por debajo de 2.0.0», así que 2.0.0 —la versión sobre la que es más explícito— no se reportaba, y un aviso que nombraba exactamente una versión afectada se convertía en un rango vacío y se descartaba entero. Espera unos pocos hallazgos nuevos que siempre estuvieron ahí, simplemente invisibles
- Los rangos escritos con sintaxis que Sentinello no implementa — <code>^1.0.0</code>, <code>~1.0.0</code> — se guardaban como una versión exacta fijada al texto literal, que nunca podía coincidir con nada mientras siguiera en la caché: un aviso con aspecto activo pero incapaz de dispararse. Ahora esos registros se rechazan en vez de guardarse en una forma que no puede funcionar, y los avisos cuyo límite superior no trae una versión corregida limpia por fin reciben una sugerencia de actualización
- El helper que enmascara una URL de webhook o un token de bot antes de que llegue a una línea de log imprimía los cortos completos. Rechazaba valores de seis caracteres o menos pero luego conservaba una cabecera de ocho caracteres y una cola de cuatro, y nada verificaba que esas dos mitades no se tocaran — así que todo secreto de entre 7 y 12 caracteres volvía completo. Ahora oculta al menos ocho caracteres o redacta el valor por completo
Los hallazgos muestran qué fuentes coinciden, y los avisos retirados dejan de reportarse
v3.2.0 · 15 ago 2026- Cuando más de una base de datos de avisos reporta la misma vulnerabilidad, Sentinello siempre ha mantenido un único hallazgo: reportar un mismo fallo tres veces porque lo conocen tres bases de datos es ruido. Lo que hacía antes era descartar todo sobre las fuentes que colapsaba, así que una vulnerabilidad confirmada de forma independiente por npm audit, OSV y GitLab gemnasium se veía igual que otra que solo conocía una base de datos. En una instancia real eso son dos tercios de los hallazgos. Ahora cada hallazgo lleva las demás fuentes que lo reportaron, y sus etiquetas aparecen junto a la superviviente
- Un hallazgo se reporta con la severidad MÁS ALTA que le haya asignado cualquier fuente. Las bases de datos discrepan de verdad —gemnasium calcula la severidad a partir del vector CVSS mientras que npm audit toma la categoría de GitHub— y para un escáner la lectura prudente es la que conviene aplicar. Esto no es cosmético: un hallazgo escalado cambia de categoría en el panel, en los totales del proyecto, en la barrera <code>--fail-on</code> de la CLI y en los umbrales de notificación. Es de esperar que algunos recuentos cambien en el primer escaneo tras actualizar; no se detectó nada nuevo, los mismos hallazgos se clasifican con más cautela
- Cuando las fuentes discrepan, el hallazgo muestra un control junto a su severidad que abre lo que dijo cada una: su propio identificador de aviso y su propia clasificación. Solo aparece cuando hay una discrepancia que explicar, de modo que un hallazgo en el que todas coinciden se mantiene despejado
- OSV registra la retirada en un campo específico y GitHub elimina los avisos retirados antes de que <code>npm audit</code> los vea, pero GitLab gemnasium no tiene ese campo en su esquema. Retira un aviso reescribiendo el registro: el título pasa a ser «False Positive», «Withdrawn Advisory: …» o «Duplicate Advisory: …», y deja intactas las versiones que nombraba antes. Sentinello leía esas versiones y reportaba hallazgos que GitLab había retirado explícitamente: 383 registros en JavaScript, Python, Go y Rust, incluido uno que reportaba <code>express</code> bajo el título «False Positive». Todos se descartan ahora, lo que además elimina toda una clase de hallazgos duplicados, ya que 278 de los 383 son avisos retirados por duplicar a otro
- La comprobación busca los marcadores de retirada de forma exacta, no en cualquier parte del texto, así que un aviso legítimo que trate *sobre* un falso positivo se sigue reportando: el CVE-2026-39395 de Cosign, titulado «Cosign’s verify-blob-attestation reports false positive when payload parsing fails», no se ve afectado
- La caché de gemnasium se reconstruye sola en su primera sincronización tras esta actualización, y entonces desaparecen los avisos retirados. No hay que hacer nada: ocurre en la sincronización diaria, o al instante desde Ajustes → Fuentes → Actualizar
Los rangos de versiones de los avisos son correctos en ambos sentidos
v3.1.1 · 14 ago 2026- Algunos avisos de GitLab gemnasium no incluyen ningún rango de versiones legible por máquina: 698 de los 10.777 de JavaScript. Sentinello rellenaba ese hueco suponiendo que todas las versiones por debajo de la primera corrección listada estaban afectadas, pero esa lista no está ordenada y contiene una corrección por rama de publicación, así que la suposición caía a menudo en la rama equivocada. protobufjs 7.6.5 se reportaba como ejecución remota de código crítica aunque esa rama se corrigió en 7.5.5, y tres avisos distintos afirmaban que todas las versiones de vite por debajo de 8.0.5 eran vulnerables. Sentinello ya no inventa rangos: recupera el real del mismo aviso publicado con su otro identificador, de la propia descripción del aviso o —solo si tienes OSV activado— de la copia de OSV que ya está en tu máquina, y descarta el registro en lugar de adivinar cuando ninguna de esas vías responde. Es de esperar que desaparezcan algunos críticos
- OSV describe un aviso corregido en varias ramas como una entrada separada por rama, y Sentinello se quedaba con la primera y descartaba el resto: 1.927 rangos de versiones vulnerables solo en JavaScript, cada uno una vulnerabilidad real que ya no podía ver. El aviso de minimatch cubre ocho ramas y solo sobrevivía una, de modo que un minimatch 3.0.4 o 9.0.0 instalado no se reportaba; next y ua-parser-js perdían ramas del mismo modo. Ahora se conservan todas. Es de esperar que aparezcan hallazgos nuevos: esas vulnerabilidades siempre estuvieron ahí, simplemente eran invisibles
- Ambas cachés de avisos se reconstruyen solas la primera vez que se sincronizan tras esta actualización, porque los rangos que contienen los produjo el código anterior. No hay nada que hacer: ocurre en la sincronización diaria, o al instante desde Ajustes → Fuentes → Actualizar si prefieres no esperar
Los hallazgos silenciados se apartan, y la base de datos deja de crecer sin fin
v3.1.0 · 13 ago 2026- Un hallazgo silenciado es una decisión que ya tomaste, así que ahora desaparece por completo de la página del proyecto en lugar de quedarse ahí atenuado. No es solo cuestión de orden: todos los números de la página — el recuento del encabezado, las insignias de ambas pestañas, la paginación, los totales por biblioteca, el botón de exportar — se calculan a partir de las mismas filas, así que la página por fin coincide con el panel, las herramientas MCP y la exportación de avisos, que ya dejaban fuera los hallazgos silenciados. Un interruptor «Mostrar silenciados» los devuelve cuando los necesites, incluso en un proyecto cuyos hallazgos están *todos* silenciados
- Escribir en un diálogo ya no pierde el foco tras un solo carácter. Ese fallo hacía prácticamente imposible rellenar el campo Motivo del diálogo de silenciado — obligatorio, y lo único que permite auditar un silenciado meses después. El mismo diálogo también dejó de heredar la alineación de la fila de tabla desde la que se abría, que es la razón por la que silenciar un hallazgo daba un diálogo alineado a la derecha y silenciar un proyecto no
- El historial de escaneos ya no crece indefinidamente. Nada había borrado nunca una fila de escaneo por antigüedad, así que un proyecto que seguía en disco acumulaba una fila por fuente y por barrido sin límite — una instancia real llegó a 2,2 GB en menos de tres meses. Ajustes → Avanzado incorpora ahora un periodo de retención, 90 días de forma predeterminada, y el worker depura más allá de ese punto cada hora conservando siempre los 100 escaneos más recientes de cada proyecto. Los hallazgos, los silenciamientos y el historial de notificaciones no se tocan nunca; solo el registro de escaneos. Con 90 días, una instancia que se actualice no borra nada en su primera pasada: la limpieza empieza cuando el historial supera de verdad ese periodo, o cuando tú lo reduces
- La mayor parte de ese crecimiento era la salida en bruto de `npm audit`, guardada íntegra en cada escaneo correcto y leída por nada en absoluto: el 98,7 % de la base de datos de aquella instancia. Ahora los escaneos guardan un resumen breve, lo que reduce una fila de unos 79 KB a unos 100 bytes, con un límite máximo para que ningún escáner pueda repetirlo
- En MCP, `get_dashboard_summary` indica ahora que un proyecto silenciado sale de sus totales mientras `list_projects` lo sigue devolviendo. Los dos cuentan poblaciones distintas a propósito, y un agente que los comparaba lo interpretaba como un error. `list_scans` también dejó de devolver la salida en bruto del escáner de cada escaneo, que podía alcanzar unos 16 MB en una sola respuesta
La descarga de gemnasium vuelve a funcionar, y la CLI devuelve la terminal
v3.0.1 · 4 ago 2026- La descarga de GitLab gemnasium fallaba en 3.0.0 con `HTTP 406`, para todo el mundo. El fetch integrado de Node añade una cabecera `Sec-Fetch-Mode: cors` que un programa no puede eliminar, y GitLab rechaza cualquier petición de archivo del repositorio que la lleve — así que nunca tuvo que ver con tu red, tu IP ni con cuántas veces reintentaras. Ahora la descarga usa una petición HTTPS normal y funciona
- El archivo se descarga por id de commit en lugar de por nombre de rama, así que todos los que actualizan desde el mismo commit comparten una copia en caché en vez de pedirle a GitLab que genere un archivo de 60 MB cada uno. Una primera descarga que tardaba casi siete minutos ahora termina en segundos
- La CLI terminaba todo su trabajo — informe escrito, resumen impreso — y luego no devolvía la terminal. La conexión de la descarga quedaba abierta detrás, manteniendo vivo el proceso; ahora se cierra en cuanto se ha leído el archivo
- Una fuente que rechaza una descarga ya no se queda tres minutos esperando antes de decirlo. Lo informa en segundos y, en una terminal, ofrece reintentar — reintentando solo la fuente que realmente falló
- `--fail-on` es honesto en ambos sentidos. Rechaza una ejecución cuya fuente de avisos no se pudo consultar, en lugar de informar de un análisis limpio que nunca hizo; y ya no falla por una fuente que desactivaste tú con `SENTINELLO_OSV_FEED_URL=off` o `SENTINELLO_GEMNASIUM_FEED_URL=off` y nunca descargaste
Sentinello ya funciona sin portal alguno
v3.0.0 · 3 ago 2026- Los escáneres se distribuyen como CLI en npm. `npx sentinello` recorre una carpeta, encuentra todos los proyectos que contiene, los contrasta con npm audit, OSV y GitLab gemnasium, y escribe un informe markdown con un prompt de remediación adjunto: sin instalación, sin cuenta, sin base de datos y sin que nada de tu código salga de la máquina
- Canalizado, el informe es lo único que sale por stdout, así que `npx sentinello | claude -p "$(cat -)"` entrega a un agente una lista de trabajo completa sin que nada corrompa el documento
- Una primera ejecución ya no pierde la fuente gemnasium por una descarga rechazada. GitLab rechaza su archivo durante uno o dos minutos seguidos, y el reintento anterior se rendía a los trece segundos; ahora la CLI espera a que pase, explica por qué espera y acepta `--feed-wait` si los tres minutos por defecto no te sirven
- Ambas estimaciones de descarga se midieron en lugar de suponerse: la exportación npm de OSV se indica como 204 MB en vez de 196, y el archivo de gemnasium como 52 MB en vez de 80. El aviso de consentimiento marca las estimaciones con una tilde para que nunca se confundan con un tamaño informado por el servidor
- Un valor con aspecto de opción ahora se rechaza en lugar de tomarse literalmente: `--out --` escribía un informe en un archivo llamado `--` dentro de tu proyecto e informaba de éxito
- El panel de Novedades ya no se sale por la parte inferior de la ventana cuando una versión tiene mucho que contar
El documento de vulnerabilidades por fin llega — y cuenta lo que debe
v2.6.0 · 29 jul 2026- get_project_advisory ahora devuelve el documento en sí. Hasta ahora los clientes conectados solo recibían sus metadatos —un nombre de archivo y un recuento— y nunca el documento, pese a que la herramienta lo describía como una lista de trabajo completa
- El informe de vulnerabilidades incluye ahora una entrada por cada aviso distinto, con sus fuentes combinadas, en lugar de una por fila de escáner: una vulnerabilidad que reportan npm audit y OSV es un único elemento de trabajo con ambos identificadores, no dos casi idénticos. Esto vale también para el botón Descargar .md del portal, y el recuento ya coincide con el del panel
- Un proyecto demasiado grande para caber en una sola respuesta MCP ahora se pagina: el documento indica que está incompleto y da la llamada exacta para obtener el resto, en vez de cortarse en silencio donde un agente leería lo que falta como limpio
- Cada parámetro de cada herramienta MCP tiene ahora una descripción, y la nueva herramienta list_mutes expone los identificadores de silenciamiento que necesita unmute — antes solo se conseguían creando el silenciamiento en la misma sesión
- Corregido un fallo en los recuentos de severidad: un hallazgo cuya severidad no era uno de los cinco valores conocidos se contaba como hallazgo pero no entraba en ninguna categoría, así que un proyecto cuyo único hallazgo fuera ese aparecía como completamente limpio
El informe de vulnerabilidades, directo por MCP
v2.5.0 · 28 jul 2026- Los clientes MCP conectados pueden obtener el informe Markdown completo de un proyecto con la nueva herramienta get_project_advisory: el mismo documento que el botón Descargar .md del portal, sin copiarlo desde el navegador
- Los hallazgos silenciados ya no se incluyen en el informe del proyecto, así que a un agente nunca se le encarga trabajo cuyo riesgo ya has aceptado
- Nota: como el informe contiene tu prompt de exportación, un cliente MCP ahora puede leer lo que hayas escrito en Ajustes → Exportar
Ventanas emergentes sin recortes y un prompt de exportación más estricto
v2.4.3 · 26 jul 2026- Los desplegables, el popover de ruta de dependencias y el menú de exportación de avisos ya no quedan recortados por la tabla o el diálogo que los contiene: se dibujan por encima de la página y se abren hacia arriba cuando no hay espacio debajo
- El prompt de exportación de avisos por defecto ahora pide al agente que planifique antes de editar nada, que agrupe los hallazgos que comparten una misma corrección y que detalle el impacto en el código de cada cambio de versión; además fija como objetivo cero hallazgos y descarta los atajos hacia un cero falso —silenciar, ampliar rangos o reducir el alcance del análisis—, dejando lo realmente irresoluble en una tabla de residuos fechada
La rama en su propia columna
v2.4.2 · 25 jul 2026- La rama de git en la que se analizó cada proyecto ahora tiene su propia columna en la lista de proyectos —texto simple, sin icono— en lugar de aparecer debajo del nombre del proyecto
Apagados limpios
v2.4.1 · 25 jul 2026- Reiniciar el contenedor ya no interrumpe un análisis a mitad de escritura, y el worker arranca de inmediato en lugar de reintentar durante ~30 segundos
- Define stop_grace_period: 60s (o --stop-timeout 60) en tu archivo compose para darle margen: el README y la documentación de Docker ya lo explican
Análisis políglota: Python, Go y Rust se suman a npm
v2.4.0 · 25 jul 2026- Sentinello ahora analiza proyectos de Python, Go y Rust además de npm: los archivos de bloqueo se resuelven totalmente sin conexión y cada proyecto informa su cobertura de análisis (completa, parcial o no auditable), de modo que las lagunas quedan visibles en lugar de silenciosas
- La base de datos gemnasium de GitLab se suma a npm audit y OSV como fuente de avisos sin conexión, deduplicada frente a las demás por alias CVE/GHSA; Configuración → Fuentes es ahora una matriz de Lenguajes × Fuentes con alcance de notificaciones por celda, y npm audit ya se puede desactivar siempre que quede una fuente activa
- Los hallazgos ahora registran la rama de git de la que provienen, visible en la lista de proyectos, el encabezado del proyecto y todas las notificaciones
- Las filas de proyecto incluyen sus propias acciones: analizar ahora, copiar o descargar el aviso, silenciar o reactivar y editar etiquetas, así una ronda de triaje ya no exige entrar en cada proyecto
- El panel de proyectos pasó de ~3,3 s a ~0,03 s, y la navegación ahora muestra estados de carga en lugar de parecer congelada
- Seguridad: 25 avisos de dependencias resueltos, incluidos CVE de libvips que estaban activos en el optimizador de imágenes del portal y nueve avisos de Next.js que afectaban al portal distribuido
- El prompt de exportación de avisos por defecto ahora cubre la antigüedad mínima de publicación, la verificación del archivo de bloqueo y los overrides obsoletos
Configuración de MCP más simple, sin variables de entorno
v2.3.0 · 9 jun 2026- Configura MCP por completo en Configuración → MCP: genera un token para activar el endpoint /api/mcp y bórralo para desactivarlo — las variables de entorno SENTINELLO_MCP_ENABLED y SENTINELLO_MCP_API_TOKEN ya no existen (un token de entorno existente se importa una vez al actualizar)
- Fragmentos de conexión listos para pegar para Claude Code, Codex, Cursor y Claude Desktop, con tu token ya incluido
- Cuando SENTINELLO_PORTAL_BASE_URL se define en el entorno, se muestra de solo lectura en Configuración → Avanzado, ya que sigue siendo autoritativa y se reaplica en cada arranque
Menos falsas alarmas y hallazgos que se limpian solos
v2.2.0 · 9 jun 2026- Los avisos de malware ahora coinciden con la versión comprometida exacta: una versión limpia o ya corregida de un paquete que estuvo comprometido deja de marcarse
- Los hallazgos duplicados ahora se resuelven solos en el siguiente análisis, de modo que las entradas antiguas o huérfanas se eliminan automáticamente
- Las etiquetas de producción y desarrollo ahora se calculan de una sola forma coherente en todas las fuentes (npm y OSV)
Un encabezado de proyecto más limpio y filtros coherentes
v2.1.0 · 6 jun 2026- Encabezado de proyecto simplificado: renombra junto al título, con silenciar y etiquetas como iconos
- Filtra los hallazgos por fuente (npm / OSV) desde un nuevo desplegable junto al filtro de tipo de dependencia
- Desplegables unificados y coherentes en toda la app, con búsqueda al escribir en listas largas como las zonas horarias
Guía de actualización más clara
v2.0.1 · 4 jun 2026- Pasos de actualización ampliados para los cambios incompatibles de 2.0
- El README indica el enlace de puerto solo en localhost
Análisis multi-fuente y una instalación reforzada y segura por defecto
v2.0.0 · 4 jun 2026- OSV como segunda fuente opcional (Configuración → Fuentes, desactivada por defecto) con detección de paquetes maliciosos, cotejada con la base de datos pública de OSV en una caché local
- Los hallazgos ahora se combinan entre fuentes: una fila por vulnerabilidad, con cada fuente etiquetada, la mejor corrección disponible y la unión de las rutas de dependencia, con filtro por fuente y un popover de ruta de dependencia
- Refuerzo de seguridad: el endpoint MCP está desactivado por defecto y requiere un token, la entrega de webhooks está protegida contra SSRF, una puerta de inicio de sesión opcional del portal, y el contenedor se ejecuta como usuario sin privilegios
- Configuración ahora es una sección de nivel superior con barra lateral y una página de Perfil
Integración MCP y novedades
v1.4.0 · 29 may 2026- Servidor MCP en /api/mcp para Claude Desktop, Cursor y otros clientes
- Nueva sección Configuración → MCP con URL del servidor y gestión de tokens
- Píldora de novedades e historial de notas de versión
Corrección de la versión en el pie
v1.3.1 · 28 may 2026- La versión en ejecución se muestra correctamente en el pie de página
Mejoras en las notificaciones
v1.3.0 · 28 may 2026- Filtrar notificaciones por entorno
- Formulario de edición de destinos más simple
- Duplicar un destino de notificación existente
Páginas de Proyectos y Bibliotecas
v1.2.0 · 24 may 2026- La vista de inicio se divide en páginas dedicadas de Proyectos y Bibliotecas
Recarga de la programación en vivo
v1.1.2 · 24 may 2026- El worker recarga la programación de escaneo en cuanto guardas cambios en el portal
Borrados más seguros y un aviso de actualización más claro
v1.1.0 · 23 may 2026- Confirmación antes de eliminar raíces y destinos de notificación
- El aviso de actualización pasa a un banner superior descartable
- El worker elimina raíces obsoletas cuando desaparece su montaje
Correcciones de precisión del escáner
v1.0.1 · 23 may 2026- Descarta hallazgos cuya versión instalada no está realmente en el rango vulnerable
- Permite eliminar un destino de notificación con historial de envíos
Primera versión de código abierto
v1.0.0 · 23 may 2026- El primer lanzamiento público de Sentinello
Hoja de ruta
Hoy Sentinello vigila tus dependencias en varios lenguajes. Esto es hacia dónde va — y lo que puedes pedir.
Priorización más inteligente
PlaneadoOrdená los hallazgos por explotabilidad y por si el código vulnerable es realmente alcanzable — triá primero lo que importa.
Más integraciones
PlaneadoMás canales de notificación y formas de conectar Sentinello con las herramientas que tu equipo ya usa.
Análisis estático (SAST)
PlaneadoDetecta patrones de código riesgosos en tu propio código, no solo CVE conocidos en tus dependencias.
Escaneo de secretos y licencias
PlaneadoSeñala secretos filtrados y problemas de licencias en el mismo portafolio, en la misma cola.
Dinos qué integrarías o escanearías a continuación — abre una incidencia en GitHub y ayuda a definir la hoja de ruta.