Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
npm-incident-response — Сканер для атаки на цепочку поставок keyv/cacheable: обнаруживает скомпрометированные npm-пакеты, проверяет хэши полезной нагрузки и находит импланты персистентности в режимах repo и host. | Kitploit
Инструменты/GitHubGitHub/securest8/npm-incident-response
Сканеры уязвимостейМеханизмы персистентностиАнализ вредоносных программЦифровая криминалистикаБезопасность Цепочки ПоставокРеагирование на Инциденты
GitHubsecurest8/npm-incident-response

npm-incident-response

Сканер для атаки на цепочку поставок keyv/cacheable: обнаруживает скомпрометированные npm-пакеты, проверяет хэши полезной нагрузки и находит импланты персистентности в режимах repo и host.

Репозиторий
2151 месяц назадЕщё не проверено

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться

npm-incident-response

Английский | Português

Автономный сканер для инцидента в цепочке поставок keyv/cacheable («Shai-Hulud: Here We Go Again», 4 авг 2026) — 440+ npm-пакетов скомпрометировано самораспространяющимся червём, который крадёт облачные и CI-учётные данные и устанавливает персистентность с механизмом «мертвеца» (dead-man's switch).

Обнаруживает за минуты, без установки чего-либо:

  • Скомпрометированные пакеты в package-lock.json, npm-shrinkwrap.json, yarn.lock (v1 и Berry), pnpm-lock.yaml и bun.lock — включая транзитивные зависимости, с полной цепочкой (например, eslint → file-entry-cache → flat-cache → [email protected]);
  • Установленные полезные нагрузки в node_modules (имя + SHA-256-хэш известных артефактов);
  • Варианты, которых ещё нет в списках IOC (эвристика: подозрительные скрипты жизненного цикла, файлы с именами червя) — всегда помечаются как SUSPECT, никогда не подтверждаются без хэша;
  • Импланты персистентности на хосте: LaunchAgent (macOS), пользовательский сервис systemd + linger (Linux), хуки в .claude/settings.json и .vscode/tasks.json, временные артефакты (bun-dl-*);
  • Механизм «мертвеца»: имплант отслеживает GitHub-токен и выполняет удалённую команду, когда отзыв возвращает 4xx. Ротация учётных данных до очистки хоста активирует ловушку — отчёт предупреждает об этом, а порядок реагирования ниже позволяет избежать ошибки.
  • Как устроена атака

    1. Учётная запись мейнтейнера семейств keyv/cacheable была скомпрометирована; атакующий опубликовал новые версии с хуком "preinstall": "node setup.mjs" — кодом, который выполняется до установки пакета, с правами того, кто запустил npm install.
    2. setup.mjs скачивает среду выполнения Bun из GitHub и запускает в ней полезную нагрузку — обход защиты, которая отслеживает только процессы node.
    3. Math_Symbol.js (~728 КБ, обфусцированный) крадёт учётные данные: метаданные инстансов AWS, ключи AWS/GCP/Azure, токены Vault, сервисные аккаунты Kubernetes, секреты GitHub Actions, npm-токены, плюс общий regex-поиск приватных ключей и bearer-токенов на диске.
    4. Это червь: с украденным npm-токеном он внедряет тот же хук в другие пакеты, которые может публиковать эта учётная запись, пересчитывает хэши целостности и перепубликовывает. Так количество пакетов выросло с ~10 до сотен.
    5. Он выводит данные без фиксированного C2 (репозитории GitHub, создаваемые на лету, DNS) и оставляет ловушку — см. ниже.

    Два вектора (второй тоньше)

    • Вектор A — установка: любой, кто запускал npm install/npm ci с включёнными скриптами жизненного цикла с 2026-08-04 09:35 UTC. С --ignore-scripts хук не выполнялся.
    • Вектор B — клонирование: в исходном репозитории появились хуки автозапуска в .claude/settings.json (SessionStart) и .vscode/tasks.json (folderOpen), которые запускают загрузчик при открытии клонированной папки — без npm install, ничего не устанавливается. Сюда входят те, кто клонировал репозиторий для расследования инцидента, и AI-агенты, открывшие директорию, — один из первых публичных случаев использования хуков AI-агентов (.claude/) как вектора атаки на цепочку поставок.

    Ловушка (механизм «мертвеца»)

    Имплант устанавливает «watcher» (gh-token-monitor), который поддерживается в живых LaunchAgent (macOS) или пользовательским сервисом systemd + loginctl enable-linger (Linux). Каждые 60 секунд он проверяет украденный GitHub-токен через API. Пока токен работает, ничего не происходит. Когда ответ становится 4xx — то есть в момент отзыва токена — он выполняет через eval содержимое ~/.config/gh-token-monitor/handler: произвольную команду, заданную удалённо атакующим. Публичный анализ не знает, что там — это может быть уничтожение данных, повторная имплантация, программа-вымогатель или ничего. Риск не поддаётся оценке; именно поэтому порядок реагирования абсолютен.

    Три свойства, которые меняют реагирование:

    • Изоляция сети безопасна: без подключения нет HTTP-ответа, значит нет 4xx — ловушка не срабатывает, а эксфильтрация прекращается. Сначала изолируйте, не выключайте питание (энергозависимая память — это улика).
    • Он одноразовый и самоочищается после срабатывания — поведение становится необъяснимым, не остаётся артефактов для расследования.
    • TTL ~24 часа: watcher самоуничтожается через сутки. Отсутствие артефактов не доказывает, что машина была чиста — сканер предупреждает об этом в режиме host.

    Почему обычная защита в основном его пропускает

    • «Подпись была валидной» — [email protected] вышел с валидной аттестацией SLSA. Происхождение (provenance) подтверждает целостность сборки, а не исходного кода: легитимный workflow компилировал уже троянизированный код.
    • «Диф кода не изменился» — верно: сама библиотека не модифицировалась. Вредоносность в package.json (хук preinstall) и двух новых файлах, добавленных в пакет (setup.mjs, Math_Symbol.js).
    • «Мы не используем keyv» — используете, косвенно: самая частая цепочка — eslint → file-entry-cache → flat-cache → keyv. Поэтому сканер показывает цепочку в каждой находке.
    • «Никто не запускал npm install» — недостаточно: см. вектор B.

    Что представляет собой скрипт в этом репозитории

    scan.mjs обладает следующими свойствами — это важно для любого, кто реагирует на инцидент в цепочке поставок:

    • Один файл, ~880 читабельных строк, ноль зависимостей. Никакого npm install. Проверьте весь scan.mjs за 15 минут перед запуском.
    • Нулевой исходящий трафик. Никакие данные не покидают вашу машину. Ни телеметрии, ни «отправьте результат на анализ». Единственная сетевая операция — --update (загрузка свежего манифеста IOC), явная и необязательная.
    • Только чтение. Сканер не изменяет, не удаляет и не выполняет ничего из найденного.
    • Работает офлайн. docker run --network=none или изолированная машина: просто скопируйте scan.mjs + iocs.json.

    Как использовать это в вашей компании

    Требование: Node.js ≥ 18 (на любой машине с npm он уже есть). Скачайте два файла — scan.mjs + iocs.json — и всё: никакой установки.

    Внимание: если вы клонировали весь этот репозиторий, папка fixtures/ содержит инертные IOC, используемые в тестах (реальные имена и версии, фиктивное содержимое — без вредоносного ПО). Сканер пропускает её автоматически и предупреждает в выводе; находки из неё появятся, только если сканировать её намеренно.

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

    • Режим repo читает lock-файлы и node_modules — а lock-файлы живут в git, поэтому он может быть централизован: один человек сканирует все репозитории компании.
    • Режим host ищет имплант (watcher, LaunchAgent/systemd, хуки IDE), который живёт на машине, где выполнялся код — этого нет в git, и это нельзя централизовать.

    Шаг 1 — AppSec сканирует все репозитории (один человек, одна машина)

    root@kitploit:~
    node scan.mjs repo /folder/with/all/the/repos --json=result.json --html=report.html
    

    Отвечает на вопрос «какие проекты затронуты» за минуты, никого не привлекая. Принимает несколько путей; обходит поддиректории (включая монорепозитории и workspaces).

    Шаг 2 — те, кто работал с затронутыми проектами, сканируют свою машину

    Для каждого проекта с находкой определите, кто трогал его с 2026-08-04 09:35 UTC (git log, логи CI). Эти люди запускают на своей машине:

    root@kitploit:~
    node scan.mjs        # current directory + host, in ~30 seconds
    

    В область действия входят все, кто (a) запускал npm install/npm ci в этом окне; или (b) просто клонировал и открыл папку в VS Code или в AI-агенте — вектору B установка не нужна.

    Поскольку стоимость ~30 секунд, а воронка может протекать (случайный клон, личный проект), самое безопасное внутреннее сообщение: каждый разработчик запускает node scan.mjs один раз и отправляет --json/--html в AppSec. Отправка вручную — это осознанное решение: у сканера нет телеметрии (нулевой исходящий трафик).

    Шаг 3 — CI-раннеры и сборочные серверы

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

    Триаж прошлого — НЕ сканируйте раннер, чтобы принять решение. Вопрос «был ли затронут этот раннер?» не решается сканированием: если какая-либо задача устанавливала затронутую версию без --ignore-scripts с 08-04, учётные данные уже были украдены в этот момент, а хост раннера редко сохраняет улики (эфемерные раннеры уничтожают контейнер в конце задачи; watcher самоочищается за ~24 часа). Отвечают на этот вопрос lock-файлы из шага 1 и логи CI. Если ответ «да, устанавливал»: пересоберите раннер и отзовите его секреты — раннеры эфемерны, чистить их нет смысла.

    Профилактика на будущее — ДА, запускайте его в пайплайне. Добавьте сканер как шаг сборки, в режиме repo, после checkout и до npm install. Он не проверяет хост раннера — он проверяет код, который собираются установить, и код возврата останавливает сборку до того, как вредоносный preinstall получит шанс выполниться:

    root@kitploit:~
    # example (GitHub Actions / GitLab CI — adapt):
    - run: node scan.mjs repo . --json    # exit 0 clean · 1 findings · 2 COMPROMISED
    - run: npm ci --ignore-scripts         # only runs if the previous step passed
    

    Краткая справка

    root@kitploit:~
    node scan.mjs                     # scan the current directory + the host
    node scan.mjs repo /path/a /path/b
    node scan.mjs host                # persistence/implants on the machine only
    node scan.mjs repo . --json=result.json --html=report.html
    node scan.mjs --update            # update iocs.json (the only network operation)
    

    Триаж

    УровеньЗначениеДействие
    COMPROMISEDВредоносная версия установлена в node_modules, полезная нагрузка подтверждена по хэшу или найден имплант персистентностиСчитайте хост скомпрометированным; следуйте порядку реагирования — очистите имплант до ротации учётных данных
    EXPOSEDВредоносная версия закреплена в lock-файле, нет доказательств выполненияЗакрепите безопасную версию, удалите node_modules, переустановите с --ignore-scripts
    AT_RISKДиапазон (^/~) в package.json, допускающий вредоносную версиюЗакрепите точную версию или заблокируйте её на прокси реестра
    SUSPECTЭвристика (имя файла червя с несовпадающим хэшем, подозрительный скрипт жизненного цикла)Проверьте вручную — это может быть новый вариант или ложное срабатывание
    INFOВектор присутствует, но IOC нет (например, общая задача folderOpen)Проанализировать

    Отчёт как доказательство

    --html создаёт автономный отчёт с меткой времени, именем хоста, версией манифеста IOC и собственным SHA-256 сканера — он пригоден как приложение к уведомлению об инциденте и как аудиторский след.

    Если сканер сообщил COMPROMISED: порядок реагирования

    Пока не отзывайте и не ротируйте никакие учётные данные — это триггер ловушки. Последовательность:

    1. ИЗОЛИРУЙТЕ — отключите машину от сети. Это безопасно: без HTTP-ответа нет 4xx, ловушка не срабатывает, эксфильтрация прекращается. Не выключайте питание (энергозависимая память — улика).

    2. СОХРАНИТЕ — перед удалением чего-либо (watcher самоуничтожается за ~24 часа):

    root@kitploit:~
    mkdir -p /tmp/evidence && cp -r ~/.config/gh-token-monitor /tmp/evidence/ 2>/dev/null
    cp /tmp/gh-token-monitor.*.log /tmp/evidence/ 2>/dev/null
    shasum -a 256 /tmp/evidence/* 2>/dev/null
    

    Файл handler — это команда атакующего, которая должна была выполниться, — не запускайте его, не вставляйте в шелл; обращайтесь с ним как с инертным текстом. Файл started_at ограничивает окно воздействия (аудитор и регулятор спросят его).

    3. УДАЛИТЕ — сначала убейте процесс watcher, затем:

    root@kitploit:~
    # macOS
    launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/com.user.gh-token-monitor.plist
    rm -f ~/Library/LaunchAgents/com.user.gh-token-monitor.plist
    
    # Linux
    systemctl --user disable --now gh-token-monitor.service
    loginctl disable-linger "$USER"
    rm -f ~/.config/systemd/user/gh-token-monitor.service
    
    # both
    rm -rf ~/.config/gh-token-monitor ~/.local/bin/gh-token-monitor.sh /tmp/bun-dl-*
    

    Также удалите вредоносные хуки из .claude/settings.json и .vscode/tasks.json, файлы setup.mjs/Math_Symbol.js/math_init.js и очистите кэши (~/.npm/_cacache, pnpm, yarn). Снова запустите node scan.mjs host, пока он не вернёт чистый результат.

    4. ОТЗОВИТЕ — только когда все затронутые хосты очищены и проверены (одного живого watcher достаточно, чтобы сработал триггер). Сначала отзовите npm-токен (останавливает распространение червя); затем GitHub (PAT, deploy-ключи), AWS/GCP/Azure, Vault, Kubernetes, секреты CI — и любой секрет, который был на диске, потому что проводился regex-поиск.

    5. ПРОВЕДИТЕ АУДИТ — червь действует от вашего имени: ищите в ваших организациях репозитории с описанием Shai-Hulud: Here We Go Again, неожиданно опубликованные с 08-04 npm-версии (депрекейтните их и уведомите потребителей) и использование учётных данных в CloudTrail/Audit Logs в окне started_at.

    После этого: удалите node_modules, переустановите из чистого lock-файла с --ignore-scripts. CI-раннеры и хосты с подтверждённым выполнением: пересобирайте с нуля, всегда — выполнялся произвольный код, и список известных артефактов не гарантирует полноты.

    Регулируемые организации (BR): подтверждённая компрометация с доступом к учётным данным может повлечь обязательства по уведомлению (Res. CMN 4.893/2021, Res. BCB 85/2021; LGPD ст. 48, если затронуты персональные данные). Документируйте таймлайн в UTC — started_at, обнаружение, сдерживание, устранение, ротация — и подтверждайте сроки с юристами/комплаенсом.

    Обновление IOC (пользователи)

    Инцидент активен, список растёт. Чтобы получить свежий манифест:

    root@kitploit:~
    node scan.mjs --update          # the only operation that touches the network
    

    --update забирает iocs.json из этого репозитория (securest8/npm-incident-response), никогда у третьих лиц — Securest8 является воротами курирования. Вы получаете то, что было опубликовано здесь последним.

    Поддержание IOC (мейнтейнеры)

    Список пакетов берётся из публичного фида Wiz; хэши, C2-домены, IOC персистентности и безопасные версии статичны и курируются в tools/gen-iocs.mjs. Снимок CSV Wiz хранится в tools/keyv-packages.csv для воспроизводимости и офлайн-запусков.

    root@kitploit:~
    node tools/gen-iocs.mjs               # fetch the latest Wiz CSV, regenerate iocs.json + refresh the snapshot
    node tools/gen-iocs.mjs --offline     # regenerate from the committed snapshot, no network
    node tools/gen-iocs.mjs --allow-shrink # allow a package count lower than the snapshot (guarded by default)
    

    Генератор идемпотентен: он сохраняет существующий manifest_version и не перезаписывает файл, если ничего существенного не изменилось, а также отказывается записывать пустой или уменьшенный манифест (защита от усечённого/изменённого вышестоящего фида).

    Автоматизация: .github/workflows/update-iocs.yml запускает генератор ежедневно (и по требованию) и коммитит в main только когда IOC действительно меняются — так что пользовательский --update отслеживает фид Wiz с задержкой примерно в день, а вся история доступна для аудита в коммитах. Переключите это на шаг pull-request (отмечено в workflow), когда инцидент утихнет и вы захотите ручное слияние.

    Тесты

    root@kitploit:~
    node test/run-tests.mjs         # 15 assertions against fixtures/demo-repo
    

    fixtures/demo-repo — тестовый репозиторий с инертными IOC (реальные имена и версии, фиктивное содержимое — без вредоносного ПО). При сканировании собственного репозитория сканера папка fixtures/ пропускается автоматически (с предупреждением в выводе); тесты сканируют её, передавая путь явно.

    Сфера применения и благодарности

    Инструмент под один инцидент, создан для быстрого триажа в активном окне атаки — не замена Socket, Snyk или аналогичных. Исследование и IOC: Socket.dev, Wiz Research (публичный CSV), Kodem Security.

    Поддерживается Securest8. Лицензия MIT.

    Скачать инструмент