←back to thread

1208 points jamesberthoty | 10 comments | | HN request time: 0.001s | source | bottom
Show context
codemonkey-zeta ◴[] No.45261026[source]
I'm coming to the unfortunate realizattion that supply chain attacks like this are simply baked into the modern JavaScript ecosystem. Vendoring can mitigate your immediate exposure, but does not solve this problem.

These attacks may just be the final push I needed to take server rendering (without js) more seriously. The HTMX folks convinced me that I can get REALLY far without any JavaScript, and my apps will probably be faster and less janky anyway.

replies(18): >>45261086 #>>45261121 #>>45261140 #>>45261165 #>>45261220 #>>45261265 #>>45261285 #>>45261457 #>>45261571 #>>45261702 #>>45261970 #>>45262601 #>>45262619 #>>45262851 #>>45267210 #>>45268405 #>>45269073 #>>45273081 #
lucideer ◴[] No.45261265[source]
> I'm coming to the unfortunate realizattion that supply chain attacks like this are simply baked into the modern JavaScript ecosystem.

I see this odd take a lot - the automatic narrowing of the scope of an attack to the single ecosystem it occurred in most recently, without any real technical argument for doing so.

What's especially concerning is I see this take in the security industry: mitigations put in place to target e.g. NPM, but are then completely absent for PyPi or Crates. It's bizarre not only because it leaves those ecosystems wide open, but also because the mitigation measures would be very similar (so it would be a minimal amount of additional effort for a large benefit).

replies(7): >>45261389 #>>45261408 #>>45261464 #>>45262010 #>>45263376 #>>45266913 #>>45270888 #
simiones ◴[] No.45263376[source]
Most people have addressed the package registry side of NPM.

But NPM has a much, much bigger problem on the client side, that makes many of these mitigations almost moot. And that is that `npm install` will upgrade every single package you depend on to its latest version that matches your declared dependency, and in JS land almost everyone uses lax dependency declarations.

So, an attacker who simply publishes a new patch version of a package they have gained access to will likely poison a good chunk of all of the users of that package in a relatively short amount of time. Even if the projects using this are careful and use `npm ci` instead of `npm install` for their CI builds, it will still easily get developers to download and run the malicious new version.

Most other ecosystems don't have this unsafe-by-default behavior, so deploying a new malicious version of a previously safe package is not such a major risk as it is in NPM.

replies(2): >>45263567 #>>45263619 #
1. Tadpole9181 ◴[] No.45263619{3}[source]
`npm install` uses a lockfile by default and will not change versions. No, not transitives either. You would have to either manually change `package.json` or call `npm update`.

You'd have to go out of your way to make your project as bad as you're describing.

replies(2): >>45263716 #>>45264258 #
2. lucideer ◴[] No.45263716[source]
A lot of people use tools like Dependabot which automates updates to the lockfile.
replies(1): >>45284666 #
3. simiones ◴[] No.45264258[source]
No, this is just wrong. It might indeed use package-lock.json if it matches your node_modules (so that running `npm install` multiple times won't download new versions). But if you're cloning a repo off of GitHub and running npm install for the first time (which a CI setup might do), it will take the latest deps from package.json and update the package-lock.json - at least this is what I've found many responses online claim. The docs for `npm ci` also suggest that it behaves differently from `npm install` in this exact respect:

> In short, the main differences between using npm install and npm ci are:

> The project must have an existing package-lock.json or npm-shrinkwrap.json.

> If dependencies in the package lock do not match those in package.json, npm ci will exit with an error, instead of updating the package lock.

replies(3): >>45264422 #>>45267351 #>>45284723 #
4. Rockslide ◴[] No.45264422[source]
Well but the docs you cited don't match what you stated. You can delete node_modules and reinstall, it will never update the package-lock.json, you will always end up with the exact same versions as before. The package-lock updating happens when you change version numbers in the package.json file, but that is very much expected! So no, running npm install will not pull in new versions randomly.
replies(1): >>45266848 #
5. 0cf8612b2e1e ◴[] No.45266848{3}[source]
The internet disagrees. NPM will gladly ignore and update lock files. There may exist a way to actually respect lock files, but the default mode of operation does not work as you would naively expect.

- NPM Install without modifying the package-lock.json https://www.mikestreety.co.uk/blog/npm-install-without-modif...

- Why does "npm install" rewrite package-lock.json? https://stackoverflow.com/questions/45022048/why-does-npm-in...

- npm - How to actually use package-lock.json for installing based on locked versions? https://stackoverflow.com/questions/47480617/npm-how-to-actu...

replies(2): >>45268083 #>>45284785 #
6. typpilol ◴[] No.45267351[source]
That's not true. Ci will never take new versions from your lock file.
7. Rockslide ◴[] No.45268083{4}[source]
Those stackoverflow posts are ancient and many major npm releases old, so in other words: irrelevant. That blog post is somewhat up to date but also very vague about the circumstances which would update the lockfile. Which certainly isn't that npm install updates dependencies to newer versions within the semver range, because it absolutely does not.
8. Tadpole9181 ◴[] No.45284666[source]
That's unrelated to this.

As well, both Dependabot and Renovate in isolated environments withour secrets or privileges, need to be manually approved, and have minimum publication ages before recommending a package update to prevent basic supply chain attacks or lockfile corruption from a pinned package version being de-published (up to a 3 day window on NPM).

9. Tadpole9181 ◴[] No.45284723[source]
Literally just try it yourself?

The way you describe it working doesn't even pass a basic "common sense" check. Just think about what you're saying: despite having a `package-lock.json`, every developer who works on a project will get every dependency updated every time they clone it and get to work?

The entire point of the lockfile is that installations respect it to keep environments agreed. The only difference with `clean install` is that it removes `node_modules` (no potential cache poisoning) and non-zero exits if there is a conflict between `package.json` and `package-lock.json`.

`install` will only update the lockfile where the lockfile conflicts with the `package.json` to allow you to make changes to that file manually (instead of via `npm` commands).

10. Tadpole9181 ◴[] No.45284785{4}[source]
1. This guy clearly doesn't know how NPM works. Don't use `--no-save` regularly or you'll be intentionally desyncing your lockfile from reality.

2&3. NPM 5 had a bug almost a decade ago. They literally link to it in both of those pages. Here[^1] is a developer repeating how I've said its supposed to work.

It would have taken you less work to just try this in a terminal than search for those "citations".

[^1]: https://github.com/npm/npm/issues/17979#issuecomment-3327012...