3 ms·
This is a great question, and there are actually a number of different reasons: 1. Package installation often happens under different privileges than actually
by tolmasky 5y ago
This is a great question, and there are actually a number of different reasons:
1. Package installation often happens under different privileges than actually running your end user app. There is unfortunately a lot of "just use --unsafe-perm to make the install work" advice out there which means a lot of people are installing packages as root even though they're not running as root. Also consider that a lot of npm packages ultimately get run in the browser, so the attack surface there should have very little to do with the files on your computer, but install scripts make this not the case. For the same reason, this means that this might be the only kind of attack that has the ability to run on your build machine, since your build machine may not actually "run" your app.
2. The fact that the code doesn't have to be run to be effective makes it quite difficult to spot, and thus increases its likelihood of sneaking into your dependency chain. For example, GitHub will often straight up just hide large `package-lock.json` file diffs, and no one wants to read through those. So a very innocuous patch version change in an otherwise unrelated bug fix could completely fool the PR reviewer: this is because there's no code "history" that would imply any sort of entryway into attack. All the code looks totally reasonable. By having to explicitly allow the package to use install scripts however, all of a sudden the PR would contain a clear indication that new foreign code that isn't represented anywhere in the commit will be run. This is huge.
3. This also takes advantage of the fact that the vast majority of npm installs aren't done by humans, but by CI and production deploys. Again, by ensuring that the attack is completely "passive", that is to say, as long as you get installed you've succeeded. A lot of times this can be triggered just by issuing a PR with automatic build and CI machines. The correct behavior for something trying to run a new script on your machine when a PR is submitted isn't to infect your CI machine, it should be for the test to fail with "package X tried to use an install script".
- danenania 5y agoAll great points, thanks. It would definitely reduce the surface area for attacks. In practice, it may just change which kinds of packages are targeted (packages in the build-time dependency tree instead of runtime), but it would still be a win. Ultimately, I still think we need real sandboxing built in to the runtime to really solve this problem. Is there something inherent to node's architecture that would make this impossible or is it just a ton of work? Could Chrome's sandbox and CSP implementation be piggy-backed on perhaps? Deno takes some steps in this direction but they stopped well short of what's really needed.
- pxc 5y ago> Deno takes some steps in this direction but they stopped well short of what's really needed. Could you say a little more about what's lacking in Deno here? I know it exists and I know it's taken some new security measures, but not much else.
- danenania 5y agoI’m not a Deno user but my understanding is that permissions for the file system or network are all-or-nothing for a whole project. There’s no ability to specify directories or domains, or for dependencies to declare permissions they need. It’s better than nothing, but only makes a difference for projects that don’t need the file system and/or network at all. It wouldn’t have helped with any node project I’ve ever seen in the wild. That said, perhaps it’s just a starting point and will be expanded into something more useful in time. It would be a killer feature imo if done right so I hope they go in that direction.