top | item 45040282

(no title)

inbx0 | 6 months ago

Periodic reminder to disable npm install scripts.

    npm config set ignore-scripts true [--global]
It's easy to do both at project level and globally, and these days there are quite few legit packages that don't work without them. For those that don't, you can create a separate installation script to your project that cds into that folder and runs their install-script.

I know this isn't a silver bullet solution to supply chain attakcs, but, so far it has been effective against many attacks through npm.

https://docs.npmjs.com/cli/v8/commands/npm-config

discuss

order

homebrewer|6 months ago

I also use bubblewrap to isolate npm/pnpm/yarn (and everything started by them) from the rest of the system. Let's say all your source code resides in ~/code; put this somewhere in the beginning of your $PATH and name it `npm`; create symlinks/hardlinks to it for other package managers:

  #!/usr/bin/bash

  bin=$(basename "$0")

  exec bwrap \
    --bind ~/.cache/nodejs ~/.cache \
    --bind ~/code ~/code \
    --dev /dev \
    --die-with-parent \
    --disable-userns \
    --new-session \
    --proc /proc \
    --ro-bind /etc/ca-certificates /etc/ca-certificates \
    --ro-bind /etc/resolv.conf /etc/resolv.conf \
    --ro-bind /etc/ssl /etc/ssl \
    --ro-bind /usr /usr \
    --setenv PATH /usr/bin \
    --share-net \
    --symlink /tmp /var/tmp \
    --symlink /usr/bin /bin \
    --symlink /usr/bin /sbin \
    --symlink /usr/lib /lib \
    --symlink /usr/lib /lib64 \
    --tmpfs /tmp \
    --unshare-all \
    --unshare-user \
    "/usr/bin/$bin" "$@"
The package manager started through this script won't have access to anything but ~/code + read-only access to system libraries:

  bash-5.3$ ls -a ~
  .  ..  .cache  code
bubblewrap is quite well tested and reliable, it's used by Steam and (IIRC) flatpak.

internet_points|6 months ago

Thanks, handy wrapper :) Note:

    --symlink /usr/lib /lib64 \
should probably be `/usr/lib64`

and

    --share-net \
should go after the `--unshare-all --unshare-user`

Also, my system doesn't have a symlink from /tmp to /var/tmp, so I'm guessing that's not needed for me (while /bin etc. are symlinks)

aorth|6 months ago

Very cool idea. Thanks for sharing. I made some minor tweaks based on feedback to your comment:

  #!/usr/bin/env bash
  #
  # See: https://news.ycombinator.com/item?id=45034496
  
  bin=$(basename "$0")
  
  echo "==========================="
  echo "Wrapping $bin in bubblewrap"
  echo "==========================="
  
  exec bwrap \
    --bind ~/.cache ~/.cache \
    --bind "${PWD}" "${PWD}" \
    --dev /dev \
    --die-with-parent \
    --disable-userns \
    --new-session \
    --proc /proc \
    --ro-bind /etc/ca-certificates /etc/ca-certificates \
    --ro-bind /etc/resolv.conf /etc/resolv.conf \
    --ro-bind /etc/ssl /etc/ssl \
    --ro-bind /usr /usr \
    --setenv PATH /usr/bin \
    --symlink /usr/bin /bin \
    --symlink /usr/bin /sbin \
    --symlink /usr/lib /lib \
    --symlink /usr/lib64 /lib64 \
    --tmpfs /tmp \
    --unshare-all \
    --unshare-user \
    --share-net \
    /usr/bin/env "$bin" "$@"

Notably `--share-net` should be moved down since it is negated by `--unshare-all`. I also added a reminder that the command is being bubblewrapped, modified the second read-write bind to the current directory, and changed the final exec to use `/usr/bin/env` to find the binary so it can be more flexible. I tested it with npm and yarn just now and it seems to work well. Thanks!

TheTaytay|6 months ago

Very cool. Hadn't heard of this before. I appreciate you posting it.

oulipo2|6 months ago

Will this work on osX? and for pnpm?

johnisgood|6 months ago

Firejail is quite good, too. I have been using firejail more than bubblewrap.

shermantanktop|6 months ago

This is trading one distribution problem (npx) for another (bubblewrap). I think it’s a reasonable trade, but there’s no free lunch.

tiagod|6 months ago

Or use pnpm. The latest versions have all dependency lifecycle scripts ignored by default. You must whitelist each package.

chrisweekly|6 months ago

pnpm is not only more secure, it's also faster, more efficient wrt disk usage, and more deterministic by design.

trw55|6 months ago

Same for bun, which I find faster than pnpm

jim201|6 months ago

This is the way. It’s a pain to manually disable the checks, but certainly better than becoming victim to an attack like this.

eitau_1|6 months ago

Why the same advice doesn't apply to `setup.py` or `build.rs`? Is it because npm is (ab)used for software distribution (eg. see sibling comment: https://news.ycombinator.com/item?id=45041292) instead of being used only for managing library-dependencies?

ivape|6 months ago

It should apply for anything. Truth be told the process of learning programming is so arduous at times that you basically just copy and paste and run fucking anything in terminal to get a project setup or fixed.

Go down the rabbit hole of just installing LLM software and you’ll find yourself in quite a copy and paste frenzy.

We got used to this GitHub shit of setting up every process of an install script in this way, so I’m surprised it’s not happening constantly.

username223|6 months ago

It should, and also to Makefile.PL, etc. These systems were created at a time when you were dealing with a handful of dependencies, and software development was a friendlier place.

Now you're dealing with hundreds of recursive dependencies, all of which you should assume may become hostile at any time. If you neither audit your dependencies, nor have the ability to sue them for damages, you're in a precarious position.

ifwinterco|6 months ago

For simple python libraries setup.py has been discouraged for a long time in favour of pyproject.toml for exactly this reason

dns_snek|6 months ago

Whenever I read this well-meaning advice I have to ask: Do you actually read hundreds of thousands of lines of code (or more) that NPM installed?

Because the workflow for 99.99% of developers is something resembling:

1. git clone

2. npm install (which pulls in a malicious dependency but disabling post-install scripts saved you for now!)

3. npm run (executing your malicious dependency, you're now infected)

The only way this advice helps you is if you also insert "audit the entirety of node_modules" in between steps 2 and 3 which nobody does.

IshKebab|6 months ago

Yeah I guess it probably helps you specifically, because most malware is going to do the lazy thing and use install scripts. But it doesn't help everyone in general because if e.g. NPM disabled those scripts entirely (or made them opt-in) then the malware authors would just put their malware into the `npm run` as you say.

halflife|6 months ago

This sucks for libraries that download native binaries in their install script. There are quite a few.

lrvick|6 months ago

Downloading binaries as part of an installation of a scripting language library should always be assumed to be malicious.

Everything must be provided as source code and any compilation must happen locally.

junon|6 months ago

You can still whitelist them, though, and reinstall them.

andix|6 months ago

I guess this won't help with something like nx. It's a CLI tool that is supposed to be executed inside the source code repo, in CI jobs or on developer pcs.

inbx0|6 months ago

According to the description in advisory, this attack was in a postinstall script. So it would've helped in this case with nx. Even if you ran the tool, this particular attack wouldn't have been triggered if you had install scripts ignored.

arminiusreturns|6 months ago

As a linux admin, I refuse to install npm or anything that requires it as a dep. It's been bad since the start. At least some people are starting to see it.

azangru|6 months ago

> As a linux admin, I refuse to install npm or anything that requires it as a dep. It's been bad since the start.

As a front-end web developer, I need a node package manager; and npm comes bundled with node.

johnisgood|6 months ago

At this point why not just avoid npm (and friends) like the plague? Genuinely curious.

ifwinterco|6 months ago

I work for a company that needs to ship software so my salary can get paid

no_wizard|6 months ago

Pnpm natively lets you selectively enable it on a package basis

antihero|6 months ago

I wonder how many other packages are going to be compromised due to this also. Like a network effect.

sheerun|6 months ago

Secondary reminder that it means nothing as soon as you run any of scripts or binaries

herpdyderp|6 months ago

Unfortunately this also blocks your own life cycle scripts.

oulipo2|6 months ago

Does it work the same for pnpm ?