SentinelloSentinello

Система раннего предупреждения для зависимостей, за которыми вы перестали следить.

В эпоху ИИ вы выпускаете больше проектов, чем способны поддерживать. Sentinello следит за каждым из них и выявляет известные CVE в их зависимостях Node.js — чтобы забытый проект никогда не превратился в инцидент.

Запустите одной командой:

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

Работает на linux/amd64 и arm64

Без аккаунта. Без SaaS. Без телеметрии. Один образ Docker и один файл SQLite — ваш код и результаты никогда не покидают вашу машину.

Или обойдитесь вовсе без портала

Те же сканеры поставляются как CLI. Без установки, без аккаунта, без базы данных: запускается, печатает сводку, с которой может работать ваш агент, и завершается.

npx sentinello

В конвейере stdout несёт только markdown, поэтому сводка доходит до агента без искажений:

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

Обходит папку

Укажите каталог — и он найдёт все проекты внутри, останавливаясь на корне каждого, чтобы монорепозиторий считался один раз, а не пятьдесят. .gitignore и .sentinelloignore учитываются.

Проверяет три источника

Определяет точные установленные версии из lock-файла и сверяет их офлайн с локальным кэшем сводок. Ни одного сетевого запроса на проект, и ничего из вашего кода не отправляется наружу.

Пишет сводку

Датированный markdown-файл с находками и приложенным промптом по устранению: сначала разобрать, предпочитать обновление родительского пакета переопределениям, проверять исправления в lock-файле.

Чем это отличается от npm audit

Это не замена npm audit: он запускает npm audit, а затем добавляет два источника сводок, недоступных npm audit, подавляя всё, что дублируется.

npm auditnpx sentinello
ОхватЕдинственный проект, в котором вы находитесь.Все проекты внутри папки — за один проход и в одном отчёте.
Источники сводокЛента сводок вашего реестра.Она же, плюс OSV и GitLab gemnasium. Дубликаты подавляются, поэтому каждый дополнительный источник добавляет только новые находки.
Вредоносные пакетыНе покрывается.Записи MAL- в OSV отмечают пакеты, опубликованные с вредоносным кодом — тайпсквоттинг, полезная нагрузка в install-скриптах — сверяя их с конкретными скомпрометированными версиями.
ВыводТаблица или JSON, который нужно интерпретировать.Markdown-сводка с приложенным промптом по устранению, готовая для передачи агенту.
СопоставлениеЗапрос к реестру на каждый проект.Офлайн, по локальному кэшу. Первый запуск скачивает его, предварительно спросив; последующие передают почти ничего.

Дополнительные источники — не формальность. В собственном репозитории Sentinello npm audit и OSV сообщают по три находки и совпадают во всех, тогда как единственная критическая находка приходит из gemnasium, которого нет ни в одном из двух других.

Возможности

Всё в одном самостоятельно размещаемом портале — никаких внешних сервисов, данные не покидают вашу сеть.

Единая очередь триажа

Просматривайте и сортируйте CVE всего портфеля в одном месте — вместо npm audit, разбросанного по десятку чекаутов.

Просмотр по проектам или библиотекам

Откройте любой репозиторий, чтобы увидеть его находки, версии с исправлением и историю, — или переключитесь на уязвимый пакет, чтобы увидеть каждый затронутый им проект и заглушить его сразу везде.

Находки, которые совпадают

Когда одну и ту же уязвимость сообщают несколько источников, находка остаётся одной — она несёт с собой, кто именно совпал, и оценивается по худшей серьёзности, которую дал любой из них.

Непрерывное сканирование

Фоновый процесс пересканирует по расписанию, поэтому новые рекомендации появляются без того, чтобы вы помнили о проверке.

Несколько источников

Не только npm audit: сопоставление с OSV и с gemnasium от GitLab для более широкого охвата CVE и обнаружения известных вредоносных пакетов.

Уведомления и вебхуки

Получайте оповещения о сбоях и находках через Slack, Telegram или обычный вебхук — с привязкой к конкретному корню или проекту, на выбранном вами языке. Полезная нагрузка в формате JSON или обычного текста для агента автоисправления.

MCP-сервер

Подключите Claude Desktop, Cursor и другие MCP-клиенты, чтобы запрашивать результаты, проекты и библиотеки — и запускать сканирование — не покидая чат.

Экспорт рекомендаций

Экспортируйте находки проекта или библиотеки в Markdown с настраиваемой подсказкой для устранения — для вашей команды или LLM.

Один образ, один файл

Один образ Docker и один файл SQLite. Никакого сервера баз данных, очереди сообщений или зависимости от облака.

Автоматически регистрируемые roots

Всё, что смонтировано в /roots, регистрируется и сканируется при запуске — имя каталога становится его меткой.

Node для каждого проекта

Учитывает .nvmrc каждого проекта, устанавливая и кэшируя зафиксированную версию Node один раз.

10 языков

Интерфейс портала, коды причин сканирования и статусы локализованы на 10 языков.

Скриншоты

Посмотрите в действии — портал сканирует несколько демонстрационных проектов. Нажмите на любой снимок, чтобы увеличить.

Сравнение

Sentinello — не более тяжёлый Dependency-Track и не более дешёвый Snyk. Он занимает другую нишу: длинный хвост проектов, которые никто не подключил к конвейеру.

SentinelloDependency-TrackSnykDependabot
Без настройки — укажите папку~~
Не нужен SBOM / шаг CI
Сканирует реальные разрешённые lockfile~
Обнаружение вредоносных пакетов
Self-hosted, без SaaS
Один образ + SQLite
AI-native (MCP + экспорт)~
Полиглот (Python, Go, …)
Корпоративные политики / VEX~~

Dependency-Track видит только проекты, которые кто-то оснастил конвейером SBOM. Sentinello находит забытые. Они сильнее в корпоративных политиках; если вы уже используете их в зрелом конвейере, оставьте их. Sentinello — для остальной части вашего портфеля, за которой никто не следит.

Зачем мы это создали

В эпоху ИИ вы выпускаете больше, чем способны поддерживать.

Сегодня один разработчик за год запускает, сдаёт и оставляет позади десяток проектов — маркетинговый сайт, клиентскую панель, пет-проект, который тихо ушёл в продакшн. Чтобы держать их в безопасности, раньше приходилось заходить по SSH в каждый чекаут и вручную запускать npm audit — или узнавать о CVE в Next.js из заголовков, спустя дни после публикации. Никто не делает этого по десятку репозиториев, так что этого не происходит вовсе.

Достаточно одной забытой зависимости с критической уязвимостью удалённого выполнения кода. Самый простой сайт, за которым вы перестали следить, становится точкой входа.

«Почему просто не взять Snyk или Dependabot?» Они живут внутри CI-конвейера, который вы настроили, — а длинному хвосту такой конвейер так и не достался. Sentinello — это система раннего предупреждения для всего остального: укажите ему папку, и он будет следить за каждым забытым проектом, выводя каждый новый CVE в одну очередь — прежде чем он превратится в инцидент.

Как это работает

Три шага. Никаких агентов для установки в ваши проекты, никаких аккаунтов.

Укажите ему свой код

Смонтируйте репозитории в /roots или добавьте их в «Настройки → Roots». Каждый каталог автоматически регистрируется и обнаруживается при запуске.

Непрерывное сканирование

Фоновый процесс по расписанию сверяет ваши зависимости с известными CVE, устанавливая нужную версию Node, которую фиксирует каждый проект, когда это требуется.

Триаж в одной очереди

Каждая находка из каждого проекта попадает в единую очередь, которую можно фильтровать по серьёзности, — с опциональными оповещениями в Slack, Telegram или вебхук.

Для кого это

Sentinello — для всех, у кого в продакшне больше, чем они способны охватить взглядом: для тех, кто разрабатывает в одиночку, для небольшой команды, для агентства, жонглирующего клиентскими проектами.

  • Вы выпускаете пет-проекты и клиентские сайты, которые должны оставаться безопасными ещё долго после запуска.
  • Вам нужен обзор всего портфеля без подключения CI к каждому репозиторию.
  • Вы предпочитаете размещать у себя, а не отдавать опись своего кода SaaS-сервису.

Если вы крупная организация, у которой Snyk или Dependabot уже встроены в зрелый конвейер, оставьте их — Sentinello не пытается заменить корпоративный SCA. Он здесь для остальной части вашего портфеля, за которой никто не следит. Он с открытым кодом и под лицензией MIT, так что вы можете в точности прочитать, что он делает.

Примечания к выпуску

Sentinello регулярно обновляется — вот что появилось в каждой версии.

Обновление Next.js ради шести уведомлений безопасности

v3.7.2 · 8 окт. 2026 г.
  • Портал и домашняя страница переходят с Next.js 16.3.6 на 16.4.0, где закрыты шесть уведомлений в самом Next: подделка серверных запросов (SSRF) в оптимизации изображений (высокая); две уязвимости отравления кэша в страницах SSG и ISR самостоятельно размещённых экземпляров — именно так работает Sentinello; утечка содержимого Draft Mode в обычные ответы через незавершённое заполнение <code>use cache</code>; маршруты изображений метаданных, игнорировавшие <code>dynamicParams</code>; и утечка информации через MCP-эндпоинт сервера разработки, который открывает только <code>pnpm dev</code>. Версии 16.4.0 был уже больше суток, но она ещё находилась в семидневном карантине, который Sentinello применяет к новым релизам, поэтому карантин был снижен только для этого обновления. У <code>braces</code> 3.0.3 по-прежнему нет исправленного релиза, и он используется только инструментами разработки.

Портал, который в простое ничего не потребляет

v3.7.1 · 7 окт. 2026 г.
  • Портал держал загрузку CPU на уровне 7–17 %, хотя ничего не происходило. Причина была в MCP-эндпоинте: клиент вроде Claude Code запрашивает у него поток через <code>GET /api/mcp</code>; эндпоинт, не хранящий сессий, открывал поток и закрывал его через несколько миллисекунд, а клиент тут же подключался снова. Выходило около четырёх запросов в секунду на каждую открытую сессию Claude Code с настроенным Sentinello, и каждый из них проверял токен и собирал целый MCP-сервер. Теперь <code>GET</code> и <code>DELETE</code> отвечают <code>405 Method Not Allowed</code> — так по спецификации MCP сервер без потока сообщает об этом, — и клиенты перестают его запрашивать. Замер на работающем экземпляре: повторных подключений больше нет, а портал в простое снова потребляет около 0,1 % CPU. Вызовы инструментов работают как прежде.
  • Отрисовка страницы проектов стоила около 1,3 секунды процессорного времени, а перерисовывается она каждую минуту, пока открыта вкладка, и каждые пять секунд во время сканирования. Почти всё уходило на одно чтение: чтобы найти последнее сканирование каждого источника для каждого проекта, перебирались все строки сканирований, и на экземпляре со 109 000 сканирований это означало каждый раз прочитывать 445 МБ сохранённых результатов. Новый индекс отвечает на этот вопрос напрямую — примерно с 1,1 секунды до 30 миллисекунд при тех же результатах, — и вся страница теперь обходится примерно в четверть секунды. Индекс создаётся один раз, при обновлении; на базе этого экземпляра объёмом 2,3 ГБ это заняло около трёх секунд.
  • Устранены четыре уязвимости в собственных зависимостях Sentinello: <code>proxy-addr</code> 2.0.8 (критическая, подмена IP-адреса через доверенную подсеть IPv6 с отображёнными IPv4-адресами) и <code>@modelcontextprotocol/sdk</code> 1.31.0 (высокая, его OAuth-клиент мог отправить учётные данные серверу авторизации, выбранному MCP-сервером) — обе за MCP-эндпоинтом; <code>sharp</code> 0.35.5 (критическая, во встроенной librsvg), который Next использует для изображений; и <code>source-map-js</code> 1.2.2 (высокая, отказ в обслуживании цикла событий) в инструментах сборки и тестирования. Все эти версии прошли семидневный карантин, который Sentinello применяет к новым выпускам. Остаётся одна уязвимость: для <code>braces</code> 3.0.3 нет исправленного выпуска, и он попадает в проект только через инструменты разработки. Один из двух путей к нему шёл через <code>nodemon</code>, который нигде не использовался, — он удалён; второй проходит через lint-плагин Next и исчезнет, когда тот откажется от <code>fast-glob</code> 3.
  • При сборке Sentinello из исходников в новой сборке мог оказаться старый портал. Кэш сборки не учитывал изменения в общих пакетах Sentinello, поэтому для выпуска, менявшего только их — например, запросы к базе данных, — <code>pnpm build</code> мог восстановить предыдущую сборку портала вместо новой. Теперь изменение любого общего пакета делает недействительными сборку и проверку типов каждого приложения, которое его использует. Образы Docker и CLI в npm собираются с нуля, и их это не затронуло.

Исправление указывается, только если оно действительно выпущено

v3.7.0 · 5 окт. 2026 г.
  • Sentinello советовал обновить <code>braces</code> до 3.0.4, а <code>node-forge</code> — до 1.4.1. Ни одна из этих версий так и не была опубликована, и ни одна рекомендация их не называла: когда рекомендация говорила «затронуты 3.0.3 и все более ранние версии» и не указывала исправления, Sentinello угадывал следующий патч-релиз. Кроме того, он принимал версию, которую npm audit предлагает для <em>родительского</em> пакета, за исправление дочернего — <code>minimatch</code> 12.0.1 для уязвимости, исправленной в 3.0.5. На экземпляре, где это обнаружилось, 35 несуществующих версий стояли в 296 находках, в том числе <code>qs</code> 6.15.4 в 113 находках, для которых всё это время существовало настоящее исправление — 6.16.0. Агенты, отправленные применять эти исправления, тратили целые запуски на поиск релизов, которых никогда не было.
  • Теперь каждое исправление для npm после каждого сканирования проверяется по реестру npm. Показывается самый ранний опубликованный релиз, который новее всех установленных копий и лежит вне затронутого диапазона каждого источника, сообщившего о рекомендации, — так что, если npm audit и OSV расходятся, исправление устраивает обоих. Каждая находка получает один из трёх ответов: версию, до которой можно обновиться; <strong>Исправленная версия не выпущена</strong>, если ни один опубликованный релиз не подходит; или «не проверено в реестре» — с исправлением, которое называет сама рекомендация, если оно есть, и причиной, по которой проверка не удалась (реестр недоступен, пакета нет в npm, диапазон не удалось прочитать). Недоступный реестр сам по себе никогда не превращается в «исправления нет»: Sentinello повторно использует ранее полученные метаданные пакета, если они ещё пригодны, оценивает по ним текущие уязвимости и помечает ответ датой их получения; без пригодных сохранённых метаданных исправление показывается как непроверенное. Сама находка по-прежнему всегда показывается с обычной серьёзностью: отсутствие исправления — не повод её скрывать.
  • Если исправленная версия не выпущена, находка теперь показывает выход из ситуации вместо версии, за которой придётся гоняться. Она сообщает, объявлен ли пакет устаревшим или заброшенным (ничего не публиковалось шесть месяцев и дольше), с его последним релизом, числом сопровождающих и еженедельными загрузками. Для каждого пути зависимостей она говорит, избавит ли от пакета обновление чего-то выше по цепочке, — и утверждает это, только проверив всё дерево зависимостей этого релиза, а не одни прямые зависимости, — или что путь закрыт: для <code>nodemon</code> › <code>chokidar</code> › <code>braces</code> chokidar 4 больше не тянет braces, но ни один выпущенный nodemon не принимает chokidar 4. Если на пути ничего не помогает, она предлагает признанные альтернативы из списка module-replacements проекта e18e, проверяя, что ни одна не возвращает уязвимый пакет (<code>tinyglobby</code> вместо <code>fast-glob</code>), или помечая альтернативу как «не проверено», если эту проверку не удалось завершить, и отмечает, когда до пакета доходят только инструменты разработки. Выход показывается в таблице находок, в экспорте рекомендаций, в <code>list_findings</code> MCP и в уведомлениях.
  • Находки, записанные до этого релиза, до следующего сканирования проекта показывают «исправление ещё не перепроверено — ожидается повторное сканирование» вместо прежней угаданной версии. В промпте по устранению по умолчанию появился новый раздел: он велит агенту не искать, не закреплять и не навязывать через override исправление уязвимого пакета, которое Sentinello не смог проверить, а следовать выходу из ситуации и самому проверять альтернативу с пометкой «не проверено», прежде чем её рекомендовать; если вы меняли промпт в настройках, ваш текст остаётся как есть, поэтому сравните его с новым вариантом по умолчанию. <code>list_findings</code> MCP получает <code>fixStatus</code>, <code>fixCheck</code> и <code>remediation</code>, а вебхук — <code>fixStatus</code> и <code>remediation</code>; его <code>recommendedVersion</code> теперь всегда только выпущенная версия. Сканер командной строки, <code>npx sentinello</code>, проверяет npm точно так же, как worker, тем же кодом: те же три ответа и тот же выход из ситуации — в сводке, в markdown и в JSON. Для этого он теперь тоже обращается к <code>registry.npmjs.org</code> и <code>api.npmjs.org</code>, отправляя только имена пакетов, и хранит ответы 24 часа рядом со своими базами рекомендаций; <code>--offline</code> не делает ни одного сетевого запроса, и тогда его исправления помечены «не проверено по реестру (офлайн)».
  • Для этого worker теперь обращается к <code>registry.npmjs.org</code> за метаданными пакетов и к <code>api.npmjs.org</code> за числом загрузок — для пакетов с находками и пакетов выше них по цепочке, а если исправление не выпущено, то и для релизов-кандидатов и альтернатив, которые рассматривает выход из ситуации, вместе с их деревьями зависимостей. Лимита на запросы нет: читается каждый пакет, который нужен выходу из ситуации, так что выход никогда не остаётся недосчитанным из-за исчерпанного бюджета. Запросы идут параллельно, а ответ старше 24 часов запрашивается снова с его ETag, так что неизменившийся пакет возвращается пустым <code>304</code>. Успешный ответ используется повторно 24 часа; неудачный запрос не сохраняется, поэтому может повториться раньше. Оба адреса перечислены на странице «О программе», в разделе «Что Sentinello отправляет вовне». <code>SENTINELLO_NPM_REGISTRY_URL</code> и <code>SENTINELLO_NPM_DOWNLOADS_URL</code> перенаправляют их на зеркало.
  • Проект, который Sentinello не может просканировать, теперь так и говорит — и объясняет почему. ddns, проект, у <code>package.json</code> которого пропал lockfile, вечно показывал свои прежние находки с пометкой «ожидается повторное сканирование»: ни одно сканирование не могло их разрешить. Теперь такой проект показывает <strong>Проект невозможно просканировать</strong> с причиной — «Нет lockfile» — и с тем, чья это забота: проекта или этой установки Sentinello, как в случае ещё не загруженной базы рекомендаций. Проект, который смогли прочитать лишь некоторые источники, показывает <strong>Проект невозможно просканировать полностью</strong>. Оба состояния видны на странице проекта, в списке проектов, на панели, в <code>list_projects</code>, <code>get_project</code> и <code>get_dashboard_summary</code> MCP, в сканере командной строки, в экспорте рекомендаций и в уведомлениях, где сбой, который должен исправить проект, озаглавлен <code>[CANNOT BE SCANNED]</code>, а вебхук передаёт <code>scanState</code>. Ни одно из них никогда не показывается как «всё в порядке»: ноль находок там означает «неизвестно», а не «безопасно». Находки, записанные прежним сканированием, остаются в списке со своей серьёзностью и пометкой «не перепроверено — проект невозможно просканировать: Нет lockfile» и датой последнего успешного сканирования, пока сканирование снова не пройдёт успешно.

Тридцать три уязвимости закрыты, пятнадцать фиксаций сняты

v3.6.0 · 1 окт. 2026 г.
  • Sentinello сканирует собственное дерево исходников так же, как любой другой проект, — и сообщал о 33 уязвимостях в самом себе: по оценке Sentinello — 3 критические, 17 высоких, 10 средних и 3 низкие, по оценке npm audit для тех же 33 — 1 критическая, 13 высоких, 16 средних и 3 низкие. Единственная, которую обе оценки считают критической, — удалённое выполнение кода в рендерере изображений <code>next/og</code> из Next.js, и оба приложения переходят на Next 16.3.6, где она исправлена. Sentinello использует <code>next/og</code> только для картинки-превью главной страницы в соцсетях, которая рисует лишь собственный переведённый слоган и описание; это сужает поверхность атаки, но обновление от этого не зависит.
  • <code>axios</code> переходит с 1.18.1 на 1.20.0 в воркере и в пакете уведомлений из-за двенадцати уязвимостей — две из них критические по оценке Sentinello и ни одной выше высокой по оценке npm audit. Sentinello обращается к axios только через HTTP-адаптер Node, чтобы доставлять уведомления в Slack, Telegram и вебхуки. Несколько из двенадцати находятся в адаптерах fetch и HTTP/2, которыми он не пользуется, но не все: перехват сокета через загрязнённый прототип и ReDoS при проверке исключений прокси лежат на том пути, который он использует. Поскольку тесты уведомлений подменяют axios заглушкой, новая версия дополнительно прогнана против локального приёмника ровно теми вызовами, которые делают модули уведомлений: доставка, вебхук, который по-прежнему отказывается следовать перенаправлению, обработка ошибок и тайм-аутов, маршрутизация через прокси и в обход него.
  • Три собственные фиксации версий Sentinello сами стали уязвимыми версиями. <code>brace-expansion</code>, <code>ip-address</code> и <code>fast-uri</code> были закреплены каждый на релизе, закрывшем более раннюю уязвимость, а сегодня ровно эти релизы покрывают десять уязвимостей; одна из уязвимостей <code>fast-uri</code> затрагивает только 3.1.6 — ту самую версию, которую называла фиксация. Поднять фиксации значило бы лишь запустить отсчёт заново, поэтому их сняли: родительский пакет каждого уже требует диапазон, разрешающийся в исправленный релиз, и lock-файл перевёл их внутри этих диапазонов на brace-expansion 5.0.12, ip-address 10.7.2 и fast-uri 3.1.8, ничего не навязывая. <code>brace-expansion</code> находится под линтером и никогда не поставляется; два других — под MCP SDK, за конечной точкой MCP портала.
  • Это стало поводом пересмотреть каждую фиксацию, и из семнадцати осталось две. Остальные либо выполнили свою задачу — после обновлений Next.js, MCP SDK и postcss собственный диапазон каждого родительского пакета разрешается в безопасную версию, — либо были временными ограничениями, помеченными к снятию при следующем пересмотре зависимостей. Обе оставшиеся защищают инструменты сборки, а не код, который выполняет Sentinello: исправленный <code>esbuild</code> под <code>drizzle-kit</code>, последний релиз которого всё ещё тянет устаревший загрузчик с уязвимой копией, и <code>esbuild</code> 0.28.1 под <code>tsup</code>, который собирает CLI. Заметка ко второй утверждала, что 0.28.1 входит в диапазон каждого потребителя; это не так — tsup требует 0.27, для которой исправленного релиза нет, — и теперь заметка говорит об этом прямо.
  • Последние десять — в <code>undici</code>, которым пользуется только эмуляция браузера в наборе тестов, и закрываются его переходом на 7.29.1; в поставляемую сборку они никогда не попадали. <code>pnpm audit</code> больше не сообщает об известных уязвимостях. Каждая взятая версия была опубликована не менее восьми дней назад, так что все без исключения прошли семидневный карантин, который Sentinello применяет к новым релизам, — а более свежие патчи, не исправляющие ничего из этого списка, остались в стороне.

Шестнадцать уязвимостей, о которых Sentinello сообщал в самом себе

v3.5.1 · 19 сент. 2026 г.
  • Sentinello сканирует собственное дерево исходников так же, как любой другой проект, — и сообщал о трёх критических уязвимостях в самом себе. Две из них — удалённое выполнение кода без аутентификации в Next.js: одна достижима на серверах под Windows, другая — через API оптимизации изображений при выдаче файла AVIF. В ветке 16.2 исправления нет ни для одной, поэтому оба приложения переходят на Next 16.3.4. Третья — в <code>sharp</code>, которым Next меняет размер изображений, и удерживала её собственная фиксация версии Sentinello: она была поставлена, чтобы закрыть более раннюю уязвимость sharp, когда ни один стабильный Next не разрешал исправленную копию, а Next 16.3 теперь запрашивает её сам. Снять фиксацию и оказалось исправлением.
  • Ещё две фиксации прошли тот же путь: написаны, чтобы закрыть уязвимость, оставлены на месте и незаметно превратились в то, что удерживало следующую. <code>fast-uri</code> был закреплён на версии, закрывшей подмену узла, и с тех пор появились ещё четыре уязвимости высокой степени, три из них — подделка запросов на стороне сервера. <code>hono</code> был закреплён на версии, закрывшей ReDoS в промежуточном слое CORS, и с тех пор набрал три средних, включая выход за пределы каталога в <code>toSSG()</code>, который сам был неполным исправлением более раннего. Обе фиксации теперь указывают на актуальную версию, и к каждой приложена заметка о том, что она закрывает и когда её следует снять.
  • Остальные уязвимости закрыты простым подъёмом версий: <code>js-yaml</code> до 4.3.2 — высокая, при которой подготовленный ключ слияния расходует процессор без ограничений, что важно для сканера, читающего чужой YAML; <code>qs</code> до 6.16.0 — два пути отказа в обслуживании в разборщике запросов за конечной точкой MCP; <code>vitest</code> до 4.1.11 — произвольное чтение файлов, которое доходило только до запускателя тестов. Шестнадцатая, в пакете с данными о совместимости браузеров, который тянет за собой Next, закрылась сама, как только дерево зависимостей сошлось на копии, уже закреплённой Sentinello. Теперь <code>pnpm audit</code> не сообщает об известных уязвимостях ни в одной из 741 зависимости, а каждая задействованная версия была опубликована достаточно давно, чтобы пройти семидневный карантин, который Sentinello применяет к новым релизам, — исключений не потребовалось.

Панель, где один источник говорил за весь проект

v3.5.0 · 20 авг. 2026 г.
  • Столбец <strong>Состояние</strong> на панели сообщал об одном источнике и отбрасывал остальные. Каждое сканирование пишет по строке на источник, и они завершаются с разницей в миллисекунды, поэтому в столбце оказывался тот, что закончил последним — на практике всегда OSV. Каждый проект показывал «База данных OSV ещё не загружена», хотя npm audit прекрасно их просканировал и нашёл настоящие уязвимости. Теперь Состояние несёт по значку на каждый источник, который не смог ответить, с указанием источника, и не показывает ничего, когда все включённые источники в порядке. В истории сканирований по той же причине появился столбец <strong>Источник</strong>: один проход писал три одинаковых на вид строки, которые нельзя было различить.
  • Настройки → Источники утверждали, что кэш актуален, пока он перестраивался. Состояние, которое читает портал, записывалось только по завершении синхронизации, поэтому на протяжении всей многоминутной перестройки оно продолжало показывать прежнее количество — тогда как каждое сканирование справедливо отвергало наполовину удалённый кэш. Оно также никогда не несло версию нормализатора, которую требует сканер, так что смена версии порождала то же ложное утверждение вообще без перестройки. Теперь строка читается как <strong>Перестроение…</strong> с приглушённым прежним количеством или <strong>Ожидает перестроения</strong>, когда кэш непригоден и им никто не занимается.
  • Догрузившийся кэш оставлял каждый проект с тем вердиктом, который тот получил, пока кэша не было. Ничто не пересканировало, поэтому <code>osv_db_not_seeded</code> держался до следующего планового прохода — или пока вы не замечали и не нажимали «Сканировать». Теперь Sentinello ставит в очередь один полный пересканинг, как только кэш снова становится пригодным. Инкрементное обновление не ставит в очередь ничего. Обновление тоже учитывается: если этот выпуск попадёт на инстанс, чьи проекты всё ещё несут вердикт, вынесенный до завершения кэша, воркер заметит расхождение при первом запуске и устранит его за вас — не нужно помнить про запуск сканирования.

Уведомление, помечавшее версию, которая его и исправила

v3.4.0 · 18 авг. 2026 г.
  • gemnasium записывает небольшое число уведомлений с пробелом между оператором сравнения и версией — <code>&lt; 0.5.2</code> вместо <code>&lt;0.5.2</code>, — и анализатор читал эту пару как два отдельных токена. Осиротевший <code>&lt;</code> получал пустую границу, а оставшаяся сама по себе версия попадала в кэш как точно закреплённая. Поэтому уведомление для <code>fresh</code> сообщало о версии 0.5.2 как об уязвимой, хотя именно 0.5.2 и является выпуском, который всё исправил, — и сообщало без доступного исправления, поскольку закреплённая версия не несёт никакой цели обновления. Так записаны 19 уведомлений, и все они разбирались неверно: 15 полностью теряли свой диапазон, а 7 закрепляли версию, которую сама запись называет исправлением; <code>pg</code> закреплял одиннадцать.
  • Sentinello перестал сам толковать синтаксис диапазонов npm и теперь сначала передаёт каждый диапазон собственной реализации npm, что разом закрывает целое семейство неверных прочтений. Для npm <code>&lt;=3.3</code> означает «до конца линейки 3.3» — при буквальном чтении всё останавливалось на 3.3.0 и упускало 3.3.1, а это реальное уведомление <code>converse.js</code>, — а <code>=103</code> означает всю линейку 103, а не одну точку, и <code>binaryen</code> записывает так восемь уведомлений. Теперь читаются и диапазоны с крышкой, тильдой, <code>1.x</code> и дефисом, тогда как прежде запись в любой из этих форм отбрасывалась без единого слова. Проверено на всех 4696 различных диапазонах версий, которые gemnasium публикует для npm: при собственном толковании расхождений с npm было 9, при делегировании — ни одного. Затронут только npm: в Python <code>==1.0</code> — это точная версия, а не подстановочный знак, так что применение там правила npm выдумало бы находки.
  • Три вещи, в которых прочтение npm верно для установки пакета и неверно для уведомления, применять не стали. Диапазон, не называющий ни одной версии — <code>*</code>, <code>x</code>, пустое поле, — при установке означает «любая версия», а в уведомлении неотличим от «это поле никто не заполнил», поэтому он отклоняется, а не превращается в находку против всех когда-либо выпущенных версий. Затесавшийся в конец <code>||</code> больше не может расширить предшествующий ему диапазон до всего. И <code>&gt;0</code> по-прежнему означает все версии, потому что <code>pandora-doomsday</code> именно так объявляет свой вредоносный пакет, а по прочтению npm вся ветка 0.x оказалась бы чистой. Отдельно: уведомлению, чьё заявленное исправление находится на начале собственного диапазона или ниже, эта граница больше не подставляется — так получался интервал, не совпадающий ни с чем, то есть находка, которая молча перестаёт сообщать, — а правило отбрасывания такого интервала теперь общее с источником OSV, а не написанное отдельно для каждого источника, что и было причиной их первоначального расхождения.
  • Тесты, которые всё это упускали, теперь порождают свои входные данные, а не перечисляют их. Каждый отдельный диапазон версий, который gemnasium публикует для npm, при каждой сборке сверяется с собственной реализацией npm, вместе с полным перебором грамматики диапазонов и всеми порядками событий диапазона в OSV. На предыдущем выпуске этот прогон падает на 28 диапазонах, тогда как десять рукописных примеров, которые он заменил, проходили все. Любое написание, которое вышестоящий источник придумает впредь, обрушит сборку при первом же импорте, а не тогда, когда кто-нибудь заметит порождённую им находку.
  • Каждая строка кода, стоящего за этими находками, теперь выполняется тестами — операторы, ветви, функции и строки на 100%, без единого исключения во всём репозитории. Это прямой ответ на то, как проскочили ошибки последних выпусков: каждая была ветвью, которую ничто не выполняло, — она сообщала об успехе, не делая ничего. При закрытии последних 109 обнаружилось, что несколько из них числились недостижимыми защитными проверками, а на деле просто не были покрыты тестами, и что одно из правил покрытия месяцами ничего не проверяло, поскольку названный в нём файл давно переехал. Это правило и 500 строк исключений вокруг него заменены одним, так что непокрытый код теперь роняет сборку, а не занижает среднее.
  • Закрыты и последние защитные пробелы: нечитаемая верхняя граница OSV оставляет допустимый интервал открытым, резервные границы проверяются после применения, а явная npm-граница предварительной версии вроде <code>&lt;1.2.3-0</code> сохраняет точный смысл.

Уведомления, объявлявшие уязвимой любую версию

v3.3.2 · 17 авг. 2026 г.
  • Уведомление, у диапазона которого нет верхней границы, совпадает со всеми версиями и делает это всегда: такую находку не снимет никакое обновление, а на странице её не отличить от действительно неисправленной уязвимости. Два уведомления по <code>xlsx</code> пришли именно в таком виде и сообщали о полностью исправленной 0.20.3 как о высокой серьёзности без доступного исправления — сразу в 11 проектах, тогда как <code>npm audit</code> корректно указывал те же два как исправленные в 0.19.3 и 0.20.2. Причина находится выше по цепочке и она намеренная: GitHub не называет исправленную версию, которую реестр не отдаёт под этим именем пакета, — SheetJS публикует 0.19.3 и новее только со своего CDN, — поэтому записывает диапазон как «всё начиная с 0», а настоящую границу помещает в отдельное поле, которое Sentinello не читал. Теперь читает. Затронуто было 15 npm-уведомлений, среди них <code>babel-traverse</code> и <code>sandbox</code>. Те 480, что действительно без исправления, по-прежнему так и сообщают, а запись, уже указавшая собственную границу, никогда не перезаписывается
  • Уведомление gemnasium, оставлявшее диапазон открытым и при этом перечислявшее исправляющие версии, теперь ограничивается самой старшей из них. Диапазон без конца утверждает, что уязвимы и все будущие выпуски, — а запись, называющая исправление, не может иметь это в виду
  • gemnasium записывает диапазоны версий Python как пересечения PEP 440 — <code>&gt;=5.0,&lt;5.8</code>, — а разборщик делил строку на токены только по пробелам, поэтому всё превращалось в один токен: нечитаемая нижняя граница и полное отсутствие верхней. Такие диапазоны не совпадают ни с чем, а не совпасть ни с чем — значит ни о чём не сообщить. В этом состоянии находились 2830 из 7159 закэшированных записей PyPI. Это была одна из трёх причин, по которым в 3.3.0 сняли Python, Go и Rust; две другие остаются открытыми, поэтому они остаются снятыми

Тот же выпуск, что и 3.3.0, но с собирающимся Docker-образом

v3.3.1 · 15 авг. 2026 г.
  • 3.3.0 опубликована в npm и на GitHub, но её контейнерный образ не собрался — на момент выпуска 3.3.0 не было ни в GHCR, ни в Docker Hub. Dockerfile перечисляет каждый пакет рабочего пространства, который устанавливает, и один из них — пакет сравнения версий — там никогда не значился. До этого выпуска ничто в образе его не импортировало, поэтому пропуск ни разу не проявился. С тех пор опубликован исправленный образ 3.3.0, собранный из кода приложения самой 3.3.0, так что <code>docker pull sentinello:3.3.0</code> снова работает. 3.3.1 несёт то же исправление в дереве исходников. Для CLI версия 3.3.0 уже была верной.

Только те экосистемы, которые действительно работают — и уведомления, которым можно верить

v3.3.0 · 15 авг. 2026 г.
  • Уведомление могло прийти пустым. Оператор получил сообщение в Telegram, объявлявшее об уязвимостях в проекте и не перечислявшее ни одной. Рассылка ограничена проектом, но выполнялась по одному разу на сканер: проход npm audit получил два ожидающих события OSV, не сопоставил ни одного и всё равно отрисовал заголовок над пустым списком. Затем он пометил оба события как доставленные — и две находки, которые он ни разу не назвал, оказались записаны как отправленные, а к доставленному событию больше никто не возвращается. Теперь событие рассылается, только если его можно описать; если нет, оно остаётся в ожидании и рассматривается снова при следующем сканировании
  • Находка сообщается с худшей оценкой, которую ей дал хоть один источник, и это повышение доходило до панели, итогов по проекту и шлюза <code>--fail-on</code> в CLI — но не до порогов уведомлений. Уведомление выполнялось до подтверждения, поэтому событие получало оценку уцелевшего источника и больше не переписывалось. На реальной инстанции 135 открытых находок несли серьёзность события ниже настоящей, <strong>41 из них записывала critical как low, high или moderate</strong>. Цель, отфильтрованная по critical и high, не была бы вызвана ни по одной из них — навсегда
  • Запланированные сканирования останавливались в полночь, вместо того чтобы продолжаться. «Каждые 3 часа с 07:00» запускалось в 07, 10, 13, 16, 19 и 22, а затем только в 07:00 — шесть сканирований в сутки вместо восьми, с девятичасовым слепым окном каждую ночь — при этом Настройки продолжали показывать выбранный интервал. «Каждые 6 часов с 20:00» давало одно сканирование в сутки. Теперь слоты переходят через смену суток
  • <strong>Python, Go и Rust отозваны.</strong> Это не осторожность из-за шероховатостей: их сбои сообщались как «чисто». Вывод исправленной версии и упорядочивание версий работают только по semver, поэтому рекомендация OSV по Django советовала «обновиться до 3.2.23» для установленной 4.2; имена пакетов PyPI в OSV не канонизированы по PEP 503 и потому никогда не совпадали с именами резолвера; а парсер диапазонов gemnasium не умеет читать пересечения через запятую из PEP 440. Источник, который по неверным причинам отвечает «уязвимостей нет», хуже того, который не предлагается вовсе, — поэтому они полностью убраны с поверхности продукта: ни переключателя, ни обнаружения, ни загрузки. <strong>Находки, уже собранные с ними, остаются видимыми, их можно заглушить; ничего не удаляется.</strong> Экосистема npm теперь называется <strong>Node.js</strong> — это имя реально сканируемой экосистемы пакетов, а не языка
  • <strong>Настройки → Источники</strong> перестроены вокруг этого. Раньше каждый источник повторял собственное объяснение рядом с собственным переключателем, а каждый источник с кэшем нёс пятистрочную панель состояния с собственной полноразмерной кнопкой «Обновить сейчас» — хотя эта кнопка ставит в очередь один общий сигнал на источник, сколько бы раз она ни появлялась. Теперь переключатели говорят только о том, включён ли источник; что каждый из них добавляет, что и откуда загружает и когда работает, переехало в одну справочную таблицу под ними, а состояние синхронизации уместилось в одну строку
  • Пакеты, которые собственный lock-файл npm объявляет достижимыми из продакшена, понижались до «только разработка». Отсутствие <code>dev: true</code> в lock-файле — это утверждение npm, что пакет ДОСТИЖИМ из продакшена, и оно сильнее того, что может сказать корневой манифест. Но резолвер перекрывал его всякий раз, когда имя встречалось и в <code>devDependencies</code>, то есть ровно тогда, когда npm был прав. Измерено на 130 реальных проектах: 142 пакета понижены в 97 из них — lodash, semver, postcss, tailwindcss, @babel/runtime — из-за чего на одной инстанции семь открытых находок скрылись из фильтра «только продакшен»
  • Любой пакет, закреплённый на версии вида <code>0.0.0-20180523222229-09b5706aa936</code>, не совпадал <strong>ни с одной рекомендацией</strong> — даже с открытой — и сканирование сообщало ok при нулевом числе находок. Нижняя граница <code>introduced: 0</code> сравнивалась как релиз 0.0.0, а в semver предрелиз сортируется ниже своего релиза. 330 из 19 085 сравнимых диапазонов реального кэша хранились как интервалы, которые ничем нельзя удовлетворить
  • Прерванная синхронизация OSV могла удалить рекомендацию навсегда. Инкрементальный путь удалял строки рекомендации, а замену получал уже внутри try/catch, поэтому любой таймаут, 5xx или остановка стирали её целиком — а курсор всё равно продвигался, оставляя идентификатор позади навсегда. Потеря была молчаливой, доживала до следующего полного пересева и происходила в синхронизации, которая отчитывалась об успехе. Кэш <code>npx sentinello</code> точно так же истончался при каждом нестабильном запуске. Теперь оба сначала получают и только потом заменяют
  • <code>--dep-type dev</code> в CLI означал «достижим из dev хоть как-нибудь», тогда как портал имеет в виду «достижим <em>только</em> из dev», поэтому пакет, достижимый из обоих, появлялся в одном представлении и отсутствовал в другом — на одной инстанции два прочтения расходятся на 177 открытых находок. Теперь CLI использует правило портала и учитывает поле <code>withdrawn</code> из OSV, прочитать которое раньше был структурно неспособен: 585 строк реального npm-кэша несут его, и все они сообщались как действующие находки
  • Рекомендация gemnasium, которая сообщает, что уязвимость начинается <em>после</em> версии — <code>&gt;1.2.8</code>, а не <code>&gt;=1.2.8</code>, — читалась так, будто затронута и сама граничная версия. Захват пакета <code>rc</code> в 2021 году описан именно так, а 1.2.8 — его последний чистый выпуск: ровно та версия, на которой рекомендация своим же указанием по устранению советует остаться. В результате каждому проекту с установленным <code>rc</code> показывалась критическая находка о вредоносном коде без доступного исправления — против версии, которая никогда не была скомпрометирована. Теперь границы сохраняются ровно так, как их формулирует рекомендация, и ложные критические находки такого рода исчезают
  • То же округление работало и в обратную сторону, скрывая настоящие находки. Рекомендация с границей <code>&lt;=2.0.0</code> сохранялась как «ниже 2.0.0», поэтому сама 2.0.0 — версия, о которой сказано яснее всего, — не сообщалась, а рекомендация, называющая ровно одну затронутую версию, превращалась в пустой интервал и отбрасывалась целиком. Ожидайте небольшое число новых находок, которые всегда были, но оставались невидимыми
  • Диапазоны, записанные синтаксисом, который Sentinello не реализует, — <code>^1.0.0</code>, <code>~1.0.0</code> — сохранялись как точная версия, привязанная к буквальному тексту, и потому не могли совпасть ни с чем, пока оставались в кэше: рекомендация выглядела действующей, но сработать не могла. Такие записи теперь отклоняются, а не хранятся в неработоспособном виде; рекомендациям, у которых верхняя граница не несёт чистой исправленной версии, наконец выдаётся предложение по обновлению
  • Помощник, который маскирует URL вебхука или токен бота, прежде чем тот попадёт в строку журнала, печатал короткие значения целиком. Он отклонял значения из шести символов и меньше, но затем оставлял восьмисимвольную голову и четырёхсимвольный хвост, и никто не проверял, не смыкаются ли эти две половины — так что любой секрет длиной от 7 до 12 символов возвращался полностью. Теперь он скрывает не менее восьми символов либо затирает значение целиком

Находки показывают, какие источники согласны, а отозванные рекомендации больше не сообщаются

v3.2.0 · 15 авг. 2026 г.
  • Когда одну и ту же уязвимость сообщают несколько баз рекомендаций, Sentinello всегда оставлял ОДНУ находку: сообщать об одном изъяне трижды лишь потому, что о нём знают три базы, — это шум. Но всё, что касалось объединённых источников, до сих пор отбрасывалось, и уязвимость, независимо подтверждённая npm audit, OSV и GitLab gemnasium, выглядела ровно так же, как та, о которой слышала лишь одна база. На реальном экземпляре это две трети всех находок. Теперь каждая находка несёт с собой остальные источники, сообщившие о ней, и их метки отображаются рядом с сохранившейся
  • Находка сообщается с САМОЙ ВЫСОКОЙ серьёзностью, которую ей присвоил любой источник. Базы действительно расходятся в оценках: gemnasium вычисляет серьёзность по вектору CVSS, а npm audit берёт категорию GitHub — и для сканера действовать стоит по осторожному прочтению. Это не косметика: повышенная находка меняет категорию на панели, в итогах проекта, в барьере <code>--fail-on</code> у CLI и в порогах уведомлений. При первом сканировании после обновления некоторые счётчики сдвинутся; ничего нового не обнаружено — те же находки оцениваются осторожнее
  • Там, где источники расходятся, рядом с серьёзностью находки появляется элемент управления, открывающий то, что сказал каждый источник: его собственный идентификатор рекомендации и его оценку. Он появляется только при наличии расхождения, поэтому находка, оценённая всеми одинаково, остаётся лаконичной
  • OSV фиксирует отзыв в отдельном поле, а GitHub удаляет отозванные рекомендации ещё до того, как их увидит <code>npm audit</code>, но у GitLab gemnasium такого поля в схеме нет. Он отзывает рекомендацию, переписывая запись на месте: заголовок становится «False Positive», «Withdrawn Advisory: …» или «Duplicate Advisory: …», а версии, которые она называла прежде, остаются на месте. Sentinello читал эти версии и сообщал о находках, которые GitLab явно отозвал: 383 записи по JavaScript, Python, Go и Rust, включая одну, сообщавшую об <code>express</code> под заголовком «False Positive». Теперь все они отбрасываются, что заодно устраняет целый класс дублирующихся находок — 278 из 383 отозваны именно как дубликаты другой рекомендации
  • Проверка сопоставляет маркеры отзыва точно, а не ищет слова где угодно в тексте, поэтому настоящая рекомендация, посвящённая ложному срабатыванию, по-прежнему сообщается: CVE-2026-39395 для Cosign с заголовком «Cosign’s verify-blob-attestation reports false positive when payload parsing fails» не затронут
  • Кэш gemnasium перестраивается сам при первой синхронизации после этого обновления, и тогда отозванные рекомендации исчезают. Ничего делать не нужно: это произойдёт при ежедневной синхронизации или сразу через «Настройки → Источники → Обновить»

Диапазоны версий в рекомендациях верны в обе стороны

v3.1.1 · 14 авг. 2026 г.
  • Некоторые рекомендации GitLab gemnasium вообще не содержат машиночитаемого диапазона версий — 698 из 10 777 для JavaScript. Sentinello закрывал этот пробел предположением, что затронуты все версии ниже первого перечисленного исправления, но этот список не упорядочен и содержит по одному исправлению на ветку выпуска, поэтому догадка регулярно попадала не в ту ветку. protobufjs 7.6.5 сообщался как критическое удалённое выполнение кода, хотя эта ветка была исправлена в 7.5.5, а три отдельные рекомендации утверждали, что уязвимы все версии vite ниже 8.0.5. Sentinello больше не выдумывает диапазоны: он восстанавливает настоящий из той же рекомендации, опубликованной под другим идентификатором, из её собственного описания или — только если у вас включён OSV — из копии OSV, уже имеющейся на вашей машине, а если ничто из этого не отвечает, отбрасывает запись, а не строит догадки. Часть критических находок исчезнет
  • OSV описывает рекомендацию, исправленную в нескольких ветках выпуска, отдельной записью на каждую ветку, а Sentinello оставлял первую и отбрасывал остальные — 1 927 уязвимых диапазонов версий только для JavaScript, и каждый из них — реальная уязвимость, ставшая невидимой. Рекомендация minimatch охватывает восемь веток, а выживала лишь одна, поэтому установленный minimatch 3.0.4 или 9.0.0 не сообщался; next и ua-parser-js теряли ветки так же. Теперь сохраняются все ветки. Появятся новые находки — эти уязвимости существовали всегда, просто были невидимы
  • Оба кэша рекомендаций перестраиваются сами при первой синхронизации после этого обновления, потому что хранящиеся в них диапазоны созданы прежним кодом. Ничего делать не нужно: это произойдёт при ежедневной синхронизации или сразу через «Настройки → Источники → Обновить», если не хотите ждать

Заглушённые находки уходят с глаз долой, а база данных перестаёт расти без конца

v3.1.0 · 13 авг. 2026 г.
  • Заглушённая находка — это решение, которое вы уже приняли, поэтому теперь она полностью уходит со страницы проекта, а не остаётся на ней блёклой строкой. Дело не только в аккуратности: каждое число на странице — счётчик в заголовке, значки обеих вкладок, постраничная навигация, итоги по библиотекам, кнопка экспорта — считается по одним и тем же строкам, так что страница наконец согласуется с панелью, инструментами MCP и экспортом рекомендаций, которые и раньше исключали заглушённые находки. Переключатель «Показать заглушённые» возвращает их в любой момент, в том числе в проекте, где заглушены *все* находки
  • Ввод в диалоговом окне больше не теряет фокус после первого же символа. Из-за этой ошибки поле «Причина» в диалоге заглушения было практически невозможно заполнить — хотя оно обязательное и остаётся единственным, что позволяет разобраться в заглушении спустя месяцы. Тот же диалог перестал наследовать выравнивание строки таблицы, из которой он открыт: именно поэтому при заглушении находки диалог получался выровненным по правому краю, а при заглушении проекта — нет
  • История сканирований больше не растёт бесконечно. Ничто и никогда не удаляло записи сканирований по возрасту, поэтому проект, остававшийся на диске, бесконечно накапливал по строке на источник за каждый проход — реальный экземпляр дошёл до 2,2 ГБ меньше чем за три месяца. В «Настройках → Дополнительно» появился срок хранения, по умолчанию 90 дней, и воркер ежечасно удаляет всё, что старше, всегда сохраняя 100 последних сканирований каждого проекта. Находки, заглушения и история уведомлений не затрагиваются — только журнал сканирований. При 90 днях обновившийся экземпляр ничего не удалит на первом же проходе: очистка начнётся, только когда история действительно окажется старше этого срока или когда вы сами уменьшите его
  • Основная часть этого роста — необработанный вывод `npm audit`, который целиком сохранялся при каждом успешном сканировании и не читался ничем: 98,7 % базы данных того экземпляра. Теперь сканирования записывают краткую сводку, и строка уменьшается примерно с 79 КБ до сотни байт, а жёсткое ограничение не позволит ни одному сканеру повторить это
  • В MCP инструмент `get_dashboard_summary` теперь прямо сообщает, что заглушённый вами проект выпадает из его итогов, тогда как `list_projects` по-прежнему его возвращает. Они намеренно считают разные совокупности, и агент, сравнивавший их, принимал это за ошибку. `list_scans` также перестал возвращать необработанный вывод сканера по каждому сканированию, который в одном ответе мог достигать примерно 16 МБ

Загрузка gemnasium снова работает, а CLI возвращает терминал

v3.0.1 · 4 авг. 2026 г.
  • В 3.0.0 загрузка GitLab gemnasium падала с `HTTP 406` у всех. Встроенный fetch в Node добавляет заголовок `Sec-Fetch-Mode: cors`, который программа не вправе убрать, а GitLab отклоняет любой запрос архива репозитория с этим заголовком — так что дело никогда не было ни в вашей сети, ни в IP, ни в числе повторов. Теперь загрузка выполняется обычным HTTPS-запросом и проходит успешно
  • Архив запрашивается по идентификатору коммита, а не по имени ветки: все, кто обновляется с одного и того же коммита, используют общую кэшированную копию вместо того, чтобы каждый просил GitLab собрать архив на 60 МБ. Первая загрузка, занимавшая почти семь минут, теперь завершается за секунды
  • CLI заканчивал всю работу — записывал отчёт, печатал сводку — и после этого не возвращал терминал. Соединение загрузки оставалось открытым и удерживало процесс; теперь оно закрывается сразу после чтения архива
  • Источник, отказавший в загрузке, больше не молчит три минуты перед сообщением. Он сообщает за секунды и в терминале предлагает повторить — повторяя только тот источник, который действительно не удался
  • `--fail-on` честен в обе стороны. Он отклоняет запуск, в котором источник рекомендаций не удалось опросить, вместо того чтобы отчитаться о чистом сканировании, которого не было; и больше не заваливает запуск из-за источника, который вы сами отключили через `SENTINELLO_OSV_FEED_URL=off` или `SENTINELLO_GEMNASIUM_FEED_URL=off` и ни разу не загружали

Sentinello теперь работает вообще без портала

v3.0.0 · 3 авг. 2026 г.
  • Сканеры выходят как CLI в npm. `npx sentinello` обходит папку, находит все проекты внутри, сверяет их с npm audit, OSV и GitLab gemnasium и пишет markdown-сводку с приложенным промптом по устранению — без установки, без аккаунта, без базы данных, и ничего из вашего кода не покидает машину
  • В конвейере на stdout попадает только сводка, поэтому `npx sentinello | claude -p "$(cat -)"` передаёт агенту полный список работ, ничем не повредив документ
  • Первый запуск больше не теряет источник gemnasium из-за отклонённой загрузки. GitLab отклоняет свой архив на минуту-две подряд, а прежние повторы сдавались через тринадцать секунд; теперь CLI дожидается окончания, объясняет, почему ждёт, и принимает `--feed-wait`, если три минуты по умолчанию вам не подходят
  • Обе оценки размера загрузки измерены, а не угаданы: npm-экспорт OSV указан как 204 МБ вместо 196, а архив gemnasium — как 52 МБ вместо 80. В запросе подтверждения оценка помечается тильдой, чтобы её нельзя было принять за размер, сообщённый сервером
  • Значение, похожее на флаг, теперь отклоняется, а не понимается буквально: `--out --` раньше писал сводку в файл с именем `--` внутри вашего проекта и рапортовал об успехе
  • Панель «Что нового» больше не уходит за нижний край окна, когда в релизе много изменений

Документ с рекомендациями действительно доходит — и считает верно

v2.6.0 · 29 июл. 2026 г.
  • get_project_advisory теперь возвращает сам документ. Раньше подключённые клиенты получали только метаданные — имя файла и количество — но не документ, хотя инструмент описывал его как полный рабочий список
  • Экспорт рекомендаций теперь содержит одну запись на каждую отдельную рекомендацию с объединёнными источниками, а не одну на строку сканера: уязвимость, о которой сообщают и npm audit, и OSV, становится единой рабочей задачей с обоими идентификаторами, а не двумя почти одинаковыми. Это касается и кнопки «Скачать .md» в портале, а количество теперь совпадает с панелью
  • Проект, который не помещается в один ответ MCP, теперь разбивается на страницы: документ сообщает, что он неполный, и указывает точный следующий вызов для получения остального, вместо того чтобы молча обрываться там, где агент счёл бы остаток чистым
  • У каждого параметра каждого инструмента MCP появилось описание, а новый инструмент list_mutes выдаёт идентификаторы отключений, нужные для unmute — раньше их можно было узнать, только создав отключение в той же сессии
  • Исправлен пробел в подсчёте уровней риска: находка с уровнем вне пяти известных значений учитывалась как находка, но не попадала ни в одну категорию, поэтому проект с единственной такой находкой выглядел полностью чистым

Экспорт рекомендаций прямо через MCP

v2.5.0 · 28 июл. 2026 г.
  • Подключённые MCP-клиенты могут получить полный Markdown-отчёт проекта новым инструментом get_project_advisory — тот же документ, что и кнопка «Скачать .md» в портале, без копирования из браузера
  • Заглушённые находки больше не попадают в экспорт рекомендаций проекта, поэтому агент никогда не получит работу, риск которой вы уже приняли
  • Примечание: поскольку отчёт содержит ваш промпт экспорта, MCP-клиент теперь может прочитать то, что вы написали в Настройки → Экспорт

Всплывающие панели без обрезки и более строгий промпт экспорта

v2.4.3 · 26 июл. 2026 г.
  • Выпадающие списки, всплывающая панель пути зависимости и меню экспорта рекомендаций больше не обрезаются таблицей или диалогом, в котором они находятся, — они отрисовываются поверх страницы и раскрываются вверх, когда снизу не хватает места
  • Стандартный промпт экспорта рекомендаций теперь требует от агента сначала составить план и только потом что-то править, группировать находки, закрывающиеся одним исправлением, и описывать влияние каждого изменения версии на код; цель — ноль находок, но обходные пути к фальшивому нулю запрещены: заглушение, расширение диапазонов или сужение области сканирования, а действительно нерешаемое попадает в датированную таблицу остатков

Ветка в отдельной колонке

v2.4.2 · 25 июл. 2026 г.
  • Ветка git, на которой сканировался проект, теперь занимает отдельную колонку в списке проектов — обычный текст, без иконки — вместо строки под названием проекта

Корректное завершение работы

v2.4.1 · 25 июл. 2026 г.
  • Перезапуск контейнера больше не обрывает сканирование на середине записи, а воркер запускается сразу, а не после ~30 секунд повторных попыток
  • Задайте stop_grace_period: 60s (или --stop-timeout 60) в compose-файле, чтобы дать ему запас, — README и документация по Docker теперь это описывают

Полиглотное сканирование — к npm добавились Python, Go и Rust

v2.4.0 · 25 июл. 2026 г.
  • Sentinello теперь сканирует проекты на Python, Go и Rust наряду с npm — файлы блокировок разбираются полностью офлайн, а каждый проект сообщает своё покрытие сканирования (полное, частичное или непроверяемое), поэтому пробелы видны, а не остаются незамеченными
  • База gemnasium от GitLab присоединяется к npm audit и OSV как офлайн-источник рекомендаций с дедупликацией по псевдонимам CVE/GHSA; раздел Настройки → Источники стал матрицей «Языки × Источники» с областью уведомлений для каждой ячейки, а сам npm audit теперь можно отключить, пока активен хотя бы один источник
  • Находки теперь фиксируют ветку git, из которой они получены, — она видна в списке проектов, в заголовке проекта и в каждом уведомлении
  • В строках проектов появились собственные действия — сканировать сейчас, скопировать или скачать рекомендацию, заглушить или снять заглушение и изменить теги, — поэтому для разбора больше не нужно заходить в каждый проект
  • Панель проектов ускорилась с ~3,3 с до ~0,03 с, а при переходах теперь показываются состояния загрузки вместо подвисшей страницы
  • Безопасность: устранено 25 рекомендаций по зависимостям, включая CVE в libvips, которые реально действовали в оптимизаторе изображений портала, и девять рекомендаций Next.js, затрагивавших поставляемый портал
  • Стандартный промпт экспорта рекомендаций теперь учитывает минимальный возраст релиза, проверку файла блокировки и устаревшие override

Более простая настройка MCP — без переменных окружения

v2.3.0 · 9 июн. 2026 г.
  • Теперь MCP настраивается полностью в «Настройки → MCP»: сгенерируйте токен, чтобы включить эндпойнт /api/mcp, очистите его, чтобы выключить — переменные окружения SENTINELLO_MCP_ENABLED и SENTINELLO_MCP_API_TOKEN удалены (существующий токен из окружения импортируется один раз при обновлении)
  • Готовые к вставке фрагменты подключения для Claude Code, Codex, Cursor и Claude Desktop, уже заполненные вашим токеном
  • Когда SENTINELLO_PORTAL_BASE_URL задана в окружении, она отображается только для чтения в «Настройки → Дополнительно», поскольку остаётся приоритетной и повторно применяется при каждом запуске

Меньше ложных срабатываний и самоочищающиеся находки

v2.2.0 · 9 июн. 2026 г.
  • Оповещения о вредоносном ПО теперь сопоставляются с точной затронутой версией — чистая или уже исправленная версия некогда скомпрометированного пакета больше не помечается
  • Дублирующиеся находки теперь устраняются сами при следующем сканировании, поэтому старые или осиротевшие записи удаляются автоматически
  • Метки production и development теперь вычисляются единым согласованным способом по всем источникам (npm и OSV)

Более чистый заголовок проекта и единообразные фильтры

v2.1.0 · 6 июн. 2026 г.
  • Упрощённый заголовок проекта — переименование рядом с названием, отключение и теги в виде иконок
  • Фильтрация находок по источнику (npm / OSV) через новый выпадающий список рядом с фильтром типа зависимости
  • Единообразные выпадающие списки по всему приложению, с поиском по вводу для длинных списков, например часовых поясов

Более понятные инструкции по обновлению

v2.0.1 · 4 июн. 2026 г.
  • Расширенные шаги обновления для несовместимых изменений 2.0
  • В README указана привязка порта только к localhost

Сканирование из нескольких источников и усиленная, безопасная по умолчанию установка

v2.0.0 · 4 июн. 2026 г.
  • OSV как необязательный второй источник (Настройки → Источники, по умолчанию выключено) с обнаружением вредоносных пакетов, сверяемый с публичной базой данных OSV в локальном кэше
  • Результаты теперь объединяются между источниками — одна строка на уязвимость, каждый источник помечен, лучшее доступное исправление и объединение путей зависимостей, с фильтром по источнику и всплывающим окном пути зависимости
  • Усиление безопасности: эндпойнт MCP по умолчанию выключен и требует токен, доставка вебхуков защищена от SSRF, необязательный вход в портал, и контейнер запускается от непривилегированного пользователя
  • Настройки теперь — раздел верхнего уровня с боковой панелью и страницей профиля

Интеграция MCP и новинки

v1.4.0 · 29 мая 2026 г.
  • MCP-сервер по адресу /api/mcp для Claude Desktop, Cursor и других клиентов
  • Новый раздел «Настройки → MCP» с URL сервера и управлением токенами
  • Значок новинок и история примечаний к выпускам

Исправление версии в подвале

v1.3.1 · 28 мая 2026 г.
  • Текущая версия корректно отображается в подвале

Улучшения уведомлений

v1.3.0 · 28 мая 2026 г.
  • Фильтрация уведомлений по среде
  • Более простая форма редактирования получателей
  • Дублирование существующего получателя уведомлений

Страницы проектов и библиотек

v1.2.0 · 24 мая 2026 г.
  • Главный экран разделён на отдельные страницы проектов и библиотек

Живая перезагрузка расписания

v1.1.2 · 24 мая 2026 г.
  • Воркер перезагружает расписание сканирования сразу после сохранения изменений в портале

Более безопасное удаление и понятный баннер обновления

v1.1.0 · 23 мая 2026 г.
  • Подтверждение перед удалением корней и получателей уведомлений
  • Уведомление об обновлении перенесено в закрываемый баннер сверху
  • Воркер удаляет устаревшие корни, когда их монтирование исчезает

Исправления точности сканера

v1.0.1 · 23 мая 2026 г.
  • Отбрасывает результаты, чья установленная версия фактически не входит в уязвимый диапазон
  • Позволяет удалить получателя уведомлений с историей отправок

Первый релиз с открытым исходным кодом

v1.0.0 · 23 мая 2026 г.
  • Первый публичный выпуск Sentinello

Дорожная карта

Сегодня Sentinello следит за вашими зависимостями на нескольких языках. Вот куда он движется — и что вы можете запросить.

Умнее приоритизация

Запланировано

Ранжируйте находки по эксплуатируемости и по тому, достижим ли уязвимый код, — сначала разбирайте главное.

Больше интеграций

Запланировано

Больше каналов уведомлений и способов подключить Sentinello к инструментам, которыми ваша команда уже пользуется.

Статический анализ (SAST)

Запланировано

Выявляйте рискованные паттерны в вашем собственном коде, а не только известные CVE в зависимостях.

Сканирование секретов и лицензий

Запланировано

Отмечайте закоммиченные секреты и проблемы с лицензиями в том же портфеле, в той же очереди.

Запросить интеграцию или источник

Расскажите, что бы вы интегрировали или просканировали дальше — откройте issue на GitHub и помогите сформировать дорожную карту.