I’ve wondered why Npm seems to have so many security fires compared to e.g. the Python package system. They shouldn’t be that different. Anyway, there are reasons: https://blog.acolyer.org/2019/09/30/small-world-with-high-risks/
I’m amused that new Pip is basically adopting the lockfile from Npm, for exactly the same reason: nailing down transitive dependency versions. If package A wants package B, and B doesn’t specify exactly what its dependencies are, then installing package A at various times will have unpredictable results.
As a developer you use package A, and specify its exact version. You create lots of awesome code and tests, and everything is wonderful. Then you send your code to CI… The CI system of course rebuilds everything from scratch. It installs package A, and dependent package B. Package B has been updated since the time you installed it. On your local machine, you use the old version of B because it matches your dependency specification, and it’s already there. For CI, or for another developer, you’ll get a newer and different version of package B, which might break things!