
Automatisierter Sicherheitsmonitor für die Lieferkette, der PyPI- und npm-Registries abfragt, neue Versionen mit Vorgängern vergleicht und LLM-Analysen verwendet, um bösartige Codeänderungen mit Slack-Benachrichtigungen zu erkennen.
Automatisierte Überwachung der wichtigsten PyPI- und npm-Pakete auf Kompromittierung der Lieferkette. Fragt beide Registries regelmäßig nach neuen Versionen ab, erstellt Diffs zwischen jeder neuen und der vorherigen Version und verwendet ein LLM (über Cursor Agent CLI), um die Diffs als gutartig oder bösartig zu klassifizieren. Bei bösartigen Funden wird eine Slack-Benachrichtigung ausgelöst.
Standardmäßig werden beide Ökosysteme überwacht. Mit --no-pypi oder --no-npm kann eines deaktiviert werden.
Jedes Ökosystem führt seinen eigenen Polling-Thread, teilt sich aber die Analyse- und Benachrichtigungspipeline.
┌─── 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 │
└───────────────┘
Die LLM-Analyse wird gezielt nach folgenden Mustern durchsucht:
pip install -r requirements.txt (die Standardbibliothek deckt den Großteil des Tools ab; requests wird für Slack-Uploads verwendet)agent-Binary, nicht die IDEWindows (PowerShell):
irm 'https://cursor.com/install?win32=true' | iex
macOS / Linux:
curl https://cursor.com/install -fsS | bash
Überprüfen mit:
agent --version
Sie müssen bei Cursor authentifiziert sein (agent login oder CURSOR_API_KEY setzen).
Platzieren Sie Ihren Slack-Bot-Token in etc/slack.json:
{
"url": "https://hooks.slack.com/services/...",
"bot_token": "xoxb-...",
"channel": "C01XXXXXXXX"
}
Der Bot benötigt die Berechtigung chat:write für den Zielkanal. Das Feld channel ist die Slack-Kanal-ID, in die Benachrichtigungen gesendet werden.
# Einmalige Ausführung: Analysiert Versionen der letzten ~10 Minuten
python monitor.py --once
# Kontinuierlich: Überwacht die Top-1000-Pakete (beide Ökosysteme), alle 5 Minuten abfragen
python monitor.py --top 1000 --interval 300
# Produktion: Überwacht Top 15000, Benachrichtigung an Slack
python monitor.py --top 15000 --interval 300 --slack
# Nur npm, Top 5000
python monitor.py --no-pypi --npm-top 5000
# Nur PyPI
python monitor.py --no-npm
python monitor.py [OPTIONEN]
Optionen:
--top N Anzahl der Top-Pakete pro Ökosystem (Standard: 15000)
--interval SEK Abrufintervall in Sekunden (Standard: 300)
--once Einmaliger Durchlauf über aktuelle Ereignisse, dann Beenden
--slack Slack-Benachrichtigungen für bösartige Funde aktivieren
--model MODEL LLM-Modell überschreiben (Standard: composer-2-fast)
--debug DEBUG-Logging aktivieren (enthält rohe Agent-Ausgabe)
PyPI-Optionen:
--no-pypi PyPI-Überwachung deaktivieren
--serial N Start-Serial für PyPI-Changelog
npm-Optionen:
--no-npm npm-Überwachung deaktivieren
--npm-top N Top-N-npm-Pakete überwachen (Standard: gleicher Wert wie --top)
--npm-seq N Start-Sequenz für npm-Replikation
PyPI und npm laufen jeweils in einem eigenen Polling-Thread. Der Polling-Status (PyPI-Serial, npm-Sequenz + Epoch) wird in last_serial.yaml gespeichert, sodass der Monitor nach einem Neustart dort weitermacht, wo er aufgehört hat.
PyPI-Pipeline:
--interval Sekunden changelog_since_serial() auf – ein einzelner API-Aufruf, der alle Ereignisse seit der letzten Prüfung zurückgibt"new release"-Ereignissen, die der Watchlist entsprechennpm-Pipeline:
replicate.npmjs.com--interval Sekunden den _changes-Feed für alle Registry-Änderungen seit der letzten Sequenz abDie gesamte Ausgabe wird sowohl auf der Konsole als auch in logs/monitor_YYYYMMDD.log protokolliert.
# Zwei Versionen von PyPI vergleichen
python package_diff.py requests 2.31.0 2.32.0
# Zwei Versionen von npm vergleichen
python package_diff.py --npm express 4.18.2 4.19.0
# In Datei speichern
python package_diff.py telnyx 2.0.0 2.1.0 -o telnyx_diff.md
# Lokale Archive vergleichen
python package_diff.py --local old.tar.gz new.tar.gz -n mypackage
Downloads erfolgen direkt über Registry-APIs (PyPI-JSON-API / npm-Registry), nicht über pip oder npm. Das bedeutet:
# Eine Diff-Datei analysieren
python analyze_diff.py telnyx_diff.md
# JSON-Ausgabe
python analyze_diff.py telnyx_diff.md --json
# Ein bestimmtes Modell verwenden
python analyze_diff.py telnyx_diff.md --model claude-4-opus
Führt die Cursor Agent CLI im --mode ask (nur lesen) mit --trust aus. Der Agent liest die Diff-Datei und gibt einen strukturierten Befund zurück.
Exit-Codes: 0 = gutartig, 1 = bösartig, 2 = unbekannt/Fehler.
# Anzeigen, was gerade veröffentlicht wird (letzte ~10 Min.)
python pypi_monitor.py --once --top 15000
# Kontinuierliche Überwachung (nur Konsolenausgabe, keine Analyse)
python pypi_monitor.py --top 1000 --interval 120
Nützlich, um die Veröffentlichungsgeschwindigkeit von PyPI zu erkunden oder die Changelog-API zu debuggen, ohne die vollständige Analyse-Pipeline auszuführen.
# Top-1000-Pakete ausgeben
python top_pypi_packages.py
# Als Bibliothek verwenden
from top_pypi_packages import fetch_top_packages
packages = fetch_top_packages(top_n=500)
# [{"projekt": "boto3", "download_count": 1577565199}, ...]
Der Monitor führt 1 API-Aufruf pro Abfrageintervall pro Ökosystem (PyPI-Changelog / npm _changes) sowie 2-3 Aufrufe pro neuer Version (Versionsverlauf + Downloads) durch. Das ist sehr ressourcenschonend.
Wenn der Monitor eine bösartige Version erkennt, wird eine Nachricht an Slack gesendet:
PyPI:
🚨 Supply Chain Alert: telnyx 4.87.2
Rang: #5.481 der Top-PyPI-Pakete
Befund: BÖSARTIG
PyPI: https://pypi.org/project/telnyx/4.87.2/
Analyse-Zusammenfassung (gekürzt):
Die Änderungen an src/telnyx/_client.py implementieren ein
verschleiertes Download-Entschlüsseln-Ausführen-Verhalten sowie
Seiteneffekte beim Modulimport. Eine _d()-Funktion dekodiert
base64-Zeichenketten, ein massiver _p-Block enthält ein
Exfiltrationsskript, das eine .wav-Datei von
http://83.142.209.203:8080/ringtone.wav herunterlädt und eine
versteckte Nutzlast mittels Steganografie extrahiert...
npm:
🚨 Supply Chain Alert: axios 0.30.4
Rang: #42 der Top-npm-Pakete
Befund: BÖSARTIG
npm: https://www.npmjs.com/package/axios/v/0.30.4
Analyse-Zusammenfassung (gekürzt):
1. **Nicht-standardmäßige Abhängigkeit** – Der `dependencies`-Block enthält `plain-crypto-js`. Veröffentlichtes axios hängt nur von `follow-redirects`, `form-data` und `proxy-from-env` ab. Ein viertes Paket, dessen Name wie ein **`crypto-js`-Typosquat** aussieht, ist ein klassisches Anzeichen für ein manipuliertes oder gefälschtes Paket, nicht für eine normale axios-Version.
agent CLI.ask-Modus, jedoch ohne Betriebssystem-Sandboxing.Logs werden sowohl auf die Standardausgabe als auch in logs/monitor_YYYYMMDD.log geschrieben. Täglich wird eine neue Datei erstellt. Beide Ökosysteme schreiben in dieselbe Datei, wobei npm-Zeilen mit [npm] gekennzeichnet sind. Beispiel:
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
Dieses Projekt ist unter der MIT-Lizenz lizenziert. Zusammenfassungen von Drittanbieter-Datenquellen und Hinweisen finden Sie in NOTICE.txt.
Beiträge sind willkommen – siehe CONTRIBUTING.md. Dieses Repository folgt dem Contributor Covenant. Melden Sie Sicherheitsprobleme über SECURITY.md, nicht über öffentliche Issues.
Fragen und Diskussionen: Elastic Community Slack.
| Datei | Zweck |
|---|
monitor.py | Hauptorchestrator – Abfragen von PyPI + npm, Diff, Analyse, Benachrichtigung (parallele Threads) |
pypi_monitor.py | Eigenständiger PyPI-Changelog-Poller (für Erkundungszwecke) |
package_diff.py | Herunterladen und Vergleichen von zwei Versionen eines beliebigen PyPI- oder npm-Pakets |
analyze_diff.py | Senden eines Diffs an die Cursor Agent CLI, Auswertung des Befundes |
top_pypi_packages.py | Abrufen und Auflisten der Top-N-PyPI-Pakete nach Downloadzahl |
slack.py | Slack-API-Client (SendMessage, PostFile) |
etc/slack.json | Slack-Bot-Anmeldedaten |
last_serial.yaml | Gespeicherter Polling-Status (PyPI-Serial + npm-Sequenz/Epoch) |
logs/ | Tägliche Logdateien (monitor_YYYYMMDD.log) |
| Quelle | Was | Ratenbegrenzungen |
|---|
| hugovk/top-pypi-packages | Top 15.000 PyPI-Pakete nach 30-Tage-Downloads (monatlich als JSON) | Keine (statische Datei) |
PyPI XML-RPC changelog_since_serial() | Echtzeit-PyPI-Ereignis-Firehose | Veraltet, aber funktionsfähig; 1 Aufruf pro Abfrage ist in Ordnung |
| PyPI JSON API | Paket-Metadaten, Versionsverlauf, Download-URLs | Großzügig; sparsam verwendet (1 Aufruf pro Version) |
| download-counts (nice-registry) | Monatliche Downloadzahlen für jedes npm-Paket (counts.json) | Keine (npm-Tarball) |
npm CouchDB-Replikation _changes-Feed | Echtzeit-Änderungsstrom der npm-Registry | Öffentlich; paginierte Lesevorgänge |
| npm Registry API | Paket-Packumente, Tarball-Downloads | Großzügig; sparsam verwendet |