A cache that only stores packages is a faster way to get compromised. Celilo’s
npm-cache-node will do more than mirror npmjs.com — it will watch what it has
served. A background daemon walks the cache against known-bad lists on a
schedule, and when it finds a match it doesn’t just log it: it pulls the poison
out of circulation and tells you. Hosting your own registry only earns its
keep if it’s also watching your back.
Scanning what you’ve already trusted
The scanner runs on a timer — every few hours — and matches every cached
package@version against public advisory feeds, starting with the GitHub
Advisory Database. Because the cache records exactly which versions it has
served, the scan covers your real supply chain, not a hypothetical one. A
package that looked clean the day you installed it gets re-examined as new
advisories land.
Quarantine, loudly
When a cached tarball matches a known compromise, the node atomically moves it
into a .quarantine/ directory. The next request for that exact version fails
loud instead of silently serving poison — and, critically, it does not fall
through to a fresh upstream fetch that would just re-download the bad bytes. A
compromise you’ve already pulled becomes a hard stop, not a shrug.
You find out immediately
Every quarantine emits an npm.cache.quarantine.<package>@<version> event on
the Celilo bus and pushes a notification through whatever channel you’ve wired
up. The point isn’t only to block the bad package — it’s to make sure you know a
compromise reached your lab, so you can go see what depended on it. A
higher-trust future adds an optional LLM pass to flag typosquats and suspicious
version diffs before any advisory names them.