
Monitor automatizado de seguridad en la cadena de suministro que consulta los registros PyPI y npm, compara las nuevas versiones con las anteriores y utiliza análisis mediante LLM para detectar cambios de código maliciosos con alertas en Slack.
Monitoreo automatizado de los paquetes principales de PyPI y npm para detectar compromisos en la cadena de suministro. Consulta ambos registros en busca de nuevas versiones, compara cada versión con su predecesora y utiliza un LLM (a través de Cursor Agent CLI) para clasificar las diferencias como benignas o maliciosas. Los hallazgos maliciosos activan una alerta en Slack.
Ambos ecosistemas se monitorean de forma predeterminada. Use --no-pypi o --no-npm para desactivar uno.
Cada ecosistema ejecuta su propio hilo de consulta, pero comparte la canalización de análisis y alertas.
┌─── PyPI ──────────────────────┐ ┌─── npm ───────────────────────┐
│ │ │ │
│ changelog_since_serial() │ │ CouchDB _changes feed │
│ │ │ │ │ │
│ ▼ │ │ ▼ │
│ ┌────────────┐ │ │ ┌────────────┐ │
│ │ All PyPI │─┐ │ │ │ All npm │─┐ │
│ │ events │ │ │ │ │ changes │ │ │
│ └────────────┘ ▼ │ │ └────────────┘ ▼ │
│ hugovk ──► Watchlist │ │ download-counts ─► Watchlist │
│ │ │ │ │ │
│ "new release" events only │ │ new versions since last epoch │
└───────────────┬───────────────┘ └───────────────┬───────────────┘
│ │
▼ ▼
┌───────────────────┐ ┌───────────────────┐
│ Download old + new│ │ Download old + new│
│ (sdist + wheel) │ │ (tarball) │
└───────────────────┘ └───────────────────┘
│ │
└─────────────────┬─────────────────┘
▼
┌───────────────┐
│ Unified diff │
│ report (.md) │
└───────┬───────┘
▼
┌───────────────┐ ◄── LLM analysis
│ Cursor Agent │ (read-only)
│ CLI (ask mode)│
└───────┬───────┘
│
verdict?
│
malicious │
▼
┌───────────────┐
│ Slack alert │
└───────────────┘
Se solicita al análisis del LLM buscar:
pip install -r requirements.txt (la stdlib cubre la mayor parte de la herramienta; requests se usa para las subidas a Slack)agent, no el IDEWindows (PowerShell):
irm 'https://cursor.com/install?win32=true' | iex
macOS / Linux:
curl https://cursor.com/install -fsS | bash
Verifique con:
agent --version
Debe estar autenticado con Cursor (agent login o establecer CURSOR_API_KEY).
Coloque su token de bot de Slack en etc/slack.json:
{
"url": "https://hooks.slack.com/services/...",
"bot_token": "xoxb-...",
"channel": "C01XXXXXXXX"
}
El bot necesita el ámbito chat:write en el canal de destino. El campo channel es el ID del canal de Slack donde se publican las alertas.
# Una sola ejecución: analizar versiones de los últimos ~10 minutos
python monitor.py --once
# Continuo: monitorear los 1000 paquetes principales (ambos ecosistemas), consultar cada 5 min
python monitor.py --top 1000 --interval 300
# Producción: monitorear los 15000 principales, alertar a Slack
python monitor.py --top 15000 --interval 300 --slack
# Solo npm, top 5000
python monitor.py --no-pypi --npm-top 5000
# Solo PyPI
python monitor.py --no-npm
| Archivo | Propósito |
|---|---|
monitor.py | Orquestador principal — consulta PyPI + npm, diff, analiza, alerta (hilos paralelos) |
pypi_monitor.py | Consultor independiente de changelog de PyPI (usado para exploración) |
package_diff.py | Descargar y comparar dos versiones de cualquier paquete de PyPI o npm |
analyze_diff.py | Enviar un diff a Cursor Agent CLI, analizar el veredicto |
top_pypi_packages.py | Obtener y listar los N paquetes principales de PyPI por descargas |
slack.py | Cliente de API de Slack (SendMessage, PostFile) |
etc/slack.json | Credenciales del bot de Slack |
last_serial.yaml | Estado de consulta persistido (serial de PyPI + secuencia/época de npm) |
logs/ | Archivos de registro diarios (monitor_YYYYMMDD.log) |
python monitor.py [OPCIONES]
Opciones:
--top N Número de paquetes principales a monitorear por ecosistema (predeterminado: 15000)
--interval SECS Intervalo de consulta en segundos (predeterminado: 300)
--once Una sola pasada sobre eventos recientes, luego salir
--slack Habilitar alertas de Slack para hallazgos maliciosos
--model MODEL Sobrescribir el modelo LLM (predeterminado: composer-2-fast)
--debug Habilitar registro DEBUG (incluye salida raw del agente)
Opciones de PyPI:
--no-pypi Deshabilitar monitoreo de PyPI
--serial N Serial del changelog de PyPI desde el que comenzar
Opciones de npm:
--no-npm Deshabilitar monitoreo de npm
--npm-top N N principales paquetes npm a monitorear (predeterminado: igual que --top)
--npm-seq N Secuencia de replicación npm desde la que comenzar
PyPI y npm se ejecutan cada uno en su propio hilo de consulta. El estado de consulta (serial de PyPI, secuencia + época de npm) se persiste en last_serial.yaml para que el monitor se reanude donde lo dejó después de un reinicio.
Canalización de PyPI:
--interval segundos, llama a changelog_since_serial() — una única llamada API que devuelve todos los eventos desde la última comprobación"new release" que coinciden con la lista de seguimientoCanalización de npm:
replicate.npmjs.com--interval segundos, obtiene el feed _changes de todos los cambios en el registro desde la última secuenciaToda la salida se registra tanto en la consola como en logs/monitor_YYYYMMDD.log.
# Comparar dos versiones de PyPI
python package_diff.py requests 2.31.0 2.32.0
# Comparar dos versiones de npm
python package_diff.py --npm express 4.18.2 4.19.0
# Guardar en archivo
python package_diff.py telnyx 2.0.0 2.1.0 -o telnyx_diff.md
# Comparar archivos locales
python package_diff.py --local old.tar.gz new.tar.gz -n mypackage
Las descargas se realizan directamente a través de las API del registro (API JSON de PyPI / registro npm), no con pip o npm. Esto significa:
# Analizar un archivo diff
python analyze_diff.py telnyx_diff.md
# Salida JSON
python analyze_diff.py telnyx_diff.md --json
# Usar un modelo específico
python analyze_diff.py telnyx_diff.md --model claude-4-opus
Ejecuta Cursor Agent CLI en modo --mode ask (solo lectura) con --trust. El agente lee el archivo diff y devuelve un veredicto estructurado.
Códigos de salida: 0 = benigno, 1 = malicioso, 2 = desconocido/error.
# Ver qué se está publicando ahora mismo (últimos ~10 min)
python pypi_monitor.py --once --top 15000
# Monitoreo continuo (solo salida en consola, sin análisis)
python pypi_monitor.py --top 1000 --interval 120
Útil para explorar la velocidad de publicación de PyPI o depurar la API de changelog sin ejecutar la canalización completa de análisis.
# Imprimir los 1000 paquetes principales
python top_pypi_packages.py
# Usar como biblioteca
from top_pypi_packages import fetch_top_packages
packages = fetch_top_packages(top_n=500)
# [{"project": "boto3", "download_count": 1577565199}, ...]
| Fuente | Qué | Límites de Tasa |
|---|---|---|
| hugovk/top-pypi-packages | 15,000 paquetes PyPI principales por descargas en 30 días (JSON mensual) | Ninguno (archivo estático) |
PyPI XML-RPC changelog_since_serial() | Flujo de eventos en tiempo real de PyPI | Obsoleto pero funcional; 1 llamada por consulta es suficiente |
| PyPI JSON API | Metadatos del paquete, historial de versiones, URLs de descarga | Generoso; utilizado con moderación (1 llamada por versión) |
| download-counts (nice-registry) | Recuentos de descargas mensuales para cada paquete npm (counts.json) | Ninguno (tarball npm) |
npm CouchDB replication _changes feed | Flujo de cambios del registro npm en tiempo real | Público; lecturas paginadas |
| npm registry API | Packuments de paquetes, descargas de tarballs | Generoso; utilizado con moderación |
El monitor realiza 1 llamada API por intervalo de consulta por ecosistema (changelog de PyPI / _changes de npm), más 2-3 llamadas por nueva versión (historial de versiones + descargas). Esto es muy ligero.
Cuando el monitor detecta una versión maliciosa, publica en Slack:
PyPI:
🚨 Alerta de Cadena de Suministro: telnyx 4.87.2
Rank: #5,481 de paquetes PyPI principales
Veredicto: MALICIOUS
PyPI: https://pypi.org/project/telnyx/4.87.2/
Resumen del análisis (truncado):
Los cambios en src/telnyx/_client.py implementan un comportamiento
de descarga-descifrado-ejecución ofuscado y efectos secundarios de
importación de módulos. Una función _d() decodifica cadenas base64,
un blob masivo _p contiene un script de exfiltración que descarga
un archivo .wav de http://83.142.209.203:8080/ringtone.wav y extrae
una carga útil oculta mediante esteganografía...
npm:
🚨 Alerta de Cadena de Suministro: axios 0.30.4
Rank: #42 de paquetes npm principales
Veredicto: MALICIOUS
npm: https://www.npmjs.com/package/axios/v/0.30.4
Resumen del análisis (truncado):
1. **Dependencia no estándar** — El bloque `dependencies` incluye `plain-crypto-js`. axios publicado solo depende de `follow-redirects`, `form-data` y `proxy-from-env`. Un cuarto paquete cuyo nombre parece un **typosquat al estilo de `crypto-js`** es un signo clásico de un paquete manipulado o falso, no de una versión normal de axios.
agent esté autenticado.ask de solo lectura pero sin aislamiento a nivel de sistema operativo.Los registros se escriben tanto en stdout como en logs/monitor_YYYYMMDD.log. Se crea un nuevo archivo cada día. Ambos ecosistemas registran en el mismo archivo, con las líneas npm prefijadas [npm]. Ejemplo:
2026-03-27 12:01:15 [INFO] Fetching top 15,000 packages from hugovk dataset...
2026-03-27 12:01:16 [INFO] Watchlist loaded: 15,000 packages (dataset updated 2026-03-01 07:34:08)
2026-03-27 12:01:16 [INFO] Fetching top 15,000 npm packages from download-counts dataset...
2026-03-27 12:01:18 [INFO] npm watchlist loaded: 15,000 packages (download-counts 1.0.52)
2026-03-27 12:01:19 [INFO] [pypi] Starting serial: 35,542,068 (from last_serial.yaml) — polling every 300s
2026-03-27 12:01:19 [INFO] [npm] Starting seq: 42,817,503 (from last_serial.yaml) — polling every 300s
2026-03-27 12:06:18 [INFO] [pypi] 2 new watchlist releases detected (serial 35,542,068 -> 35,542,190)
2026-03-27 12:06:18 [INFO] [pypi] Processing fast-array-utils 1.4 (rank #8,231)...
2026-03-27 12:06:18 [INFO] [pypi] Diffing fast-array-utils 1.3 -> 1.4
2026-03-27 12:06:50 [INFO] [pypi] Analyzing diff for fast-array-utils...
2026-03-27 12:07:35 [INFO] [pypi] Verdict for fast-array-utils 1.4: BENIGN
2026-03-27 12:06:20 [INFO] [npm] 1 new watchlist releases detected (seq -> 42,817,612)
2026-03-27 12:06:20 [INFO] [npm] Processing axios 0.30.4 (rank #42)...
2026-03-27 12:06:21 [INFO] [npm] Diffing axios 0.30.3 -> 0.30.4
2026-03-27 12:07:01 [INFO] [npm] Analyzing diff for axios...
2026-03-27 12:07:45 [INFO] [npm] Verdict for axios 0.30.4: MALICIOUS
Este proyecto está bajo la Licencia MIT. Las fuentes de datos y avisos de terceros se resumen en NOTICE.txt.
Las contribuciones son bienvenidas — consulte CONTRIBUTING.md. Este repositorio sigue el Contributor Covenant. Reporte problemas de seguridad a través de SECURITY.md, no en issues públicos.
Preguntas y discusión: Comunidad Elastic en Slack.