Remix.run Logo
diegof79 6 days ago

Transitive dependencies are the main issue.

Suppose you have a package P1 with version 1.0.0 that depends on D1 with version ^1.0.0. The “^” indicates a range query. Without going into semver details, it helps update D1 automatically for minor patches or non-breaking feature additions.

In your project, everything looks fine as P1 is pinned to 1.0.0. Then, you install P2 that also uses D1. A new patch version of D1 (1.0.1) was released. The package manager automatically upgrades to 1.0.1 because it matches the expression ^1.0.0, as specified by P1 and P2 authors.

This can lead to surprises. JS package managers use lock files to prevent changes during installs. However, they still change the lock file for additions or manual version upgrades, resolving to newer minor dependencies if the version range matches. This is often desirable for bug fixes and security updates. But, it opens the door to this type of attack.

To answer your question, yes, the JS ecosystem moves faster, and pkg managers make it easy to create small libraries. This results in many “small” libraries as transitive dependencies. Rewriting these libraries with your own code works for simple cases like left-pad, but you can’t rewrite a webserver or a build tool that also has many small transitive dependencies. For example, the chalk library is used by many CLI tools to show color output.