When I start a project I get whatever `npm install` returns. I freeze it. And then I only change it if one of a few things happens:<p>1. npm warns me of security issues<p>2. A new feature exists that I need<p>3. I've profiled and am seeking performance improvements<p>I used to just push everything forward on a regular basis in fear that I'd fall too far behind but I stopped doing that at some point and discovered that it doesn't really manifest as a problem. Chasing bugs and features usually keeps relevant packages current. Also the discipline not to depend on too many top-level dependencies.
None of this solves the referenced social engineering attack, except possibly "run everything in containers".<p>> <i>Run everything in containers</i><p>This only works if you can split up your app into micro-services that can be adequately sandboxed, and even then only if the malicious dependency is in a locked-down service. But for example if your service needs to be able to make outgoing network requests to arbitrary hosts then you can't prevent a malicious dependency from sending your private data to its own server.<p>> <i>Don't install anything that is less than 7/14/X days old</i><p>If everyone followed this advice, then the advice won't change anything. This advice only helps you if other people ignore it, at which it's just "let the suckers try the new versions first". And even then it won't solve the referenced social engineering attack, because that attack was targeting one specific user, and it doesn't matter how many other users test the dependency.<p>> <i>Sign all packages published with a private key</i> and <i>Complain if the package you dependent on have changed signing key</i><p>This doesn't help either. The malicious package was published by an authorized maintainer of the project. Presumably if the package was signed with a private key, that private key would have been given to the maintainer to use in deploying (or alternatively the maintainer would have simply asked the original author to deploy the new version).<p>> <i>Install only packages from authors you have marked as trusted</i><p>The malicious package was published under the name of a trusted author already.<p>> <i>Only install packages that have been signed by 2/3/X other people</i><p>This isn't particularly scalable. It's hard enough as it is to get other people to even review the source of your open source library; asking them to stake their reputation on signing it too would be an even higher bar. Very few packages would end up cross-signed like this.
I've been burned twice in the last month from patch upgrades to packages. (And yes, I do lock my dependencies.)<p>The first time was upgrading pstree.remy from 1.1.0 to 1.1.2 to remove the malicious flatmap-stream. Totally incompatible upgrade. Nodemon would just crash, every single time.<p>The second was in an infrequent general update including a an upgrade of url-polyfill from 1.0.13 to 1.0.14. It changed new URL('<a href="https://example.com'" rel="nofollow">https://example.com'</a>).host from 'example.com' to incorrect 'example.com:443'. This was used by angular-jwt for whitelisting URLs to send auth creds to, and wound up breaking access for all polyfilled browsers (i.e. just IE) in environments that used the HTTPS's default port (i.e. just production).<p>Somehow the npm ecosystem has (1) the package manager that most slavishly adheres to semver, while (2) having the community that least closely follows it.
There are two obvious errors here.<p>1) We didn’t discover the hack for over 60 days. Recommending 7/14/X does not address this. What X is sufficient to ensure the community inspects new code? X=60 didn’t cut it.<p>2) Private signing keys are only private from us, the general public, not necessarily from maintainers, and may be sold and transferred with ease. If I were buying a codebase, I’d require the signing private keys for continuity reasons alone. (CAB EV rules permit this!)
This is great! With some small automation for maintainers, we could help with the "Don't install anything that is less than 7/14/X days old" by just pinning dependencies and regularly publishing updates just for dependency tree updates.<p>For most projects the dep tree is small, and this level of maintenance is low. People always hate on me for saying it, but I think this level of effort would be worth it to protect the users of my modules.
I think NPM should store packages in predicable paths and not move them around. That way you can have your dependencies in source control and review all dependency updates. This worked great for me before npm started doing tree shaking. You can lock down the packages to semver minor and you will only get minor updates. Detecting something like an encrypted blob is pretty easy when you review a commit.
> Publishing doesn't need to be centralized like many publishing platforms are that seeks to keep users safe like the App Store.<p>Even the App Store doesn’t necessarily keep you safe; it’s pretty decent most of the time but malicious software sometimes slips through.
Another obvious one: Support your OSS developers<p>Many OSS devs have to handle several projects AND a job/freelancing at the same time. More money, less work for others, more time for OSS.
I'd like to see your trusted module notion fleshed out.<p>Especially with respect to self-hosted repos, eg Artifactory. Enabling a hierarchical system of trust.