The npm ecosystem is fundamentally insecure. Some highlights:
* I obtained accounts of 4 users from the top-20 list.
* One of those 4 users set their password back to the leaked one shortly after it was reset.
* 13 users [that I found the password for] had more than 50 million downloads/month.
* One of the users directly controlling more than 20 million downloads/month chose to improve their previously revoked leaked password by adding a ! to it at the end.
* While Skovoroda discovered credentials that granted him direct publish access to only 13% of npm packages, through dependencies, an attacker would have been able to spread his malicious code to about 52% of the entire npm ecosystem.
That seems less of an indictment of npm and more an indictment of JS developers not caring about or understanding basic information security principles.
The npm community has a longstanding habit of depending on dynamic version numbers, eg "^1.2.3". Until the recent advent of package-lock.json, normal builds would pull in "whatever was latest"; any compromised upstream dependency would automatically propagate downstream as fast as their CI systems run. Also, builds are pretty much irreproducible.
The maven world, by contrast, is habituated to fixed version numbers for dependencies. A fake release might affect folks downstream that explicitly choose the upgrade, but it won't be automatic.
package-lock.json helps solve the technical problem, but the JS community still has a cultural problem because JS packages are typically fine-grained, released frequently, and upgraded without much thought.
package-lock.json doesn't do anything for security unless you're going to walk the upgrades of each transitive dependency before you run `npm upgrade` (since each dependency can run arbitrary code while installing). So I wouldn't say it solves any of the security issues, just gives you a commitable snapshot of your deps.
One of the many things the npmjs.com website needs to do is provide a code viewer for each version of a package. It's a bit annoying that you have to unpack a tarball just to see the code you're going to be running if you install it. Right now everyone just takes for granted that if a NPM package links to a Github repo, that that's the code you're going to be executing.
Nothing is going to solve the explosion of transitive deps though without some sort of cultural change. I don't see that ever happening. I do like the ecosystem of tiny libraries but it's too large of a trade-off for security sensitive applications imo.
> package-lock.json helps solve the technical problem, but the JS community still has a cultural problem because JS packages are typically fine-grained, released frequently, and upgraded without much thought.
Just the other day I caught myself feeling frustrated that I had to manually add a dependency + version number in my mix.exs (Elixir package manager), just because I got so used to doing 'yarn add <package>'.
And that's despite the fact that I for quite a while now I have also been feeling a bit weird about just adding packages to my project for the exact reason discussed here (as well as the 'leftpad' fiasco).
It's both fascinating and a bit scary how easy I just do things 'the way everyone does' despite knowing better, and I hope we'll find some solution that could be applied community- or ecosystem-wide.
What makes this a problem is that the NPM ecosystem has so many transitive dependencies. Which is why a left-pad fiasco can even happen in the first place.
maybe there should be some type of 2 factor authorization to make sure you can't get in by guessing someone's insecure password, or grabbing it from a leak (due to password reuse).
Requiring it would be wise, or at least requiring it if any other packages depend on it. They're going to destroy the ecosystem if they can't secure it. One major blow and nobody will trust it anymore.
What do you expect? The userbase requires stuff like isinteger and left-pad as packages, I don't think they are capable of understanding basic security concepts.
On another note, NPM is rooting for companies instead of users as has been observed by the leftpad debacle.
It's amazing that Node.js comes with a package manager that is not fully open source and is entirely controlled by a private corporation
NPM has some serious issues and unlike node itself we can't fix them because we don't have access to all of the source code.
Npm decided to auto close most of issues raised by its users in Github without addressing them. Many of those bugs still exist, even in the latest version.
It's a shame that the community of all those awesome package maintainers is being monetized by a corporation that is mostly dysfunctional and incompetent.
The problem with measures such as 2FA is that they are voluntarily implemented only by users who are most concerned about security, whereas users setting their password to "password" are on the opposite end of the spectrum.
What we really need is (1) 2FA and other enhanced security measures and (2) the ability to exclude all packages from a project, whether imported directly or indirectly, that do not abide with a minimum level of security.
I like the direction you’re heading with this, as it touches on supply-chain issues that have most folks just throwing their hands up. What would be most interesting is a standard framework for expressing a security policy combined with some hooks in the build tooling.
I also wonder whether it would be appropriate for the repositories themselves to hold maintainers to a minimum standard as well as their own claims. E.g., package maintainers must set a >12 character password and employ 2fa.
In reality, this isn’t just an NPM issue. I suspect that similar issues plague just about every package management framework, App Store, or CDN out there. Having a couple of standardized approaches would enable developers who care to automate checks and start to generate new incentives for the folks that are publishing their work to follow some basic standards.
This is exactly what is needed. Publish on each user's profile whether their account is secure, and provide an option in the client to disallow upgrading package versions owned by users that don't comply.
You could even try to crack the password of any user with enough (by some threshold) downloads using known leaked passwords as seeds, and mark them as insecure and reset their password if successful.
You're talking about actions that security-minded parties could take already, if they cared to do so. Run your own registry, and audit everything that goes in, before it goes in. That would be a lot of work, but it would actually affect security to some degree. This idea that packages will be safe if only we inconvenience all package authors enough is just silly.
I'm curious what the percentage of npm publishers that have this toggled on is, and I wish that was available data. First, in terms of all packages, and then of top 1000 packages. I'll wildly guess <0.5% of all packages, and <1% of top 1000. You don't get 2FA without the beta client right now anyway.
It's of no surprise to anyone that follows Node.js security at this stage that the third party dependency chain is really its biggest weak link. Jordan Wright did some good research a couple of months ago on Node dependency trees and malicious packages that's worth a read:
> I'm curious what the percentage of npm publishers that have this toggled on is, and I wish that was available data.
I know we're tracking this data and I bet a follow up post will be written at some point once some numbers are available. As you say, I expect 2fa will see wide adoption as soon as a stable version lands in the upstream Node.
Just wait till everything runs in a web browser. But by then you'll be able to convert your Rust program to web assembly to draw UIs on the canvas for VR apps.
For those of us building anything that processes information with any level of sensitivity, it's not so funny. It's almost impossible to verify the integrity of JS dependencies.
I've had to adopt a policy of ignoring anything but the most carefully curated and dependency-minimised JS packages, and to avoid the language in general except when it can't be generally circumvented (i.e. in the browser).
And people think I'm crazy for keeping track of dependencies via SCM. Many packages now a day is compile to JS, eg they have 100,000 build dependencies, but all you need is actually just two or thee files, the rest can be deleted.
* I obtained accounts of 4 users from the top-20 list.
* One of those 4 users set their password back to the leaked one shortly after it was reset.
* 13 users [that I found the password for] had more than 50 million downloads/month.
* One of the users directly controlling more than 20 million downloads/month chose to improve their previously revoked leaked password by adding a ! to it at the end.
* While Skovoroda discovered credentials that granted him direct publish access to only 13% of npm packages, through dependencies, an attacker would have been able to spread his malicious code to about 52% of the entire npm ecosystem.
There is no bandaid to fix this structural issue.