← back to gallery

postinstall-radar

Live leaderboard of npm packages that run code during install, ranked by blast radius

dev-toolsnpmsupply-chainsecuritypostinstallshai-huludslsaleaderboard
Open product ↗

postinstall-radar

Live leaderboard of the top npm packages that execute scripts during npm install — ranked by weekly-download blast radius, with a change feed that fires when a popular package's install-time scripts mutate.

Built after the Mini Shai-Hulud worm (May 11–12, 2026) compromised 172 npm + PyPI packages by smuggling credential-stealing payloads through postinstall hooks. The recurring question on every engineer's Slack — "how many of my deps actually run code during install?" — finally has a public dashboard.

What this is

Sibling products in the Holy AI fleet (complementary, no overlap):

postinstall-radar's lane: the attack surface itself — which popular packages could run arbitrary code on your laptop the next time you npm i, regardless of whether they've been compromised yet.

Stack

| | |
|---|---|
| Runtime | Node.js ≥ 20 (uses global fetch) |
| Web | Express 4 |
| DB | better-sqlite3 (WAL mode) |
| Scheduler| node-cron |
| Security | helmet, compression |
| Logger | morgan |
| Auth | none — every endpoint public, including refresh |
| UI | vanilla JS SPA, dark theme, Chart.js via CDN |

Quick start

cp .env.example .env
npm install
npm start
# open http://localhost:4803/postinstall-radar/

Health check: curl localhost:4803/postinstall-radar/health — should return 200 JSON with db: "ok".

On first boot the database is empty. The server kicks a bootstrap pass through ~30 keyword seeds (1s pacing between seeds), then immediately starts populating install-script metadata for the first ~100 packages. The leaderboard fills in over the next 5–10 minutes.

Data sources (all real, all public, no mocks)

| Source | URL | Refresh |
|---|---|---|
| npm registry search | https://registry.npmjs.org/-/v1/search?text=<seed>&size=250&popularity=1.0 | 1 seed every 12 h (rotating) |
| npm registry package detail | https://registry.npmjs.org/<pkg>/latest | 150 oldest packages every 1 h |
| npm downloads (point) | https://api.npmjs.org/downloads/point/last-week/<pkg> | 200 oldest packages every 6 h |

If a fetch fails: we log it and leave the row alone. A package whose download count is unknown renders as in the UI, not a fabricated number. There is no seed array, no Math.random() jitter, no preset fallback.

Endpoints

| | |
|---|---|
| GET /postinstall-radar/ | SPA |
| GET /postinstall-radar/health | smoke check (200) |
| GET /postinstall-radar/api/leaderboard | limit, sort=risk\|downloads\|recent, min_downloads |
| GET /postinstall-radar/api/stats | totals + per-hook breakdown |
| GET /postinstall-radar/api/package/:name | full row + last 20 change events |
| GET /postinstall-radar/api/changes | recent install-script change feed |
| POST /postinstall-radar/api/check | body: {names:[...]} or {packageJson:"..."} |
| GET /postinstall-radar/api/feed.json | JSON Feed 1.1 of recent changes |
| GET /postinstall-radar/api/refresh-log | cron pipeline visibility |
| POST /postinstall-radar/api/refresh-now | kick a single batch (rate-limited only by inflight guard) |

/api/check is rate-limited to ~30 req/min/IP via an in-memory token bucket. No auth though — Arda wants to open the page and just use it.

How risk_score is computed

risk_score = log10(max(weekly_downloads, 1)) × hook_count

Deterministic. A package with 10 M weekly downloads and a single postinstall (e.g. esbuild) gets 7 × 1 = 7.00. A package with 50 k weekly downloads and three hooks gets 4.7 × 3 ≈ 14.1 — making the dashboard surface "small-but-noisy" packages that quietly run more than one script. No randomness, no machine learning, no opinion.

What this does NOT do

Deployment

DEPLOY_MANIFEST.json follows the RNDLAB orchestrator schema. The Mac watcher under ~/development/RNDLAB/rndlab-core/ picks up queue.jsonl entries every 30 s, rsyncs the directory to /var/www/projects/postinstall-radar, registers a systemd unit, wires up the nginx route, smoke-checks /health, and posts to the showcase.

No vault secrets to inject — the npm registry is fully unauthenticated.

License

MIT.