
Monitor automatico di sicurezza della supply chain che interroga i registri PyPI e npm, confronta le nuove release con le precedenti e utilizza l'analisi LLM per rilevare modifiche di codice dannose con avvisi su Slack.
Monitoraggio automatizzato dei principali pacchetti PyPI e npm per compromissioni della supply chain. Interroga entrambi i registry per nuove release, confronta ogni release con la precedente e utilizza un LLM (tramite Cursor Agent CLI) per classificare le differenze come benigne o malevole. I risultati malevoli attivano un avviso su Slack.
Entrambi gli ecosistemi sono monitorati per impostazione predefinita. Usa --no-pypi o --no-npm per disabilitarne uno.
Ogni ecosistema esegue il proprio thread di polling ma condivide la pipeline di analisi e notifica.
┌─── PyPI ──────────────────────┐ ┌─── npm ───────────────────────┐
│ │ │ │
│ changelog_since_serial() │ │ CouchDB _changes feed │
│ │ │ │ │ │
│ ▼ │ │ ▼ │
│ ┌────────────┐ │ │ ┌────────────┐ │
│ │ Tutti gli │─┐ │ │ │ Tutte le │─┐ │
│ │ eventi PyPI│ │ │ │ │ modifiche │ │ │
│ └────────────┘ ▼ │ │ │ npm │ │ │
│ hugovk ──► Watchlist │ │ └────────────┘ ▼ │
│ │ │ │ download-counts ─► Watchlist │
│ solo eventi "new release" │ │ nuove versioni dall'ultimo │
└───────────────┬───────────────┘ │ epoch │
│ └───────────────┬───────────────┘
▼ ▼
┌───────────────────┐ ┌───────────────────┐
│ Scarica vecchia + │ │ Scarica vecchia + │
│ nuova (sdist + │ │ nuova (tarball) │
│ wheel) │ └───────────────────┘
└───────────────────┘
│ │
└─────────────────┬─────────────────┘
▼
┌───────────────┐
│ Report diff │
│ unificato (.md)│
└───────┬───────┘
▼
┌───────────────┐ ◄── Analisi LLM
│ Cursor Agent │ (sola lettura)
│ CLI (ask mode)│
└───────┬───────┘
│
verdetto?
│
malevolo │
▼
┌───────────────┐
│ Avviso Slack │
└───────────────┘
L'analisi LLM è istruita per cercare:
pip install -r requirements.txt (la libreria standard copre la maggior parte dello strumento; requests è usata per i caricamenti su Slack)agent standalone, non l'IDEWindows (PowerShell):
irm 'https://cursor.com/install?win32=true' | iex
macOS / Linux:
curl https://cursor.com/install -fsS | bash
Verifica con:
agent --version
Devi essere autenticato con Cursor (agent login o imposta CURSOR_API_KEY).
Inserisci il tuo token bot Slack in etc/slack.json:
{
"url": "https://hooks.slack.com/services/...",
"bot_token": "xoxb-...",
"channel": "C01XXXXXXXX"
}
Il bot necessita dell'ambito chat:write sul canale di destinazione. Il campo channel è l'ID del canale Slack dove vengono pubblicati gli avvisi.
# Passaggio singolo: analizza le release degli ultimi ~10 minuti
python monitor.py --once
# Continuo: monitora i primi 1000 pacchetti (entrambi gli ecosistemi), polling ogni 5 min
python monitor.py --top 1000 --interval 300
# Produzione: monitora i primi 15000, avvisa su Slack
python monitor.py --top 15000 --interval 300 --slack
# Solo npm, primi 5000
python monitor.py --no-pypi --npm-top 5000
# Solo PyPI
python monitor.py --no-npm
| File | Scopo |
|---|---|
monitor.py | Orchestratore principale — esegue il polling di PyPI + npm, diff, analisi, notifica (thread paralleli) |
pypi_monitor.py | Poller standalone del changelog PyPI (usato per esplorazione) |
package_diff.py | Scarica e confronta due versioni di qualsiasi pacchetto PyPI o npm |
analyze_diff.py | Invia un diff a Cursor Agent CLI, analizza il verdetto |
top_pypi_packages.py | Recupera e elenca i primi N pacchetti PyPI per conteggio download |
slack.py | Client API Slack (SendMessage, PostFile) |
etc/slack.json | Credenziali bot Slack |
last_serial.yaml | Stato di polling persistito (serial PyPI + sequence/epoch npm) |
logs/ | File di log giornalieri (monitor_YYYYMMDD.log) |
python monitor.py [OPZIONI]
Opzioni:
--top N Numero di pacchetti migliori da monitorare per ecosistema (default: 15000)
--interval SECS Intervallo di polling in secondi (default: 300)
--once Singolo passaggio sugli eventi recenti, poi esci
--slack Abilita avvisi Slack per risultati malevoli
--model MODEL Sovrascrivi modello LLM (default: composer-2-fast)
--debug Abilita logging DEBUG (include output raw dell'agente)
Opzioni PyPI:
--no-pypi Disabilita monitoraggio PyPI
--serial N Serial del changelog PyPI da cui iniziare
Opzioni npm:
--no-npm Disabilita monitoraggio npm
--npm-top N Primi N pacchetti npm da monitorare (default: uguale a --top)
--npm-seq N Sequence di replica npm da cui iniziare
PyPI e npm eseguono ciascuno il proprio thread di polling. Lo stato di polling (serial PyPI, sequence + epoch npm) viene persistito in last_serial.yaml in modo che il monitor riprenda da dove si era interrotto dopo un riavvio.
Pipeline PyPI:
--interval secondi, chiama changelog_since_serial() — una singola chiamata API che restituisce tutti gli eventi dall'ultimo controllo"new release" corrispondenti alla watchlistPipeline npm:
replicate.npmjs.com--interval secondi, recupera il feed _changes per tutte le modifiche al registry dall'ultima sequenceTutto l'output è registrato sia sulla console che su logs/monitor_YYYYMMDD.log.
# Confronta due versioni da PyPI
python package_diff.py requests 2.31.0 2.32.0
# Confronta due versioni da npm
python package_diff.py --npm express 4.18.2 4.19.0
# Salva su file
python package_diff.py telnyx 2.0.0 2.1.0 -o telnyx_diff.md
# Confronta archivi locali
python package_diff.py --local old.tar.gz new.tar.gz -n mipacchetto
I download sono effettuati direttamente tramite API dei registry (PyPI JSON API / npm registry), non tramite pip o npm. Questo significa:
# Analizza un file diff
python analyze_diff.py telnyx_diff.md
# Output JSON
python analyze_diff.py telnyx_diff.md --json
# Usa un modello specifico
python analyze_diff.py telnyx_diff.md --model claude-4-opus
Esegue Cursor Agent CLI in --mode ask (sola lettura) con --trust. L'agente legge il file diff e restituisce un verdetto strutturato.
Codici di uscita: 0 = benigno, 1 = malevolo, 2 = sconosciuto/errore.
# Vedi cosa viene rilasciato in questo momento (ultimi ~10 min)
python pypi_monitor.py --once --top 15000
# Monitoraggio continuo (solo output console, nessuna analisi)
python pypi_monitor.py --top 1000 --interval 120
Utile per esplorare la velocità di rilascio di PyPI o eseguire debug dell'API del changelog senza eseguire l'intera pipeline di analisi.
# Stampa i primi 1000 pacchetti
python top_pypi_packages.py
# Usa come libreria
from top_pypi_packages import fetch_top_packages
pacchetti = fetch_top_packages(top_n=500)
# [{"project": "boto3", "download_count": 1577565199}, ...]
| Fonte | Cosa | Limiti di frequenza |
|---|---|---|
| hugovk/top-pypi-packages | Primi 15.000 pacchetti PyPI per download su 30 giorni (JSON mensile) | Nessuno (file statico) |
PyPI XML-RPC changelog_since_serial() | Flusso di eventi PyPI in tempo reale | Deprecato ma funzionale; 1 chiamata per polling è sufficiente |
| PyPI JSON API | Metadati pacchetto, cronologia versioni, URL download | Generoso; usato con parsimonia (1 chiamata per release) |
| download-counts (nice-registry) | Conteggi download mensili per ogni pacchetto npm (counts.json) | Nessuno (tarball npm) |
npm CouchDB replication feed _changes | Flusso di modifiche al registry npm in tempo reale | Pubblico; letture paginate |
| npm registry API | Packument dei pacchetti, download tarball | Generoso; usato con parsimonia |
Il monitor effettua 1 chiamata API per intervallo di polling per ecosistema (changelog PyPI / _changes npm), più 2-3 chiamate per nuova release (cronologia versioni + download). È molto leggero.
Quando il monitor rileva una release malevola, pubblica su Slack:
PyPI:
🚨 Allerta Supply Chain: telnyx 4.87.2
Posizione: #5.481 dei primi pacchetti PyPI
Verdetto: MALEVOLO
PyPI: https://pypi.org/project/telnyx/4.87.2/
Riepilogo analisi (troncato):
Le modifiche a src/telnyx/_client.py implementano un comportamento
di download-decrypt-execute offuscato ed effetti collaterali di
import di moduli. Una funzione _d() decodifica stringhe base64,
un enorme blob _p contiene uno script di esfiltrazione che scarica
un file .wav da http://83.142.209.203:8080/ringtone.wav ed estrae
un payload nascosto tramite steganografia...
npm:
🚨 Allerta Supply Chain: axios 0.30.4
Posizione: #42 dei primi pacchetti npm
Verdetto: MALEVOLO
npm: https://www.npmjs.com/package/axios/v/0.30.4
Riepilogo analisi (troncato):
1. **Dipenderza non standard** — Il blocco `dependencies` include `plain-crypto-js`. Axios pubblicato dipende solo da `follow-redirects`, `form-data` e `proxy-from-env`. Un quarto pacchetto il cui nome assomiglia a un typosquat di **`crypto-js`** è un classico segno di un pacchetto manomesso o falso, non di una release normale di axios.
agent sia autenticato.ask di sola lettura ma senza sandbox a livello di sistema operativo.I log vengono scritti sia su stdout che su logs/monitor_YYYYMMDD.log. Viene creato un nuovo file ogni giorno. Entrambi gli ecosistemi scrivono sullo stesso file, con le righe npm precedute da [npm]. Esempio:
2026-03-27 12:01:15 [INFO] Recupero dei primi 15.000 pacchetti dal dataset hugovk...
2026-03-27 12:01:16 [INFO] Watchlist caricata: 15.000 pacchetti (dataset aggiornato 2026-03-01 07:34:08)
2026-03-27 12:01:16 [INFO] Recupero dei primi 15.000 pacchetti npm dal dataset download-counts...
2026-03-27 12:01:18 [INFO] Watchlist npm caricata: 15.000 pacchetti (download-counts 1.0.52)
2026-03-27 12:01:19 [INFO] [pypi] Avvio serial: 35.542.068 (da last_serial.yaml) — polling ogni 300s
2026-03-27 12:01:19 [INFO] [npm] Avvio seq: 42.817.503 (da last_serial.yaml) — polling ogni 300s
2026-03-27 12:06:18 [INFO] [pypi] Rilevate 2 nuove release nella watchlist (serial 35.542.068 -> 35.542.190)
2026-03-27 12:06:18 [INFO] [pypi] Elaborazione fast-array-utils 1.4 (posizione #8.231)...
2026-03-27 12:06:18 [INFO] [pypi] Confronto fast-array-utils 1.3 -> 1.4
2026-03-27 12:06:50 [INFO] [pypi] Analisi diff per fast-array-utils...
2026-03-27 12:07:35 [INFO] [pypi] Verdetto per fast-array-utils 1.4: BENIGNO
2026-03-27 12:06:20 [INFO] [npm] Rilevata 1 nuova release nella watchlist (seq -> 42.817.612)
2026-03-27 12:06:20 [INFO] [npm] Elaborazione axios 0.30.4 (posizione #42)...
2026-03-27 12:06:21 [INFO] [npm] Confronto axios 0.30.3 -> 0.30.4
2026-03-27 12:07:01 [INFO] [npm] Analisi diff per axios...
2026-03-27 12:07:45 [INFO] [npm] Verdetto per axios 0.30.4: MALEVOLO
Questo progetto è concesso in licenza con Licenza MIT. Le fonti di dati e le note di terze parti sono riassunte in NOTICE.txt.
I contributi sono benvenuti — vedi CONTRIBUTING.md. Questo repository segue il Contributor Covenant. Segnala problemi di sicurezza tramite SECURITY.md, non tramite issue pubbliche.
Domande e discussioni: Slack della comunità Elastic.