Re:Understand filesystem takeover vulnerabilities in NPM Jav...
by Normal_gaussian on Wednesday January 08, 2020 @12:10AM
(#21988546)
First:
One package can attack by declaring a malicious executable (bin) with the same name as one from a package that you would intentionally use.
Second:
If the malicious package is installed globally, it is injected into your regular PATH, and can similarly "hijack" regular commands.
-
At first I read tfa and said "and? Thats what I expect it to do". Then I noted:
* for a given package installation, a dependencies dependencies bins are available. This is generally counter intuitive.
* conflicting bin entries do not generate warnings or errors.
On a personal note:
- I dont install node modules globally. Wrt development it should stay in repo, and I'm not a fan of managing system utilities from anywhere other than my distros package manager.. largely because its a PITA (I'm looking at you Python).
- I cant think of any reason why non top level dependencies should have their bin files exposed. That is madness.
- if it was just top level files, this would be a meh - I should get a conflict warning but I (or my cocontributors) deliberately installed those packages, so im not too bothered there.
Re:Understand filesystem takeover vulnerabilities in NPM Jav...
by latchkey on Wednesday January 08, 2020 @12:32AM
(#21988637)
I personally don't ever install globally either. But I do have './node_modules/.bin' in my PATH because well... I'm lazy.
If two packages try to install the same filename in that directory, I would want a full stop failure so that I can work it out myself. I'm honestly a bit surprised this isn't already the case.
Re:Understand filesystem takeover vulnerabilities in NPM Jav...
by lioeters on Wednesday January 08, 2020 @05:15AM
(#21990069)
The fact that "bin" files of globally installed dependencies can overwrite each other silently - it's an understandable oversight, and I'll be glad if npm/yarn notifies me in the future.
What surprised me was that the "bin" names can be a relative or absolute path, like:
"bin": {
"/usr/bin/date": "./fake-date"
}
That is scary! I'm guessing these paths will be sanitized in the newest versions of package managers, but that seems like it was a pretty big security hole.
As others have commented, I prefer not to install things globally - mostly locally linked packages of my own. I believe projects should not require or recommend globally installed commands, everything it needs for building should be in its local node_modules folder.
Re:Understand filesystem takeover vulnerabilities in NPM Jav...
by tomxor on Wednesday January 08, 2020 @07:45AM
(#21990874)
> What surprised me was that the "bin" names can be a relative or absolute path, like:
> "bin": { "/usr/bin/date": "./fake-date" }
This will only possibly work if you install it with root privileges... at which point you need to have a reasonable level of trust of the script you are running. It's unreasonable to give the same level of trust to npm packages that you do your OS package manager since anyone can publish an npm package without anyone elses permission.
For this reason I think npm's defaults are a really shitty choice (global prefix under root). I always change the global prefix to live in my user directory for this reason so I can npm install -g without root:
sudo npm config -g set prefix '~/.local'
You will need to add the local bin to your PATH (if it doesn't already contain it)
PATH="$HOME/.local/bin:$PATH"
The order above is important, local must come before existing PATHs for lower precedence so that it cannot override higher privilege bins... e.g so that if an npm package added a bin for '~/.local/bin/cat', it would never be called implicitly since '/usr/bin/cat' exists.
Re:Understand filesystem takeover vulnerabilities in NPM Jav...
by ryukafalz on Wednesday January 08, 2020 @08:34AM
(#21991248)
>The order above is important, local must come before existing PATHs for lower precedence so that it cannot override higher privilege bins
You've got the order reversed there - the first item found in your PATH will be used, and therefore earlier directories in your PATH have higher precedence:
jfred@lambdacrypt ~$ cat dir1/pathtest
#!/run/current-system/profile/bin/bash
echo "script in dir1"
jfred@lambdacrypt ~$ cat dir2/pathtest
#!/run/current-system/profile/bin/bash
echo "script in dir2"
jfred@lambdacrypt ~$ PATH=$HOME/dir1:$HOME/dir2 pathtest
script in dir1
Re:Understand filesystem takeover vulnerabilities in NPM Jav...
by inimino on Wednesday January 08, 2020 @08:59AM
(#21991452)
I don't understand the point in using ~/.local/bin and then putting it in your PATH. The point of treating /usr/local/bin and the other root-owned binary directories specially is that they are in your path, which means that if you type "ls" you want to run "ls" and not something untrusted. For that reason, anything you put in your PATH needs to be treated exactly with as much care as anything you install in /bin. The only difference might be that you don't affect other users on the same system, in a multi-user environment (which is increasingly rare). It might be convenient if you wanted to be able to clean up an entire installation by deleting one directory, but it's not a security feature.
Don't install binaries anywhere in your path if you don't trust them or know where they came from. (Also, sibling is correct that first location found wins when searching PATH for a command name.)
Also, it's not unreasonable to trust npm packages just like OS packages if you know who released it. NPM names are first-come, first-served, and once allocated, they are permanent. If you know and trust the person who released the package, there's nothing wrong with trusting the package. This was, in fact, the norm when npm was new and the community was small and most people knew each other. The only problem is with treating npm like a vetted distro like Debian, and assuming that anything on npm is safe to install without any connection to the author (or 1001 dependencies). That's where everything started to go sideways.
Re:Understand filesystem takeover vulnerabilities in NPM Jav...
by tomxor on Wednesday January 08, 2020 @09:44PM
(#21998062)
> anything you put in your PATH needs to be treated exactly with as much care as anything you install in /bin. [...] it's not a security feature.
The parent was highlighting how the article points out you can overwrite root files:
> "bin": { "/usr/bin/date": "./fake-date" }
This is not possible with ~/.local
I wouldn't call this a "security feature", but I would call it prudent to not hand over root access to npm packages.
> Also, it's not unreasonable to trust npm packages just like OS packages if you know who released it. NPM names are first-come, first-served, and once allocated, they are permanent. If you know and trust the person who released the package, there's nothing wrong with trusting the package.
This is not the problem with npm, the problem is dependencies, and their dependencies and so on. I certainly will never be able to personally vet the 1000 deep nest of dependencies in an npm package I may have to use.
Re:Understand filesystem takeover vulnerabilities in NPM Jav...
by inimino on Wednesday January 08, 2020 @09:18AM
(#21991626)
"bin": { "/usr/bin/date": "./fake-date" }
The only way that can do anything scary, is if you are running `sudo npm install -g <untrusted package>`, and at that point you should already be terrified. Don't do that.
This is no different from any other package you install from any third party. The author of the package is the relevant third party here, npm is just a host, they don't do your security homework for you. (Think "github", not "Debian".)
Re:Understand filesystem takeover vulnerabilities in NPM Jav...
by inimino on Wednesday January 08, 2020 @09:11AM
(#21991538)
No, it's not. If you want to install a package like babel or webpack, or npm itself, and you want it to install manpages and commands like any real Unix program, you want it in /usr/local, and this is exactly what /usr/local is for.
These are the usecases that -g is for, and that's the only thing it's for: utilities that you want to add to your system, not mere runtime JS dependencies. NPM has this feature because in the beginning people (including me) wanted it to be more than just a manager for JS files under a build directory, because we were using it to build shared useful utilities, not just runtime dependencies.
This is a problem that has played out again and again with every programming language that has its own package installer, because setting the boundaries and interacting with the host system correctly while satisfying everyone's needs is challenging.
Re:Understand filesystem takeover vulnerabilities in NPM Jav...
by tomxor on Wednesday January 08, 2020 @09:26PM
(#21997978)
Using ~/.local gives you all those things without giving root access, there is no good reason to stick everything in /usr/local especially with something like npm which is wide open for anyone to publish anything instantly.
Re:Understand filesystem takeover vulnerabilities in NPM Jav...
by inimino on Sunday January 12, 2020 @10:25PM
(#22031579)
But once you run any of those binaries, it's free to replace any of your other (non-root-owned) binaries in `~/.local`. So the trust you're talking about seems to be a preference, but I don't think there's any particularly plausible threat model that makes one of these safer than the other.
Re:Understand filesystem takeover vulnerabilities in NPM Jav...
by johannes1234321 on Wednesday January 08, 2020 @04:17AM
(#21989772)
Why would one use such a exploit? - Using a postinstall script to do evil stuff is way more powerful and simpler to use. And thus more dangerous. If I want to hide something I put it in my libraries code (the user installed it, so at some point in time will `require` my code)
One package can attack by declaring a malicious executable (bin) with the same name as one from a package that you would intentionally use.
Second:
If the malicious package is installed globally, it is injected into your regular PATH, and can similarly "hijack" regular commands.
-
At first I read tfa and said "and? Thats what I expect it to do". Then I noted:
* for a given package installation, a dependencies dependencies bins are available. This is generally counter intuitive.
* conflicting bin entries do not generate warnings or errors.
On a personal note: - I dont install node modules globally. Wrt development it should stay in repo, and I'm not a fan of managing system utilities from anywhere other than my distros package manager.. largely because its a PITA (I'm looking at you Python). - I cant think of any reason why non top level dependencies should have their bin files exposed. That is madness. - if it was just top level files, this would be a meh - I should get a conflict warning but I (or my cocontributors) deliberately installed those packages, so im not too bothered there.
If two packages try to install the same filename in that directory, I would want a full stop failure so that I can work it out myself. I'm honestly a bit surprised this isn't already the case.
The only problem is that npx ALSO defaults to installing things, which is ridiculous.
What surprised me was that the "bin" names can be a relative or absolute path, like:
"bin": { "/usr/bin/date": "./fake-date" }
That is scary! I'm guessing these paths will be sanitized in the newest versions of package managers, but that seems like it was a pretty big security hole.
As others have commented, I prefer not to install things globally - mostly locally linked packages of my own. I believe projects should not require or recommend globally installed commands, everything it needs for building should be in its local node_modules folder.
> "bin": { "/usr/bin/date": "./fake-date" }
This will only possibly work if you install it with root privileges... at which point you need to have a reasonable level of trust of the script you are running. It's unreasonable to give the same level of trust to npm packages that you do your OS package manager since anyone can publish an npm package without anyone elses permission.
For this reason I think npm's defaults are a really shitty choice (global prefix under root). I always change the global prefix to live in my user directory for this reason so I can npm install -g without root:
You will need to add the local bin to your PATH (if it doesn't already contain it) The order above is important, local must come before existing PATHs for lower precedence so that it cannot override higher privilege bins... e.g so that if an npm package added a bin for '~/.local/bin/cat', it would never be called implicitly since '/usr/bin/cat' exists.You've got the order reversed there - the first item found in your PATH will be used, and therefore earlier directories in your PATH have higher precedence:
Don't install binaries anywhere in your path if you don't trust them or know where they came from. (Also, sibling is correct that first location found wins when searching PATH for a command name.)
Also, it's not unreasonable to trust npm packages just like OS packages if you know who released it. NPM names are first-come, first-served, and once allocated, they are permanent. If you know and trust the person who released the package, there's nothing wrong with trusting the package. This was, in fact, the norm when npm was new and the community was small and most people knew each other. The only problem is with treating npm like a vetted distro like Debian, and assuming that anything on npm is safe to install without any connection to the author (or 1001 dependencies). That's where everything started to go sideways.
The parent was highlighting how the article points out you can overwrite root files:
> "bin": { "/usr/bin/date": "./fake-date" }
This is not possible with ~/.local
I wouldn't call this a "security feature", but I would call it prudent to not hand over root access to npm packages.
> Also, it's not unreasonable to trust npm packages just like OS packages if you know who released it. NPM names are first-come, first-served, and once allocated, they are permanent. If you know and trust the person who released the package, there's nothing wrong with trusting the package.
This is not the problem with npm, the problem is dependencies, and their dependencies and so on. I certainly will never be able to personally vet the 1000 deep nest of dependencies in an npm package I may have to use.
The only way that can do anything scary, is if you are running `sudo npm install -g <untrusted package>`, and at that point you should already be terrified. Don't do that.
This is no different from any other package you install from any third party. The author of the package is the relevant third party here, npm is just a host, they don't do your security homework for you. (Think "github", not "Debian".)
Don't install packages you can't trust.
These are the usecases that -g is for, and that's the only thing it's for: utilities that you want to add to your system, not mere runtime JS dependencies. NPM has this feature because in the beginning people (including me) wanted it to be more than just a manager for JS files under a build directory, because we were using it to build shared useful utilities, not just runtime dependencies.
This is a problem that has played out again and again with every programming language that has its own package installer, because setting the boundaries and interacting with the host system correctly while satisfying everyone's needs is challenging.
Will they actually warn the user if this happens? The npm blog post was unclear on this point:
https://blog.npmjs.org/post/189618601100/binary-planting-wit...
Depending on code loaded means you trust it.