2

Basically what's to prevent me from publishing an NPM module with arbitrary installation script that steals everything from your computer when you npm install my-malicious-package if the installation is not running in sandbox?

In this article they suggest that most of the attackers would place their malicious script in the pre/post install hooks. That's easy to detect and filter out. I'm mostly concerned with the actual installation of the package where arbitrary could be ran.

Kousha
  • 32,871
  • 51
  • 172
  • 296

3 Answers3

2

There's nothing preventing those scripts from performing any actions as current user. You need to avoid running install scripts.

Most malicious packages are using those, but in rare cases (like lofygang recently) the packages may carry malicious code in the functionality too.

How to protect a project from malicious packages

  1. make sure you don't run lifecycle (postinstall) scripts unless they're known and necessary (see my talk on this topic)
  2. put 3rdparty code in a compartment, lock down the environment, decide on which powerful APIs to pass to each package.

The second step requires the use of Compartment, which is a work-in-progress in TC39 https://github.com/tc39/proposal-compartments/

But a shim exists. And Some tooling was built on top of that shim.

You could use the SES-shim directly and implement your own controls, or use the convenience of LavaMoat

LavaMoat lets you generate and tweak a per-package policy where you can decide which globals and builtins it should have access to. LavaMoat also offers a tool to manage install scripts.

Here's my talk on SES and LavaMoat with a demo at the end.

How to set up LavaMoat

See LavaMoat docs for more details

  1. disable/allow dependency lifecycle scripts (eg. "postinstall") via @lavamoat/allow-scripts
npm i --ignore-scripts -D @lavamoat/allow-scripts
npx --no-install allow-scripts setup
npx --no-install allow-scripts auto
  • then, edit the allow-list in package.json
  • after every insstall/reinstall run allow-scripts
  1. run your server or build process in lavamoat-node
npm i -D lavamoat

in your package.json add something like:

"scripts": {
  "lavamoat-policy": "lavamoat app.js --autopolicy",
  "start": "lavamoat app.js"
  • run lavamoat-policy every time you make changes to your dependency tree and review the policy (see also: policy override)
  • run npm start to start your app

Disclaimer: I contribute to LavaMoat and Endo. They are Open Source projects on permissive licenses.

naugtur
  • 16,827
  • 5
  • 70
  • 113
0

The only way that npm itself runs package code is in install hooks.

If you disable install hooks, no untrusted code can run until you actually load it in your application (at which point you're hosed).

SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
  • So let me get this straight. Whatever script that performs the actual `install` of my script is sandboxed? – Kousha Aug 23 '17 at 17:48
  • @Kousha: No; that script is part of npm itself (it just extracts files), and is trusted. – SLaks Aug 23 '17 at 17:49
0

I've made node-safe, which allows you to use the native macOS sandbox when using node, npm and yarn:

# Allow reading files, but only in the current folder
node --enable-sandbox --allow-read="./**" myscript.js

When using the sandboxed package managers rogue dependencies are not able to compromise your system anymore through postinstall scripts and other means.

endzeit
  • 685
  • 1
  • 6
  • 15