But in the Maven/Gradle ecosystem, most projects pin exact dependency versions. Support for version ranges and dynamic versions exist, but they are generally avoided because they hurt reproducible builds. That means a malicious new release does not automatically flow into most consumers’ builds just because it was published.
I'd go as far to say that NPM should:
1. Enforce scope (namespace) requirement, and require external verification (reverse DNS for example).
2. Disable version range support out of the box. User must --enable this setting from the command line at all times.
3. Remove support for install scripts completely. If someone wants to publish a ready-to-run software, there are plenty of other mechanisms.
Who the heck says everyone who publishes a library has a domain? That seems absurd.
Don't count other people money.
A small bar of $20/year is also enough to completely cut-down on contributors who sign up with the intention of publishing malicious packages: they have to pay $20/year for each malicious package they want to publish!
Heck domain names are ephemeral, forget a deadline by a day and they are snatched up my squatters. They don't provide any extra guarantees. Do we really think a domain requirement is going to stop state level actors that are already stealing 2FA package publishing tokens from major software orgs?
Is that your target? Because if so, then nothing will stop them.
Requiring domain name verification is not going to do anything when 2FA tokens are being stolen.
What it will do is prevent students and people who want to stay anonymous from contributing to open source.
This exists because domains (historically) used to be expensive by western standards. .com used to be $75/year back in the day.
This directly influences how well e.g. version pinning works. In the Java world, package versions are _relatively_ independent from eachother and have few transitive dependencies, and as such version conflicts are relatively rare. This means you can get away with full pinning of all dependencies, with the occasional manual override of a conflicting transitive dependency.
This doesn't work in JavaScript. The dependency ecosystem is massively intertwined, if every library would specify exact versions you'd end up with literally hundreds of conflicts to resolve. That's not feasible. As a result, they've chosen the middle ground of using lock files in addition to version ranges.
This also hurts the effectiveness of verified namespaces: when packages come from hundreds of different sources, you're not going to notice 1 or 2 sketchy ones in there.
Other consequences of the big monolithic packages in Java are that updates tend to be less frequent, and more often from large reputable venders. Both of these help to reduce the problem too.
While the JavaScript toolchain can definitely learn a lot from the Java toolchains, the problems it needs to solve are not the same, and thus solutions don't translate 1-1.
At least I hope that they'll get rid of install scripts, that's such a low hanging fruit that really should've be done a decade ago.
How will that help? It's just going to break things that legitimately require them.
Instead of being infected upon running "npm install", you'll just get infected upon running "npm run" instead. The former is slightly more reliable but fixing that is just kicking the can down the road. Maybe we'll have a few days before the payloads get rewritten.