Um sistema de alerta antecipado para as dependências que você parou de vigiar.
Na era da IA você publica mais projetos do que consegue manter. O Sentinello vigia cada um e revela os CVEs conhecidos em suas dependências Node.js — para que um projeto esquecido nunca vire um incidente.
Execute com um único 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 em linux/amd64 e arm64
Sem conta. Sem SaaS. Sem telemetria. Uma imagem Docker e um arquivo SQLite — seu código e seus achados nunca saem da sua máquina.
Ou dispense o portal por completo
Os mesmos scanners vêm como CLI. Sem instalação, sem conta, sem banco de dados: ele roda, imprime um parecer sobre o qual seu agente pode agir, e encerra.
npx sentinelloEm pipe, o stdout carrega apenas o markdown, então o parecer chega íntegro ao agente:
npx sentinello | claude -p "$(cat -)"Percorre a pasta
Aponte para um diretório e ele encontra todos os projetos abaixo, parando na raiz de cada um para que um monorepo conte uma vez e não cinquenta. .gitignore e .sentinelloignore são respeitados.
Consulta três fontes
Resolve as versões exatas instaladas a partir do lockfile e as compara offline com um cache local de pareceres. Nenhuma chamada de rede por projeto, e nada do seu código é enviado.
Escreve um parecer
Um arquivo markdown datado com os achados e um prompt de remediação anexado: triar antes de mexer em qualquer coisa, preferir atualizar o pacote pai a usar overrides, verificar as correções no lockfile.
Como difere do npm audit
Não substitui o npm audit: ele executa o npm audit e então adiciona duas fontes de pareceres que o npm audit não enxerga, suprimindo o que elas duplicam.
| npm audit | npx sentinello | |
|---|---|---|
| Escopo | O único projeto em que você está. | Todos os projetos sob uma pasta, em uma passagem e um relatório. |
| Fontes de pareceres | O feed de pareceres do seu registry. | Esse, mais OSV e GitLab gemnasium. Duplicatas são suprimidas, então cada fonte extra só acrescenta achados inéditos. |
| Pacotes maliciosos | Não coberto. | Os registros MAL- do OSV sinalizam pacotes publicados com malware — typosquats, cargas em scripts de instalação — comparados às versões especificamente comprometidas. |
| Saída | Uma tabela, ou JSON que você precisa interpretar. | Um parecer em markdown com um prompt de remediação anexado, pronto para entregar a um agente. |
| Correspondência | Uma chamada ao registry por projeto. | Offline, contra um cache local. A primeira execução o baixa e pergunta antes; as seguintes transferem quase nada. |
As fontes extras não são formalidade. No próprio repositório do Sentinello, npm audit e OSV relatam três achados cada e concordam em todos, enquanto o único achado crítico vem do gemnasium, que nenhuma das outras duas carrega.
Recursos
Tudo em um portal auto-hospedado — sem serviços externos, sem dados saindo da sua rede.
Fila de triagem única
Veja e faça a triagem de CVEs de todo o seu portfólio em um só lugar — em vez de npm audit espalhado por uma dúzia de cópias.
Navegue por projeto ou biblioteca
Entre em qualquer repositório para ver seus achados, versões de correção e histórico — ou pule para um pacote vulnerável para ver todos os projetos afetados e silenciá-lo em todos de uma vez.
Ocorrências que concordam
Quando várias fontes relatam a mesma vulnerabilidade ela continua sendo uma só ocorrência — trazendo quais delas concordaram, classificada pela pior severidade que qualquer uma tenha dado.
Escaneamento contínuo
Um processo em segundo plano reescaneia conforme um agendamento, então novos avisos aparecem sem você precisar lembrar de verificar.
Múltiplas fontes
Além do npm audit: comparação com o OSV e com o gemnasium do GitLab para maior cobertura de CVEs e detecção de pacotes maliciosos conhecidos.
Notificações e webhooks
Receba alertas de falhas e achados via Slack, Telegram ou um webhook simples — definidos por root ou projeto, no idioma que você escolher. Payloads em JSON ou texto simples para um agente de correção automática.
Servidor MCP
Conecte o Claude Desktop, o Cursor e outros clientes MCP para consultar achados, projetos e bibliotecas — e iniciar varreduras — sem sair do chat.
Exportação de avisos
Exporte os achados de um projeto ou biblioteca como Markdown, com um prompt de remediação personalizável para a sua equipe ou um LLM.
Uma imagem, um arquivo
Uma imagem Docker e um arquivo SQLite. Sem servidor de banco de dados, sem fila de mensagens, sem dependência de nuvem.
Roots autorregistrados
Tudo o que for montado em /roots é registrado e escaneado na inicialização — o nome do diretório vira o seu rótulo.
Node por projeto
Respeita o .nvmrc de cada projeto, instalando e armazenando em cache uma única vez a versão do Node que ele fixa.
10 idiomas
A interface do portal, os códigos de motivo de escaneamento e os status estão traduzidos para 10 idiomas.
Capturas
Veja em ação — o portal escaneando alguns projetos de demonstração. Clique em qualquer captura para ampliá-la.
Como se compara
O Sentinello não é um Dependency-Track mais pesado nem um Snyk mais barato. Ocupa outro nicho: a cauda longa de projetos que ninguém ligou a um pipeline.
| Sentinello | Dependency-Track | Snyk | Dependabot | |
|---|---|---|---|---|
| Sem configuração — aponte para uma pasta | ~ | ~ | ||
| Não exige SBOM / etapa de CI | ||||
| Escaneia lockfiles resolvidos reais | ~ | |||
| Detecção de pacotes maliciosos | ||||
| Auto-hospedado, sem SaaS | ||||
| Uma imagem + SQLite | ||||
| Nativo para IA (MCP + export) | ~ | |||
| Poliglota (Python, Go, …) | ||||
| Política corporativa / VEX | ~ | ~ |
O Dependency-Track só vê os projetos que alguém instrumentou com um pipeline de SBOM. O Sentinello encontra os que você esqueceu. Eles são mais fortes em política corporativa — se você já os roda em um pipeline maduro, mantenha-os. O Sentinello é para o resto do seu portfólio que ninguém está vigiando.
Por que criamos isto
Na era da IA, você publica mais do que consegue manter.
Hoje quem desenvolve sozinho cria, entrega e segue em frente em uma dúzia de projetos por ano — o site de marketing, o painel do cliente, o projeto paralelo que foi para produção sem alarde. Manter tudo isso seguro costumava significar dar SSH em cada cópia para rodar npm audit na mão, ou descobrir um CVE do Next.js por uma manchete dias depois de ele aparecer. Ninguém aguenta esse ritmo em uma dúzia de repositórios, então simplesmente não acontece.
Basta uma única dependência esquecida com uma falha crítica de execução remota de código. O site mais simples que você deixou de vigiar vira a porta de entrada.
“Por que não usar logo o Snyk ou o Dependabot?” Eles vivem dentro do pipeline de CI que você montou — e a cauda longa nunca ganhou um. O Sentinello é o sistema de alerta antecipado para todo o resto: aponte-o para uma pasta e ele vigia cada projeto que você esqueceu, revelando cada novo CVE em uma única fila antes que vire um incidente.
Como funciona
Três passos. Sem agentes para instalar nos seus projetos, sem contas para criar.
Aponte-o para o seu código
Monte seus repositórios em /roots ou adicione-os em Configurações → Roots. Cada diretório é registrado e descoberto automaticamente na inicialização.
Ele escaneia continuamente
Um processo em segundo plano compara suas dependências com os CVEs conhecidos conforme um agendamento, instalando a versão do Node que cada projeto fixa quando necessário.
Triagem em uma única fila
Cada achado de cada projeto chega a uma única fila que você pode filtrar por severidade — com alertas opcionais para Slack, Telegram ou um webhook.
Para quem é
O Sentinello é para todos que têm mais em produção do que conseguem vigiar — a pessoa que desenvolve sozinha, a equipe pequena, a agência que faz malabarismo com trabalho de clientes.
- Você publica projetos paralelos e sites de clientes que precisam continuar seguros muito depois do lançamento.
- Você quer uma visão de todo o portfólio sem cabear CI em cada repositório.
- Você prefere auto-hospedar a entregar o inventário do seu código a um SaaS.
Se você é uma organização grande com Snyk ou Dependabot já integrados em um pipeline maduro, mantenha-os — o Sentinello não tenta substituir o SCA corporativo. Ele está aqui para o resto do seu portfólio que ninguém vigia. É de código aberto e licenciado sob MIT, então você pode ler exatamente o que ele faz.
Notas de versão
O Sentinello é atualizado com frequência — veja o que cada versão trouxe.
Um painel que deixava uma única fonte falar pelo projeto inteiro
v3.5.0 · 20 de ago. de 2026- A coluna <strong>Estado</strong> do painel relatava uma única fonte e descartava as demais. Cada varredura grava uma linha por fonte e elas terminam com milissegundos de diferença, então a coluna mostrava a que terminava por último — na prática sempre OSV. Todo projeto lia “Banco de dados OSV ainda não baixado” enquanto o npm audit os havia analisado bem e encontrado vulnerabilidades reais. Agora Estado carrega um selo por fonte que não conseguiu responder, cada um nomeando a fonte, e não mostra nada quando todas as fontes ativas estão bem. O histórico de varreduras ganhou uma coluna <strong>Fonte</strong> pelo mesmo motivo: uma varredura gravava três linhas idênticas sem como distingui-las.
- Configurações → Fontes afirmava que um cache estava atualizado enquanto era reconstruído. O estado que o portal lê só era gravado ao fim de uma sincronização, então durante toda uma reconstrução de vários minutos ele seguia mostrando a contagem anterior — enquanto cada varredura recusava corretamente o cache meio apagado. Ele também nunca carregava a versão do normalizador, que o scanner exige, então uma mudança de versão produzia a mesma afirmação falsa sem reconstrução nenhuma. A linha agora diz <strong>Reconstruindo…</strong> com a contagem anterior esmaecida, ou <strong>Reconstrução pendente</strong> quando um cache está inutilizável e nada está resolvendo.
- Um cache que terminava de baixar deixava todo projeto preso no veredito obtido enquanto ele faltava. Nada varria de novo, então <code>osv_db_not_seeded</code> ficava lá até a próxima varredura agendada, ou até você notar e clicar em Varrer. O Sentinello agora enfileira uma varredura completa assim que um cache volta a ser utilizável. Uma atualização incremental não enfileira nada. A atualização conta: se esta versão chegar a uma instância cujos projetos ainda carregam aquele veredito de antes de o cache terminar, o worker percebe a divergência no primeiro boot e resolve para você — sem varredura para lembrar de rodar.
Um aviso que apontava a versão que o corrigia
v3.4.0 · 18 de ago. de 2026- O gemnasium escreve alguns poucos avisos com um espaço entre o comparador e sua versão — <code>< 0.5.2</code> em vez de <code><0.5.2</code> — e o analisador lia esse par como dois tokens separados. O <code><</code> órfão ficava com um limite vazio, e a versão que sobrava sozinha era guardada em cache como versão exata. Assim, o aviso do <code>fresh</code> apontava a 0.5.2 como vulnerável quando 0.5.2 é justamente a versão que o corrigiu — e apontava sem correção disponível, porque uma versão fixada não carrega nenhum destino de atualização. São 19 avisos escritos desse jeito e todos eram lidos errado: 15 perdiam o intervalo por completo e 7 fixavam uma versão que o próprio registro indica como correção; o <code>pg</code> fixava onze.
- O Sentinello parou de interpretar por conta própria a sintaxe de intervalos do npm e agora entrega cada intervalo à própria implementação do npm, o que aposenta de uma vez toda uma família de leituras erradas. Para o npm, <code><=3.3</code> significa “até o fim da linha 3.3” — lido ao pé da letra, parava na 3.3.0 e perdia a 3.3.1, que é um aviso real do <code>converse.js</code> — e <code>=103</code> significa toda a linha 103 em vez de um único ponto, algo que o <code>binaryen</code> declara oito vezes. Intervalos com circunflexo, til, <code>1.x</code> e hífen também passam a ser lidos, quando antes um registro escrito em qualquer um deles era descartado sem aviso. Conferido nos 4.696 intervalos de versões distintos que o gemnasium publica para npm: interpretá-los por conta própria divergia do npm em 9; delegar não diverge em nenhum. Só o npm é afetado — em Python, <code>==1.0</code> é uma versão exata e não um curinga, então aplicar ali a regra do npm inventaria achados.
- Três coisas que a leitura do npm acerta ao instalar um pacote e erra num aviso ficam retidas. Um intervalo que não nomeia versão alguma — <code>*</code>, <code>x</code>, um campo vazio — significa “qualquer versão” quando o npm instala algo e “ninguém preencheu isto” num aviso, então é recusado em vez de virar um achado contra todas as versões já publicadas. Um <code>||</code> solto no fim já não pode alargar para tudo o intervalo que o antecede. E <code>>0</code> continua significando todas as versões, porque o <code>pandora-doomsday</code> declara assim seu pacote malicioso e a leitura do npm inocentaria todo o 0.x. À parte disso, um aviso cuja correção declarada fique no início do seu próprio intervalo afetado ou abaixo dele já não tem esse limite substituído — isso produzia um intervalo que não correspondia a nada, ou seja, um achado que para de relatar em silêncio — e a regra para descartar um intervalo assim agora é compartilhada com a fonte OSV em vez de escrita uma vez por fonte, que foi exatamente como as duas passaram a discordar.
- Os testes que continuavam deixando tudo isso passar agora geram suas entradas em vez de listá-las. Cada intervalo de versões distinto que o gemnasium publica para npm é conferido contra a própria implementação do npm a cada build, junto com todo o produto cartesiano da gramática de intervalos e todas as ordenações dos eventos de intervalo do OSV. Executada contra a versão anterior, essa varredura falha em 28 intervalos, enquanto os dez exemplos escritos à mão que ela substitui passavam todos. Qualquer grafia inventada rio acima daqui em diante quebra o build já na primeira importação, e não quando alguém repara no achado que ela produziu.
- Cada linha do código por trás destes achados agora é exercitada pela suíte de testes — instruções, ramificações, funções e linhas a 100%, sem exceções em todo o repositório. É a resposta direta a como os erros das últimas versões escaparam: cada um era uma ramificação que nada executava, relatando sucesso sem fazer nada. Fechar os 109 restantes revelou vários que constavam como verificações de segurança inalcançáveis e simplesmente não estavam testados, além de uma regra de cobertura que havia meses não verificava nada porque o arquivo que ela nomeava tinha sido movido. Essa regra e as 500 linhas de exceções ao seu redor dão lugar a uma única, de modo que código sem testes agora quebra a compilação em vez de baixar uma média.
- As últimas lacunas defensivas também foram fechadas: um limite superior OSV ilegível deixa o intervalo válido aberto, limites de fallback são validados depois de aplicados e um limite npm de pré-lançamento explícito como <code><1.2.3-0</code> mantém seu significado exato.
Avisos que declaravam vulnerável qualquer versão
v3.3.2 · 17 de ago. de 2026- Um aviso cujo intervalo afetado não tem fim corresponde a todas as versões, para sempre — um achado que nenhuma atualização consegue encerrar e que, na página, não se distingue de uma vulnerabilidade realmente sem correção. Dois avisos de <code>xlsx</code> chegaram assim e apontaram uma versão 0.20.3 totalmente corrigida como de severidade alta e sem correção disponível, em 11 projetos ao mesmo tempo, enquanto o <code>npm audit</code> relatava corretamente esses mesmos dois avisos como corrigidos em 0.19.3 e 0.20.2. A causa está a montante e é deliberada: o GitHub não nomeia uma versão corrigida que o registro não sirva sob aquele nome de pacote — a SheetJS publica a 0.19.3 e as seguintes apenas a partir do seu próprio CDN —, então declara o intervalo como “tudo a partir de 0” e registra o limite real em outro campo que o Sentinello nunca lia. Agora lê. Havia 15 avisos npm afetados, entre eles <code>babel-traverse</code> e <code>sandbox</code>. Os 480 que de fato não têm correção continuam dizendo isso, e um registro que já declara o próprio limite nunca é sobrescrito
- Um aviso do gemnasium que deixava o intervalo em aberto enquanto listava as versões que o corrigem passa a ser limitado pela mais alta delas. Um intervalo sem fim afirma que também as versões futuras são vulneráveis, e nenhum registro que nomeie uma correção pode querer dizer isso
- O gemnasium escreve os intervalos de versão do Python como interseções PEP 440 — <code>>=5.0,<5.8</code> — e o analisador separava os tokens apenas por espaços, de modo que tudo virava um só: um limite inferior ilegível e nenhum limite superior. Intervalos assim não correspondem a nada, e não corresponder a nada significa não relatar nada. Estavam nesse estado 2.830 dos 7.159 registros PyPI em cache. Esse era um dos três motivos pelos quais Python, Go e Rust foram retirados na 3.3.0; os outros dois continuam em aberto, portanto seguem retirados
A mesma versão da 3.3.0, com uma imagem Docker que compila
v3.3.1 · 15 de ago. de 2026- A 3.3.0 foi publicada no npm e no GitHub, mas sua imagem de contêiner falhou ao compilar, então no momento do lançamento não existia 3.3.0 no GHCR nem no Docker Hub. O Dockerfile lista cada pacote do workspace que instala, e um deles — o de comparação de versões — nunca havia sido listado. Nada dentro da imagem o importava até esta versão, então a omissão jamais tinha feito diferença. Desde então foi publicada uma imagem 3.3.0 corrigida, construída a partir do próprio código de aplicação da 3.3.0, de modo que <code>docker pull sentinello:3.3.0</code> volta a funcionar. A 3.3.1 carrega a mesma correção na árvore de código. Se você usa a CLI, a 3.3.0 já estava correta.
Apenas os ecossistemas que realmente funcionam — e notificações em que você pode confiar
v3.3.0 · 15 de ago. de 2026- Uma notificação podia chegar vazia. Um operador recebeu uma mensagem do Telegram anunciando vulnerabilidades em um projeto e sem listar nenhuma. O envio é delimitado por projeto, mas rodava uma vez por scanner: a passagem do npm audit recebeu dois eventos pendentes do OSV, não correspondeu a nenhum e ainda assim renderizou o título sobre uma lista vazia. Depois marcou ambos os eventos como entregues — então as duas ocorrências que nunca nomeou ficaram registradas como notificadas, e nada revisita um evento entregue. Agora um evento só é enviado se puder ser descrito; caso contrário fica pendente e é reconsiderado na próxima varredura
- Uma ocorrência é reportada com a pior classificação que qualquer fonte lhe deu, e essa escalada chegava ao painel, aos totais por projeto e ao portão <code>--fail-on</code> da CLI — mas não aos limiares de notificação. A notificação rodava antes da corroboração, então o evento ficava carimbado com a classificação da fonte sobrevivente e nunca era reescrito. Em uma instância real, 135 ocorrências abertas carregavam uma severidade de evento abaixo da real, <strong>41 delas registrando uma crítica como baixa, alta ou moderada</strong>. Um destino filtrado para crítica e alta nunca teria sido alertado por nenhuma delas, permanentemente
- Varreduras agendadas paravam à meia-noite em vez de continuar. “A cada 3 horas a partir das 07:00” rodava às 07, 10, 13, 16, 19 e 22 e só voltava às 07:00 — seis varreduras por dia em vez de oito, com uma janela cega de nove horas toda noite — enquanto as Configurações continuavam informando o intervalo escolhido. “A cada 6 horas a partir das 20:00” conseguia uma varredura por dia. Os horários agora atravessam a virada do dia
- <strong>Python, Go e Rust foram retirados.</strong> Não é cautela com arestas: suas falhas se reportavam como limpo. A derivação de correções e a ordenação de versões são apenas semver, então um aviso do OSV sobre Django recomendava “atualizar para 3.2.23” contra um 4.2 instalado; os nomes de pacotes PyPI do OSV não são canonicalizados conforme a PEP 503, então nunca coincidiam com os do resolvedor; e o parser de intervalos do gemnasium não consegue ler interseções com vírgula da PEP 440. Uma fonte que responde “sem vulnerabilidades” pelos motivos errados é pior do que uma que não é oferecida, então elas sumiram por completo da superfície do produto — sem chave, sem descoberta, sem download. <strong>As ocorrências que você já coletou com elas continuam visíveis e podem ser silenciadas; nada é excluído.</strong> O ecossistema npm agora se chama <strong>Node.js</strong>, que nomeia o ecossistema de pacotes de fato varrido em vez de uma linguagem
- <strong>Configurações → Fontes</strong> foi reconstruída em torno disso. Cada fonte repetia a própria explicação ao lado da própria chave, e cada uma apoiada em cache trazia um painel de estado de cinco linhas com o próprio botão “Atualizar agora” em tamanho cheio — mesmo que esse botão enfileire um único sinal compartilhado por fonte, não importa quantas vezes apareça. As chaves agora dizem apenas se uma fonte está ativa; o que cada uma acrescenta, o que baixa e de onde, e quando roda foi para uma única tabela de referência abaixo delas, e o estado de sincronização virou uma linha
- Pacotes que o próprio lockfile do npm declara alcançáveis a partir da produção estavam sendo rebaixados para somente desenvolvimento. Um lockfile que omite <code>dev: true</code> é o npm afirmando que o pacote É alcançável a partir da produção — uma afirmação mais forte do que o manifesto raiz pode fazer — mas o resolvedor a sobrescrevia sempre que o nome também aparecia em <code>devDependencies</code>, exatamente quando o npm estava certo. Medido em 130 projetos reais: 142 pacotes rebaixados em 97 deles — lodash, semver, postcss, tailwindcss, @babel/runtime — escondendo sete ocorrências abertas do filtro somente-produção em uma instância
- Qualquer pacote fixado em uma versão como <code>0.0.0-20180523222229-09b5706aa936</code> não correspondia a <strong>nenhum aviso</strong>, nem mesmo a um aberto, e a varredura reportava ok com zero ocorrências. Um limite de aviso <code>introduced: 0</code> era comparado como o release 0.0.0, e em semver uma prerelease ordena abaixo do seu release. 330 dos 19.085 intervalos comparáveis de um cache real estavam armazenados como intervalos que nada podia satisfazer
- Uma sincronização do OSV interrompida podia apagar um aviso permanentemente. O caminho incremental excluía as linhas de um aviso e só então buscava a substituição dentro de um try/catch, então qualquer timeout, 5xx ou desligamento o removia por inteiro — e ainda avançava o cursor, deixando o id permanentemente para trás. A perda era silenciosa, sobrevivia até a próxima ressemeadura completa e acontecia em uma sincronização que reportava sucesso. O cache do <code>npx sentinello</code> se erodia do mesmo jeito a cada execução instável. Ambos agora buscam primeiro e substituem depois
- O <code>--dep-type dev</code> da CLI significava “alcançável a partir de dev de algum modo”, enquanto o portal significa “alcançável <em>somente</em> a partir de dev”, então um pacote alcançável pelos dois aparecia em uma visão e não na outra — 177 ocorrências abertas diferem entre as duas leituras em uma instância. A CLI agora usa a regra do portal e respeita o campo <code>withdrawn</code> do OSV, que ela era estruturalmente incapaz de ler: 585 linhas de um cache npm real carregam um, e todas eram reportadas como ocorrências ativas
- Um aviso do gemnasium que diz que uma vulnerabilidade começa <em>depois</em> de uma versão — <code>>1.2.8</code> em vez de <code>>=1.2.8</code> — era lido como se a própria versão do limite fosse afetada. O sequestro do pacote <code>rc</code> em 2021 está escrito exatamente assim, e 1.2.8 é sua última versão limpa: justamente a que a nota de remediação do próprio aviso manda manter. Todo projeto com <code>rc</code> instalado via um achado crítico de malware, sem correção disponível, contra uma versão que nunca foi comprometida. Os limites agora são preservados exatamente como o aviso os declara, e os falsos críticos desse tipo desaparecem
- O mesmo arredondamento agia no sentido inverso e escondia achados reais. Um aviso limitado por <code><=2.0.0</code> era guardado como “abaixo de 2.0.0”, então 2.0.0 — a versão sobre a qual ele é mais explícito — não era reportada, e um aviso que nomeava exatamente uma versão afetada virava um intervalo vazio e era descartado por inteiro. Espere alguns achados novos que sempre estiveram lá, apenas invisíveis
- Intervalos escritos com sintaxe que o Sentinello não implementa — <code>^1.0.0</code>, <code>~1.0.0</code> — eram guardados como versão exata presa ao texto literal, incapaz de casar com qualquer coisa enquanto permanecesse em cache: um aviso com aparência ativa que jamais poderia disparar. Esses registros agora são recusados em vez de guardados numa forma que não funciona, e avisos cujo limite superior não traz uma versão corrigida limpa finalmente recebem sugestão de atualização
- O auxiliar que mascara uma URL de webhook ou um token de bot antes de chegar a uma linha de log imprimia os curtos por inteiro. Ele rejeitava valores de seis caracteres ou menos, mas então mantinha uma cabeça de oito caracteres e uma cauda de quatro, e nada verificava se essas duas metades se encontravam — então todo segredo entre 7 e 12 caracteres voltava completo. Agora ele esconde ao menos oito caracteres ou redige o valor por inteiro
Os achados mostram quais fontes concordam, e avisos retirados deixam de ser reportados
v3.2.0 · 15 de ago. de 2026- Quando mais de uma base de avisos reporta a mesma vulnerabilidade, o Sentinello sempre manteve um único achado: reportar a mesma falha três vezes porque três bases a conhecem é ruído. O que ele fazia antes era descartar tudo sobre as fontes que unificava, então uma vulnerabilidade confirmada de forma independente pelo npm audit, pelo OSV e pelo GitLab gemnasium parecia idêntica a uma que só uma base jamais reportou. Numa instância real isso são dois terços dos achados. Agora cada achado carrega as demais fontes que o reportaram, e seus selos aparecem ao lado do sobrevivente
- Um achado é reportado com a PIOR severidade atribuída por qualquer fonte. As bases realmente discordam — o gemnasium calcula a severidade a partir do vetor CVSS enquanto o npm audit adota a categoria do GitHub — e, para um scanner, a leitura cautelosa é a que vale agir. Isto não é cosmético: um achado elevado muda de categoria no painel, nos totais do projeto, na barreira <code>--fail-on</code> da CLI e nos limiares de notificação. Espere alguns números mudarem na primeira varredura após a atualização; nada novo foi detectado, os mesmos achados estão sendo classificados com mais cautela
- Onde as fontes discordam, o achado exibe ao lado da severidade um controle que abre o que cada uma realmente disse: o identificador de aviso dela e a classificação dela. Ele só aparece quando há divergência a explicar, de modo que um achado avaliado igualmente por todas permanece limpo
- O OSV registra a retirada em um campo próprio e o GitHub remove avisos retirados antes que o <code>npm audit</code> sequer os veja, mas o GitLab gemnasium não tem esse campo em seu esquema. Ele retira um aviso reescrevendo o registro: o título passa a ser “False Positive”, “Withdrawn Advisory: …” ou “Duplicate Advisory: …”, enquanto as versões que ele citava continuam ali. O Sentinello lia essas versões e reportava achados que o GitLab havia retirado explicitamente: 383 registros em JavaScript, Python, Go e Rust, incluindo um que reportava o <code>express</code> sob o título “False Positive”. Todos são descartados agora, o que também elimina toda uma classe de achados duplicados, já que 278 dos 383 são avisos retirados por duplicarem outro
- A verificação compara os marcadores de retirada de forma exata, em vez de procurar as palavras em qualquer lugar, então um aviso legítimo que trate *sobre* um falso positivo continua sendo reportado: o CVE-2026-39395 do Cosign, intitulado “Cosign’s verify-blob-attestation reports false positive when payload parsing fails”, não é afetado
- O cache do gemnasium se reconstrói sozinho na primeira sincronização após esta atualização, e então os avisos retirados desaparecem. Não há nada a fazer: acontece na sincronização diária, ou imediatamente em Configurações → Fontes → Atualizar
Os intervalos de versão dos avisos estão corretos nos dois sentidos
v3.1.1 · 14 de ago. de 2026- Alguns avisos do GitLab gemnasium não trazem nenhum intervalo de versões legível por máquina — 698 dos 10.777 de JavaScript. O Sentinello preenchia essa lacuna presumindo que todas as versões abaixo da primeira correção listada estavam afetadas, mas essa lista não é ordenada e contém uma correção por ramo de lançamento, então o palpite caía com frequência no ramo errado. O protobufjs 7.6.5 era reportado como execução remota de código crítica embora aquele ramo tenha sido corrigido em 7.5.5, e três avisos distintos afirmavam que toda versão do vite abaixo de 8.0.5 era vulnerável. O Sentinello não inventa mais intervalos: recupera o real do mesmo aviso publicado sob seu outro identificador, da própria descrição do aviso ou — somente se você tiver o OSV ativado — da cópia do OSV já presente na sua máquina, e descarta o registro em vez de adivinhar quando nenhuma dessas vias responde. Espere que alguns críticos desapareçam
- O OSV descreve um aviso corrigido em vários ramos como uma entrada separada por ramo, e o Sentinello ficava com a primeira e descartava as demais — 1.927 intervalos de versões vulneráveis só em JavaScript, cada um deles uma vulnerabilidade real que deixou de ser vista. O aviso do minimatch cobre oito ramos e apenas um sobrevivia, de modo que um minimatch 3.0.4 ou 9.0.0 instalado não era reportado; next e ua-parser-js perdiam ramos do mesmo jeito. Agora todos os ramos são mantidos. Espere que apareçam novos achados — essas vulnerabilidades sempre estiveram lá, apenas invisíveis
- Os dois caches de avisos se reconstroem sozinhos na primeira sincronização após esta atualização, porque os intervalos que guardam foram produzidos pelo código antigo. Não há nada a fazer: acontece na sincronização diária, ou imediatamente em Configurações → Fontes → Atualizar, se preferir não esperar
As constatações silenciadas saem do caminho, e o banco de dados para de crescer sem fim
v3.1.0 · 13 de ago. de 2026- Uma constatação silenciada é uma decisão que você já tomou, então agora ela sai por completo da página do projeto em vez de ficar ali esmaecida. Não é só arrumação: todos os números da página — a contagem do título, os selos das duas abas, a paginação, os totais por biblioteca, o botão de exportar — são calculados a partir das mesmas linhas, de modo que a página finalmente concorda com o painel, com as ferramentas MCP e com a exportação de alertas, que já deixavam as silenciadas de fora. Um controle “Mostrar silenciados” as traz de volta quando você quiser, inclusive num projeto cujas constatações estão *todas* silenciadas
- Digitar em uma caixa de diálogo não perde mais o foco depois de um único caractere. Esse defeito tornava praticamente impossível preencher o campo Motivo do diálogo de silenciamento — obrigatório, e a única coisa que torna um silenciamento auditável meses depois. O mesmo diálogo também deixou de herdar o alinhamento da linha de tabela de onde foi aberto, e é por isso que silenciar uma constatação produzia um diálogo alinhado à direita enquanto silenciar um projeto não
- O histórico de varreduras não cresce mais para sempre. Nada jamais havia excluído uma linha de varredura por idade, então um projeto que permanecia em disco acumulava uma linha por fonte a cada passagem, indefinidamente — uma instância real chegou a 2,2 GB em menos de três meses. Configurações → Avançado agora traz um período de retenção, 90 dias por padrão, e o worker limpa o que passar disso a cada hora, sempre mantendo as 100 varreduras mais recentes de cada projeto. Constatações, silenciamentos e histórico de notificações nunca são tocados; apenas o registro de varreduras. Com 90 dias, uma instância que se atualiza não apaga nada na primeira passagem: a limpeza só começa quando o histórico realmente ultrapassa esse período, ou quando você mesmo o reduz
- A maior parte desse crescimento era a saída bruta do `npm audit`, guardada por inteiro a cada varredura bem-sucedida e lida por absolutamente nada — 98,7% do banco daquela instância. As varreduras agora registram um resumo curto, o que leva uma linha de cerca de 79 KB para uns 100 bytes, com um teto rígido para que nenhum scanner repita isso
- No MCP, `get_dashboard_summary` agora informa que um projeto silenciado sai dos seus totais enquanto `list_projects` continua a retorná-lo. Os dois contam populações diferentes de propósito, e um agente que os comparava lia isso como um defeito. `list_scans` também parou de devolver a saída bruta do scanner de cada varredura, que podia chegar a uns 16 MB numa única resposta
O download do gemnasium volta a funcionar — e a CLI devolve o terminal
v3.0.1 · 4 de ago. de 2026- O download do GitLab gemnasium falhava na 3.0.0 com `HTTP 406`, para todo mundo. O fetch nativo do Node adiciona um cabeçalho `Sec-Fetch-Mode: cors` que um programa não pode remover, e o GitLab recusa qualquer requisição de arquivo do repositório que o carregue — então nunca teve a ver com sua rede, seu IP ou quantas vezes você tentou. Agora o download usa uma requisição HTTPS comum e funciona
- O arquivo é buscado pelo id do commit em vez do nome do branch, então todos que atualizam a partir do mesmo commit compartilham uma cópia em cache em vez de cada um pedir ao GitLab que gere um arquivo de 60 MB. Um primeiro download que levava quase sete minutos agora termina em segundos
- A CLI terminava todo o trabalho — relatório escrito, resumo impresso — e depois nunca devolvia o terminal. A conexão do download ficava aberta por trás, mantendo o processo vivo; agora ela é fechada assim que o arquivo é lido
- Uma fonte que recusa um download não trava mais por três minutos antes de avisar. Ela avisa em segundos e, num terminal, oferece tentar de novo — repetindo apenas a fonte que realmente falhou
- `--fail-on` é honesto nos dois sentidos. Ele recusa uma execução cuja fonte de avisos não pôde ser consultada, em vez de relatar uma varredura limpa que nunca fez; e não falha mais por causa de uma fonte que você mesmo desligou com `SENTINELLO_OSV_FEED_URL=off` ou `SENTINELLO_GEMNASIUM_FEED_URL=off` e nunca baixou
O Sentinello agora roda sem portal nenhum
v3.0.0 · 3 de ago. de 2026- Os scanners saem como CLI no npm. `npx sentinello` percorre uma pasta, encontra todos os projetos abaixo, confere contra npm audit, OSV e GitLab gemnasium, e escreve um parecer em markdown com um prompt de remediação anexado — sem instalação, sem conta, sem banco de dados, e nada do seu código sai da máquina
- Em pipe, o parecer é a única coisa no stdout, então `npx sentinello | claude -p "$(cat -)"` entrega a um agente uma lista de trabalho completa sem nada corromper o documento
- A primeira execução não perde mais a fonte gemnasium por um download recusado. O GitLab recusa seu arquivo por um ou dois minutos seguidos, e a repetição antiga desistia em treze segundos; agora a CLI espera passar, diz por que está esperando, e aceita `--feed-wait` se os três minutos padrão não servirem
- As duas estimativas de download foram medidas, não chutadas: o export npm do OSV é informado como 204 MB em vez de 196, e o arquivo do gemnasium como 52 MB em vez de 80. O aviso de consentimento marca uma estimativa com um til para que nunca seja confundida com um tamanho informado pelo servidor
- Um valor com cara de flag agora é recusado em vez de aceito ao pé da letra — `--out --` escrevia um parecer em um arquivo chamado `--` dentro do seu projeto e relatava sucesso
- O painel de Novidades não escapa mais pela parte de baixo da janela quando uma versão tem muito a dizer
O documento de parecer realmente chega — e conta o que você quer dizer
v2.6.0 · 29 de jul. de 2026- get_project_advisory agora retorna o próprio documento de parecer. Antes, os clientes conectados recebiam só os metadados — um nome de arquivo e uma contagem — e nunca o documento, embora a ferramenta o descrevesse como uma lista de trabalho completa
- A exportação de pareceres agora tem uma entrada por parecer distinto, com suas fontes mescladas, em vez de uma por linha de scanner: uma vulnerabilidade que npm audit e OSV relatam é um único item de trabalho carregando os dois IDs, não dois quase idênticos. Isso vale também para o Download .md do portal, e a contagem agora bate com o painel
- Um projeto grande demais para caber em uma resposta MCP agora é paginado — o documento informa que está incompleto e dá a chamada exata para buscar o resto, em vez de ser cortado em silêncio onde um agente leria o restante como limpo
- Toda entrada de toda ferramenta MCP agora tem uma descrição, e uma nova ferramenta list_mutes expõe os IDs de silenciamento de que unmute precisa — antes só obteníveis criando o silenciamento na mesma sessão
- Corrigida uma falha nas contagens de severidade: um achado cuja severidade não fosse um dos cinco valores conhecidos era contado como achado mas não entrava em nenhum balde de severidade, então um projeto cujo único achado tivesse isso parecia completamente limpo
O relatório de vulnerabilidades, direto pelo MCP
v2.5.0 · 28 de jul. de 2026- Clientes MCP conectados podem obter o relatório Markdown completo de um projeto com a nova ferramenta get_project_advisory — o mesmo documento do botão Baixar .md do portal, sem copiá-lo do navegador
- Descobertas silenciadas não entram mais no relatório do projeto, então um agente nunca recebe um trabalho cujo risco você já aceitou
- Observação: como o relatório contém o seu prompt de exportação, um cliente MCP agora consegue ler o que você escreveu em Configurações → Exportação
Popups sem corte e um prompt de exportação mais rigoroso
v2.4.3 · 26 de jul. de 2026- Os menus suspensos, o popover de caminho de dependência e o menu de exportação de avisos não são mais cortados pela tabela ou pelo diálogo em que ficam — eles são renderizados acima da página e abrem para cima quando não há espaço embaixo
- O prompt padrão de exportação de avisos agora pede que o agente planeje antes de editar qualquer coisa, agrupe os achados que compartilham uma mesma correção e detalhe o impacto no código de cada mudança de versão; ele mira zero achados e descarta os atalhos para um zero falso — silenciar, ampliar intervalos ou reduzir o escopo da análise —, deixando o que é realmente irredutível em uma tabela de resíduos datada
O branch em sua própria coluna
v2.4.2 · 25 de jul. de 2026- O branch do git em que o projeto foi analisado agora tem uma coluna própria na lista de projetos — texto simples, sem ícone — em vez de ficar embaixo do nome do projeto
Desligamentos limpos
v2.4.1 · 25 de jul. de 2026- Reiniciar o contêiner não interrompe mais uma análise no meio da gravação, e o worker inicia imediatamente em vez de tentar de novo por ~30 segundos
- Defina stop_grace_period: 60s (ou --stop-timeout 60) no seu arquivo compose para dar espaço a ele — o README e a documentação do Docker agora explicam isso
Análise poliglota — Python, Go e Rust se juntam ao npm
v2.4.0 · 25 de jul. de 2026- O Sentinello agora analisa projetos Python, Go e Rust além de npm — os arquivos de bloqueio são resolvidos totalmente offline e cada projeto informa sua cobertura de análise (completa, parcial ou não auditável), de modo que as lacunas fiquem visíveis em vez de silenciosas
- O banco gemnasium do GitLab se junta ao npm audit e ao OSV como fonte de avisos offline, deduplicada em relação às demais por alias CVE/GHSA; Configurações → Fontes agora é uma matriz Linguagens × Fontes com escopo de notificação por célula, e o próprio npm audit pode ser desativado desde que uma fonte permaneça ativa
- Os achados agora registram o branch do git de onde vieram, exibido na lista de projetos, no cabeçalho do projeto e em todas as notificações
- As linhas de projeto trazem suas próprias ações — analisar agora, copiar ou baixar o aviso, silenciar ou reativar e editar tags — assim uma rodada de triagem não exige mais entrar em cada projeto
- O painel de projetos passou de ~3,3 s para ~0,03 s, e a navegação agora mostra estados de carregamento em vez de parecer travada
- Segurança: 25 avisos de dependências resolvidos, incluindo CVEs do libvips que estavam ativos no otimizador de imagens do portal e nove avisos do Next.js que afetavam o portal distribuído
- O prompt padrão de exportação de avisos agora cobre idade mínima de publicação, verificação do arquivo de bloqueio e overrides obsoletos
Configuração de MCP mais simples, sem variáveis de ambiente
v2.3.0 · 9 de jun. de 2026- Configure o MCP inteiramente em Configurações → MCP: gere um token para ativar o endpoint /api/mcp e limpe-o para desativá-lo — as variáveis de ambiente SENTINELLO_MCP_ENABLED e SENTINELLO_MCP_API_TOKEN foram removidas (um token de ambiente existente é importado uma vez na atualização)
- Trechos de conexão prontos para colar para Claude Code, Codex, Cursor e Claude Desktop, já preenchidos com o seu token
- Quando SENTINELLO_PORTAL_BASE_URL é definida no ambiente, ela aparece como somente leitura em Configurações → Avançado, pois continua sendo autoritativa e é reaplicada a cada inicialização
Menos alarmes falsos e achados que se limpam sozinhos
v2.2.0 · 9 de jun. de 2026- Os avisos de malware agora correspondem à versão comprometida exata — uma versão limpa ou já corrigida de um pacote que esteve comprometido deixa de ser sinalizada
- Achados duplicados agora se resolvem sozinhos na próxima varredura, de modo que entradas antigas ou órfãs são removidas automaticamente
- Os rótulos de produção e desenvolvimento agora são calculados de uma única forma consistente em todas as fontes (npm e OSV)
Um cabeçalho de projeto mais limpo e filtros consistentes
v2.1.0 · 6 de jun. de 2026- Cabeçalho de projeto simplificado — renomeie ao lado do título, com silenciar e tags como ícones
- Filtre as ocorrências por fonte (npm / OSV) em um novo menu suspenso ao lado do filtro de tipo de dependência
- Menus suspensos unificados e consistentes em todo o app, com busca ao digitar em listas longas como fusos horários
Orientações de atualização mais claras
v2.0.1 · 4 de jun. de 2026- Passos de atualização ampliados para as alterações incompatíveis da 2.0
- O README indica a vinculação de porta somente em localhost
Varredura multi-fonte e uma instalação reforçada e segura por padrão
v2.0.0 · 4 de jun. de 2026- OSV como segunda fonte opcional (Configurações → Fontes, desativada por padrão) com detecção de pacotes maliciosos, comparada com o banco de dados público do OSV em um cache local
- Os achados agora são mesclados entre fontes — uma linha por vulnerabilidade, cada fonte marcada, a melhor correção disponível e a união dos caminhos de dependência, com filtro por fonte e um popover de caminho de dependência
- Reforço de segurança: o endpoint MCP está desativado por padrão e exige um token, a entrega de webhooks é protegida contra SSRF, uma porta de login opcional do portal, e o contêiner é executado como usuário sem privilégios
- Configurações agora é uma seção de nível superior com barra lateral e uma página de Perfil
Integração MCP e novidades
v1.4.0 · 29 de mai. de 2026- Servidor MCP em /api/mcp para Claude Desktop, Cursor e outros clientes
- Nova seção Configurações → MCP com URL do servidor e gerenciamento de tokens
- Etiqueta de novidades e um histórico de notas de versão
Correção da versão no rodapé
v1.3.1 · 28 de mai. de 2026- A versão em execução é exibida corretamente no rodapé
Melhorias nas notificações
v1.3.0 · 28 de mai. de 2026- Filtrar notificações por ambiente
- Formulário de edição de destinos mais simples
- Duplicar um destino de notificação existente
Páginas de Projetos e Bibliotecas
v1.2.0 · 24 de mai. de 2026- A tela inicial é dividida em páginas dedicadas de Projetos e Bibliotecas
Recarregamento da agenda em tempo real
v1.1.2 · 24 de mai. de 2026- O worker recarrega a agenda de varredura assim que você salva alterações no portal
Exclusões mais seguras e um aviso de atualização mais claro
v1.1.0 · 23 de mai. de 2026- Confirmação antes de excluir raízes e destinos de notificação
- Aviso de atualização movido para um banner superior dispensável
- O worker remove raízes obsoletas quando o ponto de montagem desaparece
Correções de precisão do scanner
v1.0.1 · 23 de mai. de 2026- Descarta achados cuja versão instalada não está realmente na faixa vulnerável
- Permite excluir um destino de notificação com histórico de envios
Primeira versão de código aberto
v1.0.0 · 23 de mai. de 2026- O primeiro lançamento público do Sentinello
Roadmap
Hoje o Sentinello vigia suas dependências em várias linguagens. É para cá que ele vai — e o que você pode pedir.
Priorização mais inteligente
PlanejadoClassifique os achados por explorabilidade e se o código vulnerável é realmente alcançável — triagem do que importa primeiro.
Mais integrações
PlanejadoMais canais de notificação e formas de conectar o Sentinello às ferramentas que sua equipe já usa.
Análise estática (SAST)
PlanejadoDetecte padrões de código arriscados no seu próprio código, não só CVEs conhecidos nas dependências.
Varredura de segredos e licenças
PlanejadoSinalize segredos commitados e problemas de licença no mesmo portfólio, na mesma fila.
Diga o que você integraria ou escanearia em seguida — abra uma issue no GitHub e ajude a moldar o roadmap.