
Monitor automatizado de segurança da cadeia de suprimentos que consulta os registros PyPI e npm, compara novas versões com as anteriores e utiliza análise de LLM para detectar alterações maliciosas de código, com alertas no Slack.
Monitoramento automatizado dos principais pacotes PyPI e npm para comprometimento da cadeia de suprimentos. Consulta ambos os registros em busca de novos lançamentos, faz diff de cada lançamento em relação ao seu predecessor e usa um LLM (via Cursor Agent CLI) para classificar os diffs como benignos ou maliciosos. Descobertas maliciosas disparam um alerta no Slack.
Ambos ecossistemas são monitorados por padrão. Use --no-pypi ou --no-npm para desabilitar um.
Cada ecossistema executa sua própria thread de consulta, mas compartilha o pipeline de análise e alerta.
┌─── 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 │
└───────────────┘
A análise do LLM é instruída a procurar por:
pip install -r requirements.txt (a stdlib cobre a maior parte da ferramenta; requests é usado para uploads no Slack)agent, não o IDEWindows (PowerShell):
irm 'https://cursor.com/install?win32=true' | iex
macOS / Linux:
curl https://cursor.com/install -fsS | bash
Verifique com:
agent --version
Você deve estar autenticado com o Cursor (agent login ou definir CURSOR_API_KEY).
Coloque seu token do bot do Slack em etc/slack.json:
{
"url": "https://hooks.slack.com/services/...",
"bot_token": "xoxb-...",
"channel": "C01XXXXXXXX"
}
O bot precisa do escopo chat:write no canal de destino. O campo channel é o ID do canal do Slack onde os alertas são postados.
# Única execução: analisa lançamentos dos últimos ~10 minutos
python monitor.py --once
# Contínuo: monitora os 1000 principais pacotes (ambos ecossistemas), consulta a cada 5 minutos
python monitor.py --top 1000 --interval 300
# Produção: monitora os 15000 principais, alerta para o Slack
python monitor.py --top 15000 --interval 300 --slack
# Apenas npm, top 5000
python monitor.py --no-pypi --npm-top 5000
# Apenas PyPI
python monitor.py --no-npm
| Arquivo | Finalidade |
|---|---|
monitor.py | Orquestrador principal — consulta PyPI + npm, diff, analisa, alerta (threads paralelas) |
pypi_monitor.py | Consultor PyPI autônomo (usado para exploração) |
package_diff.py | Baixa e compara duas versões de qualquer pacote PyPI ou npm |
analyze_diff.py | Envia um diff para o Cursor Agent CLI, analisa veredito |
top_pypi_packages.py | Busca e lista os N principais pacotes PyPI por contagem de downloads |
slack.py | Cliente da API do Slack (SendMessage, PostFile) |
etc/slack.json | Credenciais do bot do Slack |
last_serial.yaml | Estado de consulta persistido (serial PyPI + sequência/época npm) |
logs/ | Arquivos de log diários (monitor_YYYYMMDD.log) |
python monitor.py [OPÇÕES]
Opções:
--top N Número de pacotes principais a observar por ecossistema (padrão: 15000)
--interval SECS Intervalo de consulta em segundos (padrão: 300)
--once Única passagem sobre eventos recentes, depois sai
--slack Habilita alertas do Slack para descobertas maliciosas
--model MODEL Substitui o modelo LLM (padrão: composer-2-fast)
--debug Habilita log DEBUG (inclui saída bruta do agent)
Opções PyPI:
--no-pypi Desabilita monitoramento PyPI
--serial N Serial do changelog PyPI para iniciar
Opções npm:
--no-npm Desabilita monitoramento npm
--npm-top N Top N pacotes npm a observar (padrão: igual a --top)
--npm-seq N Sequência de replicação npm para iniciar
PyPI e npm cada um executa em sua própria thread de consulta. O estado da consulta (serial PyPI, sequência + época npm) é persistido em last_serial.yaml para que o monitor retome de onde parou após uma reinicialização.
Pipeline PyPI:
--interval segundos, chama changelog_since_serial() — uma única chamada de API que retorna todos os eventos desde a última verificação"new release" que correspondem à lista de observaçãoPipeline npm:
replicate.npmjs.com--interval segundos, busca o feed _changes para todas as alterações do registro desde a última sequênciaToda saída é registrada tanto no console quanto em logs/monitor_YYYYMMDD.log.
# Compare duas versões do PyPI
python package_diff.py requests 2.31.0 2.32.0
# Compare duas versões do npm
python package_diff.py --npm express 4.18.2 4.19.0
# Salve em arquivo
python package_diff.py telnyx 2.0.0 2.1.0 -o telnyx_diff.md
# Compare arquivos locais
python package_diff.py --local old.tar.gz new.tar.gz -n mypackage
Os downloads são feitos diretamente via APIs de registro (PyPI JSON API / npm registry), não via pip ou npm. Isso significa:
# Analise um arquivo diff
python analyze_diff.py telnyx_diff.md
# Saída JSON
python analyze_diff.py telnyx_diff.md --json
# Use um modelo específico
python analyze_diff.py telnyx_diff.md --model claude-4-opus
Executa o Cursor Agent CLI em --mode ask (somente leitura) com --trust. O agente lê o arquivo diff e retorna um veredito estruturado.
Códigos de saída: 0 = benigno, 1 = malicioso, 2 = desconhecido/erro.
# Veja o que está sendo lançado agora (últimos ~10 min)
python pypi_monitor.py --once --top 15000
# Monitoramento contínuo (apenas saída no console, sem análise)
python pypi_monitor.py --top 1000 --interval 120
Útil para explorar a velocidade de lançamento do PyPI ou depurar a API de changelog sem executar todo o pipeline de análise.
# Exiba os 1000 principais pacotes
python top_pypi_packages.py
# Use como biblioteca
from top_pypi_packages import fetch_top_packages
packages = fetch_top_packages(top_n=500)
# [{"project": "boto3", "download_count": 1577565199}, ...]
| Fonte | O que | Limites de Taxa |
|---|---|---|
| hugovk/top-pypi-packages | Top 15.000 pacotes PyPI por downloads em 30 dias (JSON mensal) | Nenhum (arquivo estático) |
PyPI XML-RPC changelog_since_serial() | Fluxo de eventos PyPI em tempo real | Depreciado mas funcional; 1 chamada por consulta é suficiente |
| PyPI JSON API | Metadados do pacote, histórico de versões, URLs de download | Generoso; usado com moderação (1 chamada por lançamento) |
| download-counts (nice-registry) | Contagens mensais de download para cada pacote npm (counts.json) | Nenhum (tarball npm) |
npm CouchDB replication _changes feed | Fluxo de alterações do registro npm em tempo real | Público; leituras paginadas |
| npm registry API | Documentação do pacote, downloads de tarballs | Generoso; usado com moderação |
O monitor faz 1 chamada de API por intervalo de consulta por ecossistema (changelog PyPI / npm _changes), além de 2-3 chamadas por novo lançamento (histórico de versões + downloads). Isso é muito leve.
Quando o monitor detecta um lançamento malicioso, ele publica no Slack:
PyPI:
🚨 Alerta de Cadeia de Suprimentos: telnyx 4.87.2
Rank: #5,481 dos principais pacotes PyPI
Veredito: MALICIOSO
PyPI: https://pypi.org/project/telnyx/4.87.2/
Resumo da análise (truncado):
As alterações em src/telnyx/_client.py implementam comportamento
de download-descriptografar-executar ofuscado e efeitos colaterais
de importação de módulos. Uma função _d() decodifica strings base64,
um enorme blob _p contém um script de exfiltração que baixa um
arquivo .wav de http://83.142.209.203:8080/ringtone.wav e extrai
um payload oculto via esteganografia...
npm:
🚨 Alerta de Cadeia de Suprimentos: axios 0.30.4
Rank: #42 dos principais pacotes npm
Veredito: MALICIOSO
npm: https://www.npmjs.com/package/axios/v/0.30.4
Resumo da análise (truncado):
1. **Dependência não padrão** — O bloco `dependencies` inclui `plain-crypto-js`. O axios publicado depende apenas de `follow-redirects`, `form-data` e `proxy-from-env`. Um quarto pacote cujo nome parece um **typosquat ao estilo `crypto-js`** é um sinal clássico de um pacote adulterado ou falso, não de um lançamento normal do axios.
agent autenticado.ask, mas sem isolamento a nível de SO.Os logs são escritos tanto no stdout quanto em logs/monitor_YYYYMMDD.log. Um novo arquivo é criado a cada dia. Ambos ecossistemas registram no mesmo arquivo, com linhas npm prefixadas por [npm]. Exemplo:
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 projeto está licenciado sob a Licença MIT. Fontes de dados de terceiros e avisos estão resumidos em NOTICE.txt.
Contribuições são bem-vindas — veja CONTRIBUTING.md. Este repositório segue o Contributor Covenant. Relate problemas de segurança através de SECURITY.md, não por issues públicas.
Perguntas e discussões: Slack da comunidade Elastic.