Every scanner you run is looking backwards.
A CVE is a record of something already found. By the time one exists, a researcher has spotted the flaw, someone has assigned it an identifier, and a database has published it. That chain takes time. The attacks worth worrying about most don't wait for it.
The uncomfortable part is what the industry's exploitation signals are built on. EPSS scores a CVE. CISA's Known Exploited Vulnerabilities catalogue lists CVEs seen being exploited in the wild. Your prioritisation queue sorts CVEs by severity. It's a decent machine for the problem it was built for, and completely blind to the attack that hasn't been given a number yet. That attack is usually the one moving fastest.
The moment that matters has no identifier
Look at how the supply-chain compromises everyone remembers actually unfolded.
event-stream, 2018. A popular npm package, millions of installs a week, maintained by someone who'd stopped caring about it. A stranger offered to take it over and the maintainer said yes, which was a perfectly ordinary thing to do. The new owner shipped a couple of clean releases, then added a dependency carrying code that targeted one specific bitcoin wallet. No CVE existed at the moment of the handover. The handover was the signal.
ua-parser-js, 2021. The maintainer's npm account was hijacked and three poisoned versions went out inside a few hours, carrying a cryptominer and a password stealer. The CVE came afterwards. Anyone who ran an install against a bad version in that window was hit before the advisory was written.
polyfill.io, 2024. No package, no CVE, nowhere for one to live. The domain serving a script to hundreds of thousands of sites was sold, and the new operator began injecting malware into what it returned. Control changed hands and the payload changed with it. No vulnerability database was ever going to tell you, because the whole event happened outside the model a database describes.
xz-utils, 2024. This one did get a CVE, and it's the most instructive of the lot. A contributor spent close to two years building trust, earning commit rights, and leaning on an exhausted maintainer, before staging a backdoor in the release tarballs. CVE-2024-3094 was assigned only because one engineer noticed his SSH logins had got about half a second slower and went looking. The backdoor took months to build, and the human signals were on display the entire time: a new maintainer taking over a critical library, an original author visibly worn down, and a published tarball that no longer matched the git history. None of that is a vulnerability. All of it was a warning, and it all predated the number by the better part of a year.
The shape repeats. Whatever made each package dangerous happened at the source, in the open, well before anyone recorded it. A scanner keyed on CVEs arrives after the interesting part is over.
What we watch instead
So we watch the source, and score the health of the project rather than the length of its vulnerability list.
In practice that means tracking the things that move before an advisory does. Commit velocity that falls off a cliff, which is what abandonment looks like from the outside. Maintainer churn, and the bus factor underneath it, so a critical library resting on one tired person is something you can see rather than discover. Ownership and control changes, the npm handovers and the domain sales, treated as events in their own right. Release artefacts that drift from the source they claim to be built from.
None of those needs a CVE to fire. Most of them precede one, and some of them, like polyfill.io, describe attacks that would never have produced a CVE at all. We're not trying to predict the future. We're trying to stand where the warning actually appears, at the time it appears, instead of waiting by the database for a number that shows up late or never.
What this isn't
We still ingest the CVE feeds, KEV, OSV, and more than ten others. A known, scored, actively exploited vulnerability in something you ship is a real problem, and you should hear about it fast. This doesn't replace that work. It covers the window that work can't reach, the stretch between a package turning dangerous and the world writing it down.
I'd rather be early and occasionally wrong about a project's health than perfectly precise about a CVE that landed a month too late to matter. The fastest trigger produces no CVE. If that's the trigger you care about, the CVE was never going to be where you found it.
Originally published on the OSPulse blog.
Top comments (0)