
Small world with high risks: a study of security threats in the NPM ecosystem - godelmachine
https://blog.acolyer.org/2019/09/30/small-world-with-high-risks/
======
segphault
What the npm ecosystem really needs is something like the distinction between
Ubuntu's "main" and "universe" repositories, so that you have a smaller subset
of known-good packages with harmonized transitive dependencies, stronger
centralized curation, a lot more direct scrutiny, tighter control over
versioning, and some party that is responsible for addressing vulnerabilities
and ensuring appropriate maintainership. If you could rely on that for core
functionality and only needed to go outside of it for the long tail of more
specialized things, it would be a lot cleaner and safer than what we do today.

Linux distros have many, many years of experience curating packages at scale.
It is crazy to me that the node community just totally disregards all of the
best practices learned by the Linux distros in favor of practices that are
lazy and unambiguously dangerous.

~~~
bostik
Intel and Nokia were trying to add repository trust levels to rpm back in
2010/2011.

To this day, if you can add a new repository, it is fully trusted and can
provide trojaned updates to any core package. Bump the version number to
something higher than what the core distro would use and you can persist for
quite a long time. I remember pointing this out at a Nokia project (would have
been no later than early 2008) as an attack vector via apt repositories.

We wanted to prevent a rogue or compromised repository from being able to
provide an update to, say, glibc or libstdc++. Never got to work on that -
Elopcalypse took it all down.

~~~
hnarn
> To this day, if you can add a new repository, it is fully trusted and can
> provide trojaned updates to any core package.

Invent idiot-proof security and someone will invent a better idiot. Even if
you have a "trusted=1" flag for repos, you can be sure people will set
external repos to be just as trusted as the core ones without a second thought
as soon as they stop them from doing what they want to do (whatever that is,
or however in/sane it is).

It's maybe not the most elegant option, but for security-conscious sysadmins
you could already today disable all repos ad hoc and run your "system wide
update" only from certain whitelisted repos, while still allowing specific
one-off package installs from third party repos.

By adding a third party repo you have already said you trust that repo to
install software, probably as root, on your machine. It doesn't get much worse
than that from a security standpoint anyway right, will "trust flags" really
make much of a difference to the wider security issue?

Sorry if I'm making too many assumptions here or thinking out loud.

~~~
bostik
> _Even if you have a "trusted=1" flag for repos, you can be sure people will
> set external repos to be just as trusted as the core ones_

That was the thing - you couldn't.

I don't remember which way the level hierarchy went, but the idea was that rpm
could not be executed directly even by root (LSM prevented that), and all
package installation logic was confined to Zypper/libzypp. Packages and repos
could declare their security level. Trying to pull in an upgrade to a
LEVEL(core) package from a LEVEL(media) repository would fail. Zypper simply
would not allow to install a package from a lower-security repository over an
installed package that had come from a higher-security origin. Manually added
LEVEL(core) repos would have been ignored.

There were a few layers of applied crypto, package signatures and immutable
keyrings involved too. I had a prototype Zypper/libzypp with package-level
signature verification almost ready just before my vacation and planned to
polish it to an RFC after coming back. Best laid plans... During those two
weeks the entirety of Nokia's linux development had been axed, maemo killed
and thousands of good embedded systems engineers were suddenly looking for new
jobs.

Funny thing, though. Zypper's source code was almost pleasant to work with
after having seen the Lovecraftian horrors that made up libapt.

------
ecmascript
Security has always been one of my biggest worries when using node. The
mentality in the javascript world seems to be to simply not care.

To just use whatever libraries. On all the node.js projects I have worked on,
none has had any security aspects when importing a new library. That is a bit
scary since many libraries has a ton of dependencies themselves.

Not once have I even heard a discussion about a security topic or perhaps
maybe vetting dependencies and similar stuff.

------
fock
or maybe just make a standard library (with a tool to pick only what's
necessary for the web) - I think the worst thing is the incredible number of
packages just replacing the node-native modules. One would suppose that in a
"always-run-on-the-latest-version"-ecosystem one would try to integrate those
into the mainline, but apparently some people really like a filled
package.json...

Also if you look close, a lot of commonly required modules in the big projects
are just used once in an act of "code"-spam by interested parties...

EDIT: just have a look at this:
[https://github.com/eslint/eslint/commit/55bc35dcd2dc3987cc77...](https://github.com/eslint/eslint/commit/55bc35dcd2dc3987cc776ac1ba195c72e31d6311)
\- let's use cross-spawn, if you could use this node-native function
(available for about a 100 years...)
[https://nodejs.org/api/child_process.html#child_process_chil...](https://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options)

------
dominicr
For basic JS functions, I much prefer to write my own than rely on someone
else's. A low number of dependencies is a factor for me when choosing a
package (if there are options).

Quite a few packages cover basic functions, such as type identification, array
handling, etc... which have only a few lines of relevant JS code but are used
by many other packages. That seems to unnecessarily increase the risk to my
project of the module disappearing or becoming a security threat. There's
something to be said for rolling your own helper functions.

------
justincormack
There is also work ongoing to isolate libraries at run time so they can’t do
anything see [https://www.infoq.com/presentations/npm-security-realms-
ses/](https://www.infoq.com/presentations/npm-security-realms-ses/)

~~~
z3t4
Unix based operating systems have pretty great file system security and almost
everything is based on the file system, and you can use unix sockets for
networking. So you can for example create a new user, give the user access to
only the folders it needs. Then run the program as that user. You can also
from within the app itself read configuration files, etc, then chroot, and
setuid to continue as a non privileged user. Then you can use Apparmor or
se_linux to fine tune access.

~~~
twic
But you can't apply any of that to one particular library that a program uses,
while not restricting the rest of the program.

~~~
z3t4
Yeh, you could spawn new processes with different access levels, but it might
add too much complexity to the app. It would be cool if we could require
modules like this:

    
    
        foo = require("excitingModule", {fs: true, net: true, os: true});
    

It wouldn't be that hard to implement either.

~~~
lachenmayer
The creator of Node is currently working on a runtime to enable exactly that:
[https://deno.land](https://deno.land)

~~~
z3t4

        deno --allow-net https://deno.land/std/examples/echo_server.ts
    

This would be the same as running something with an unprivileged user:

    
    
        sudo -u otheruser node echo_server.js
    

Deno however takes it to a whole new level by running server code directly
from the web =)

~~~
bartlomieju
You can scope it further:

    
    
      deno --allow-net=0.0.0.0:8000 https://deno.land/std/examples/echo_server.ts
    

Or even provide a list of addresses:

    
    
      deno --allow-net=0.0.0.0:8000,localhost https://deno.land/std/examples/echo_server.ts

~~~
z3t4
On Linux you can use namespaces

    
    
        ip netns exec networkname node script.js
    

Still only on the entire app though, the idea was how to restrict single
modules and their dependencies, not your whole app! Something like:

    
    
        const foo = requires("bar", {fs: true, net: "0.0.0.0:8000", os: true});

------
2sk21
I wonder if a system similar to the way Kosher certification might be
applicable here. A company could continuously scan packages for threats and
host the scanned packages which could be accessed via subscription.

~~~
riyakhanna1983
Why should we trust a company over the community? And how accurate could be
the scanning? What if something is missed or if there are a lot of false
positives?

~~~
elliekelly
I do wonder how frequently and thoroughly the community is looking at the
packages though. Perhaps I'm in the minority but I really only look when I'm
debugging or trying to write a similar function myself to remove a dependency.
But as a fairly novice and self-taught developer I'm not sure I'd recognize a
security threat even if I was staring right at it.

~~~
2sk21
That is exactly my point. Studying code for security exploits is hard and
tedious work. If I were developing a Node.js app, I would be glad to pay
someone to do that for me.

------
mike-cardwell
This is why I wrote:
[https://gitlab.com/mikecardwell/safernode](https://gitlab.com/mikecardwell/safernode)

~~~
fock
why don't you use podman, bubblewrap or just straight namespaces?

~~~
mike-cardwell
Because I'm familiar with Docker

------
lacker
I wonder if it would be worth it for a set of large companies who depend on
the npm ecosystem to get together and jointly fund security auditing for the
top packages.

------
riyakhanna1983
"vetting the most dependent upon 1,500 packages would reduce the ITP ten fold,
and vetting 4,000 packages would reduce it by a factor of 25"... I wonder how
accurate could be this automated package vetting?

------
trishankdatadog
NPM should use The Update Framework (TUF) [1] and in-toto [2] in order to
protect its users from attacks against the registry itself. A notable list of
adoptions include:

* Datadog is using both TUF and in-toto to defend against attacks between developers and end-users of its Agent integrations [3].

* Docker Content Trust is protecting users from a compromise of Docker Hub itself [4] using a version of TUF [5].

* Uptane is a version of TUF that is being standardized to protect software updates for automobiles [6].

* PyPI is considering adopting TUF to protect users of Python packages [7].

* Cloud Native Application Bundles is standardizing the use of TUF and in-toto to protect users of cloud-native applications [8].

Disclosure: I am a security engineer at Datadog, and am involved with both TUF
and in-toto.

[1] [https://theupdateframework.com](https://theupdateframework.com)

[2] [https://in-toto.io](https://in-toto.io)

[3] [https://www.datadoghq.com/blog/engineering/secure-
publicatio...](https://www.datadoghq.com/blog/engineering/secure-publication-
of-datadog-agent-integrations-with-tuf-and-in-toto/)

[4] [https://success.docker.com/article/docker-hub-user-
notificat...](https://success.docker.com/article/docker-hub-user-notification)

[5] [https://blog.docker.com/2015/08/content-trust-
docker-1-8/](https://blog.docker.com/2015/08/content-trust-docker-1-8/)

[6] [https://uptane.github.io/](https://uptane.github.io/)

[7]
[https://github.com/pypa/warehouse/issues/5247](https://github.com/pypa/warehouse/issues/5247)

[8] [https://github.com/deislabs/cnab-
spec/blob/master/300-CNAB-s...](https://github.com/deislabs/cnab-
spec/blob/master/300-CNAB-security.md)

------
twic
Who is ehsalazar? Is that actually a person publishing micro-packages, or
what?

------
Roboprog
How does this compare to package managers such as Maven (Java) or CPAN (Perl)?

What is the vetting process for other package managers?

------
franciscop
I thought this was written by certain company that is trying very hard on
profiting creating FUD in the npm ecosystem. To my pleasant surprise it isn't
and it's written by a new/different author. Scroll almost to the end and there
it is, the author is a board observer in said company.

~~~
jannes
It's not FUD if the danger is real. In that case it's just everyone's
responsibility to stay informed.

