
Автоматизированный монитор безопасности цепочки поставок, который опрашивает реестры PyPI и npm, сравнивает новые релизы с предыдущими и использует анализ LLM для обнаружения вредоносных изменений кода с уведомлениями в Slack.
Автоматизированный мониторинг популярных пакетов PyPI и npm на предмет компрометации цепочки поставок. Опрашивает оба реестра на наличие новых релизов, сравнивает каждый новый релиз с предыдущим и использует LLM (через Cursor Agent CLI) для классификации изменений как безвредные или вредоносные. Вредоносные находки вызывают оповещение в Slack.
По умолчанию мониторинг ведется для обеих экосистем. Используйте --no-pypi или --no-npm, чтобы отключить одну из них.
В каждой экосистеме работает свой поток опроса, но они используют общий конвейер анализа и оповещения.
┌─── PyPI ──────────────────────┐ ┌─── npm ───────────────────────┐
│ │ │ │
│ changelog_since_serial() │ │ CouchDB _changes feed │
│ │ │ │ │ │
│ ▼ │ │ ▼ │
│ ┌────────────┐ │ │ ┌────────────┐ │
│ │ Все PyPI │─┐ │ │ │ Все npm │─┐ │
│ │ события │ │ │ │ │ изменения │ │ │
│ └────────────┘ ▼ │ │ └────────────┘ ▼ │
│ hugovk ──► Список наблюдения │ │ download-counts ─► Список наблюдения│
│ │ │ │ │ │
│ только события "new release" │ │ новые версии с последней эпохи│
└───────────────┬───────────────┘ └───────────────┬───────────────┘
│ │
▼ ▼
┌───────────────────┐ ┌───────────────────┐
│ Загрузить старую +│ │ Загрузить старый +│
│ новую (sdist + │ │ новый (tarball) │
│ wheel) │ │ │
└───────────────────┘ └───────────────────┘
│ │
└─────────────────┬─────────────────┘
▼
┌───────────────┐
│ Unified diff │
│ report (.md) │
└───────┬───────┘
▼
┌───────────────┐ ◄── Анализ LLM
│ Cursor Agent │ (только чтение)
│ CLI (ask mode)│
└───────┬───────┘
│
вердикт?
│
вредоносный │
▼
┌───────────────┐
│ Оповещение в │
│ Slack │
└───────────────┘
Анализ LLM нацелен на поиск:
pip install -r requirements.txt (стандартная библиотека покрывает большую часть инструмента; requests используется для загрузки в Slack)agent, а не IDEWindows (PowerShell):
irm 'https://cursor.com/install?win32=true' | iex
macOS / Linux:
curl https://cursor.com/install -fsS | bash
Проверьте с помощью:
agent --version
Вы должны быть аутентифицированы в Cursor (agent login или установите CURSOR_API_KEY).
Поместите ваш токен бота Slack в etc/slack.json:
{
"url": "https://hooks.slack.com/services/...",
"bot_token": "xoxb-...",
"channel": "C01XXXXXXXX"
}
Боту требуется область chat:write для целевого канала. Поле channel — это ID канала Slack, куда публикуются оповещения.
# Однократный запуск: проанализировать релизы за последние ~10 минут
python monitor.py --once
# Непрерывный мониторинг: отслеживать топ-1000 пакетов (обе экосистемы), опрос каждые 5 мин
python monitor.py --top 1000 --interval 300
# Продакшн: мониторинг топ-15000, оповещение в Slack
python monitor.py --top 15000 --interval 300 --slack
# Только npm, топ-5000
python monitor.py --no-pypi --npm-top 5000
# Только PyPI
python monitor.py --no-npm
| Файл | Назначение |
|---|---|
monitor.py | Основной оркестратор — опрос PyPI + npm, сравнение, анализ, оповещение (параллельные потоки) |
pypi_monitor.py | Автономный опросчик журнала изменений PyPI (используется для исследования) |
package_diff.py | Загрузка и сравнение двух версий любого пакета PyPI или npm |
analyze_diff.py | Отправка различий в Cursor Agent CLI, разбор вердикта |
top_pypi_packages.py | Получение и вывод списка топ-N пакетов PyPI по количеству загрузок |
slack.py | Клиент API Slack (SendMessage, PostFile) |
etc/slack.json | Учетные данные бота Slack |
last_serial.yaml | Сохраненное состояние опроса (серийный номер PyPI + последовательность/эпоха npm) |
logs/ | Ежедневные файлы журнала (monitor_YYYYMMDD.log) |
python monitor.py [ОПЦИИ]
Опции:
--top N Количество отслеживаемых пакетов в каждой экосистеме (по умолчанию: 15000)
--interval SECS Интервал опроса в секундах (по умолчанию: 300)
--once Однократный проход по последним событиям, затем выход
--slack Включить оповещения Slack для вредоносных находок
--model MODEL Переопределить модель LLM (по умолчанию: composer-2-fast)
--debug Включить отладку (включает необработанный вывод агента)
Опции PyPI:
--no-pypi Отключить мониторинг PyPI
--serial N Серийный номер журнала изменений PyPI, с которого начинать
Опции npm:
--no-npm Отключить мониторинг npm
--npm-top N Количество отслеживаемых пакетов npm (по умолчанию: совпадает с --top)
--npm-seq N Последовательность репликации npm, с которой начинать
PyPI и npm работают каждый в своем потоке опроса. Состояние опроса (серийный номер PyPI, последовательность + эпоха npm) сохраняется в last_serial.yaml, чтобы монитор возобновлял работу с места остановки после перезапуска.
Конвейер PyPI:
--interval секунд вызывает changelog_since_serial() — один вызов API, который возвращает все события с момента последней проверки"new release", соответствующие списку наблюденияКонвейер npm:
replicate.npmjs.com--interval секунд получает канал _changes для всех изменений реестра с момента последней последовательностиВсе выходные данные записываются как в консоль, так и в файл logs/monitor_YYYYMMDD.log.
# Сравнить две версии из PyPI
python package_diff.py requests 2.31.0 2.32.0
# Сравнить две версии из npm
python package_diff.py --npm express 4.18.2 4.19.0
# Сохранить в файл
python package_diff.py telnyx 2.0.0 2.1.0 -o telnyx_diff.md
# Сравнить локальные архивы
python package_diff.py --local old.tar.gz new.tar.gz -n mypackage
Загрузки выполняются напрямую через API реестров (PyPI JSON API / npm registry), а не через pip или npm. Это означает:
# Проанализировать файл различий
python analyze_diff.py telnyx_diff.md
# Вывод в JSON
python analyze_diff.py telnyx_diff.md --json
# Использовать определенную модель
python analyze_diff.py telnyx_diff.md --model claude-4-opus
Запускает Cursor Agent CLI в режиме --mode ask (только чтение) с --trust. Агент читает файл различий и возвращает структурированный вердикт.
Коды выхода: 0 = безвредно, 1 = вредоносно, 2 = неизвестно/ошибка.
# Посмотреть, что выпускается прямо сейчас (за последние ~10 мин)
python pypi_monitor.py --once --top 15000
# Непрерывный мониторинг (только вывод в консоль, без анализа)
python pypi_monitor.py --top 1000 --interval 120
Полезно для изучения скорости выпуска PyPI или отладки API журнала изменений без запуска полного конвейера анализа.
# Вывести топ-1000 пакетов
python top_pypi_packages.py
# Использовать как библиотеку
from top_pypi_packages import fetch_top_packages
packages = fetch_top_packages(top_n=500)
# [{"project": "boto3", "download_count": 1577565199}, ...]
| Источник | Что | Лимиты запросов |
|---|---|---|
| hugovk/top-pypi-packages | Топ-15,000 пакетов PyPI по загрузкам за 30 дней (ежемесячный JSON) | Нет (статический файл) |
PyPI XML-RPC changelog_since_serial() | Живой поток событий PyPI | Устаревший, но работает; 1 вызов за опрос — нормально |
| PyPI JSON API | Метаданные пакета, история версий, URL для загрузки | Щедрый; используется редко (1 вызов на релиз) |
| download-counts (nice-registry) | Ежемесячные счетчики загрузок для каждого пакета npm (counts.json) | Нет (tarball npm) |
| npm CouchDB replication _changes feed | Поток изменений в реальном времени реестра npm | Публичный; постраничное чтение |
| npm registry API | Манифесты пакетов, загрузка tarball'ов | Щедрый; используется редко |
Монитор выполняет 1 вызов API за интервал опроса на экосистему (журнал изменений PyPI / _changes npm), плюс 2-3 вызова на новый релиз (история версий + загрузки). Это очень легко.
Когда монитор обнаруживает вредоносный релиз, он отправляет сообщение в Slack:
PyPI:
🚨 Оповещение о цепочке поставок: telnyx 4.87.2
Рейтинг: #5,481 среди топ-пакетов PyPI
Вердикт: ВРЕДОНОСНЫЙ
PyPI: https://pypi.org/project/telnyx/4.87.2/
Сводка анализа (сокращенно):
Изменения в src/telnyx/_client.py реализуют обфусцированное
поведение загрузка-расшифровка-выполнение и побочные эффекты
импорта модуля. Функция _d() декодирует строки base64,
огромный блок _p содержит скрипт эксфильтрации, который загружает
файл .wav с http://83.142.209.203:8080/ringtone.wav и извлекает
скрытую нагрузку с помощью стеганографии...
npm:
🚨 Оповещение о цепочке поставок: axios 0.30.4
Рейтинг: #42 среди топ-пакетов npm
Вердикт: ВРЕДОНОСНЫЙ
npm: https://www.npmjs.com/package/axios/v/0.30.4
Сводка анализа (сокращенно):
1. **Нестандартная зависимость** — Блок `dependencies` включает `plain-crypto-js`. Публикуемый axios зависит только от `follow-redirects`, `form-data` и `proxy-from-env`. Четвертый пакет, чье имя выглядит как **typosquat в стиле `crypto-js`**, является классическим признаком подделанного или фейкового пакета, а не обычного релиза axios.
agent.ask, но без изоляции на уровне ОС.Логи записываются как в stdout, так и в файл logs/monitor_YYYYMMDD.log. Каждый день создается новый файл. Обе экосистемы пишут в один файл, строки npm имеют префикс [npm]. Пример:
2026-03-27 12:01:15 [INFO] Получение топ-15 000 пакетов из набора данных hugovk...
2026-03-27 12:01:16 [INFO] Список наблюдения загружен: 15 000 пакетов (набор данных обновлен 2026-03-01 07:34:08)
2026-03-27 12:01:16 [INFO] Получение топ-15 000 пакетов npm из набора данных download-counts...
2026-03-27 12:01:18 [INFO] Список наблюдения npm загружен: 15 000 пакетов (download-counts 1.0.52)
2026-03-27 12:01:19 [INFO] [pypi] Стартовый серийный номер: 35 542 068 (из last_serial.yaml) — опрос каждые 300 с
2026-03-27 12:01:19 [INFO] [npm] Стартовая последовательность: 42 817 503 (из last_serial.yaml) — опрос каждые 300 с
2026-03-27 12:06:18 [INFO] [pypi] Обнаружено 2 новых релиза из списка наблюдения (серийный номер 35 542 068 -> 35 542 190)
2026-03-27 12:06:18 [INFO] [pypi] Обработка fast-array-utils 1.4 (рейтинг #8 231)...
2026-03-27 12:06:18 [INFO] [pypi] Сравнение fast-array-utils 1.3 -> 1.4
2026-03-27 12:06:50 [INFO] [pypi] Анализ различий для fast-array-utils...
2026-03-27 12:07:35 [INFO] [pypi] Вердикт для fast-array-utils 1.4: БЕЗВРЕДНО
2026-03-27 12:06:20 [INFO] [npm] Обнаружен 1 новый релиз из списка наблюдения (последовательность -> 42 817 612)
2026-03-27 12:06:20 [INFO] [npm] Обработка axios 0.30.4 (рейтинг #42)...
2026-03-27 12:06:21 [INFO] [npm] Сравнение axios 0.30.3 -> 0.30.4
2026-03-27 12:07:01 [INFO] [npm] Анализ различий для axios...
2026-03-27 12:07:45 [INFO] [npm] Вердикт для axios 0.30.4: ВРЕДОНОСНЫЙ
Этот проект лицензирован под MIT License. Сторонние источники данных и уведомления обобщены в NOTICE.txt.
Приветствуются вклады — см. CONTRIBUTING.md. Этот репозиторий следует Contributor Covenant. Сообщайте о проблемах безопасности через SECURITY.md, а не в открытых issues.
Вопросы и обсуждения: Elastic community Slack.