Weekend at Bernie's

zbentley1 pts0 comments

Weekend at Bernie’s | Andrew Nesbitt

In the 1989 film, two junior employees turn up at their boss’s beach house to find him dead, and spend the rest of the weekend wheeling him around the party with sunglasses on so nobody notices. The other guests keep slapping him on the back and putting drinks in his hand. It works because nobody looks too closely and because everyone has a strong incentive for Bernie to still be alive.

I have spent the last couple of weeks trying to work out how many of the open source packages we all depend on are in roughly that condition: resolving in every install, pulling millions of downloads a week, accepting new issues, with nobody behind the sunglasses. I’m asking now rather than a few years ago because AI-assisted vulnerability discovery is changing how often somebody actually checks for a pulse.

This matters most at the point where one of those packages gets a security report. Sometimes nobody responds at all, the embargo expires, and a CVE is published with no fixed version to point at. Sometimes a fix does get written, often by the reporter or a drive-by contributor, and it lands in git or sits in an open PR, but the one account with publish rights on the registry has gone and the patched code never reaches anyone’s install command.

Linux distributions deal with that second case routinely because distro packagers have always carried patches without waiting for upstream, but language package managers have no equivalent role. The registry namespace belongs to whoever registered it, and if they’re gone there is nobody standing between you and the unpatched tarball. There are per-application workarounds, which I went through in some detail last week, but they put the work on every downstream consumer individually rather than fixing the published artifact once.

There’s also a quieter way an unmaintained package causes problems that doesn’t need a vulnerability in the package itself. If it declares a tight version range on one of its own dependencies, and that dependency is actively maintained and ships a security release in a new major version, the resolver can’t reach the fix because the dead package’s constraint won’t allow it. Everything downstream gets held on the vulnerable version by a single line in a manifest that nobody is around to edit, which is more or less the situation byroot describes hitting with openssl in Bundler.

What counts as dead

The naive way to do this is to look at the last commit date, call anything over two years old “abandoned”, and publish a scary number. I didn’t want to do that, because a package with no commits since 2019 isn’t necessarily dead. A lot of the most depended-on packages in any ecosystem are forty lines long, finished, and don’t need commits. The thing I actually want to know is whether anyone would answer if you knocked, and the commit log on its own doesn’t tell you that.

So I started from the ecosyste.ms critical package set, which is the top packages per registry by a blend of downloads and dependent repos, across sixteen package managers. That gave me 8,606 packages backed by 5,874 distinct repositories. For each repo I pulled a year of commit activity, a year of issue and PR activity, who closed or merged anything, who has publish rights on the registry, the date of the last release, and any security advisories filed against the package. Then I sorted them into four buckets.

Active : regular non-bot commits to the default branch, or a release, in the past year.

Dormant : little or no development, but someone with write access has closed an issue, merged a PR, or pushed a commit in the past year, so a fix could plausibly land.

Dead : the repo is archived, or issues/PRs were filed in the past year and nobody with write access closed, merged, committed or released anything in response.

Unknown : no issues or PRs filed and no activity, so responsiveness hasn’t been tested.

Dead requires evidence of non-response rather than just inactivity, because I’d rather undercount than put a package on a list whose author happened to take a year off.

The numbers

Of those 5,874 critical repos, 48.8% are active, 20.2% are dormant, 12.1% are dead, and 18.9% are unknown. So just under half are unambiguously maintained. Twelve percent confirmed dead doesn’t sound enormous, but those 713 repositories back packages whose dependent-repo counts sum to about 290 million (these are edges in the dependency graph, not deduplicated repositories), and adding the dormant and unknown buckets takes that sum well past a billion.

Broken down by ecosystem the dead share wobbles a bit, but it’s in double figures almost everywhere I have enough repos to say anything:

ecosystem<br>repos<br>active<br>dormant<br>dead<br>unknown<br>dead...

dead package nobody because packages year

Related Articles