Yes, the npm ecosystem is at fault
Posted on Tue 27 November 2018 in Programming • Tagged with npm, Javascript, open source, package manager, security • Leave a comment
Even if you are like me and don’t use any (server-side) Javascript, or node.js, or npm, it may feel like every other week there are news about yet another npm snafu.
The latest incident could be the most severe one yet, at least from the security standpoint. In a nutshell, the owner of event-stream — a popular package even by npm standards — had transferred ownership of it to another person. The new owner would then publish a new version of the package which contained a targeted backdoor, intended to steal large amounts of Bitcoin from the users of one particular wallet provider.
Quite a step up from the left-pad fiasco, isn’t it?…
Like it usually happens with any major incident, lots of people are eager to put the blame on someone, or something, as quickly as possible. Rather unsurprisingly, the original owner of event-stream came up as a pretty obvious target. Without his abdication of ownership rights, the argument goes, the entire ordeal wouldn’t have happened in the first place. More broadly, as a maintainer of a popular package, he owes it to the community to make sure it remains available and safe to use, now and for the foreseeable future.
But if those are the responsibilities, then what are the rewards?… Well, in the author’s own words, “you get literally nothing from maintaing a popular package”. Looks like once the fun of it wears off, it’s just all work and no play, for little to no tangible benefit.
This problem is of course not specific to Javascript or npm. Here’s, for example, a good take on the issue from the creator of Clojure.
However, this doesn’t mean every other package manager is equally susceptible to the sort of issues that have shaken npm time and time again. To say the same thing could’ve happened to Python/Ruby/Go/Haskell/etc. is vacuous. While factually true, it’s an instance of the Fallacy of Grey: a claim that because nothing is ideal, everything must be equally flawed.
In reality, the Javascript ecosystem facilitated by npm is singularly vulnerable to problems of this kind. It follows directly from how granular the npm packages are, and how wide and deep their dependency trees get.
Indeed, it would be quite a fascinating exercise to quantify the difference numerically, by comparing the average size of a dependency graph between npm, PyPI, Rubygems, Hoogle, and so on. It’s rather obvious npm would come as a “winner”, likely with Rust’s Cargo not very far behind.
Apparently, this not unintentional either — the node.js community seems to like it this way. But as the yesterday’s incident has exposed, this state of affairs relies on the distributed conscientiousness of very many parties — in this case, npm package authors. When one inevitably falters, the impact reaches far and wide, rippling through the massively intertwined npm registry.
While it may be satisfying, then, to blame the package owner as the immediate culprit, it’s way more productive to consider how the damage could have been mitigated.
We can, for example, look at the unimaginably dense dependency graph of npm — if anyone ever dared to visualize it in its entirety — and realize it shouldn’t really have so many edges. Had it been little sparser, more similar to the graphs of PyPI or Ruby, then removing (i.e. compromising) a single leaf node would’ve had proportionally smaller impact.
So yes, it’s true that all package managers are exposed to the risk of compromised packages. It is, however, something that can be estimated and compared — and unfortunately, it is clear that for npm, this risk is currently the largest.
Continue reading