
Alert: NPM modules hijacked - vdfs
http://www.drinchev.com/blog/alert-npm-modules-hijacked/
======
jimrandomh
There's a lesson to be drawn here about dependency hygiene. On one hand, code-
reuse is a good thing, and incorporating other projects by reference is a way
to make it happen. On the other hand, each dependency you add creates a little
bit of risk: that the package will be updated in a way that breaks your
application, or the package maintainer will go rogue, or the package will get
hijacked.

Most programming-language communities manage the code-reuse/dependency-hygiene
tradeoff by concentrating code into a relatively small number of large
libraries, and when people want a function or two that isn't in one of the
libraries they're using, they incorporate it by copy-paste. In the
Javascript/NPM world, on the other hand, I see a lot of projects with
dependency references to huge numbers of tiny dependencies.

Today, we're seeing one of the reasons why that's a liability. Most people
will take away lessons about code signing and signatures, and presumably the
NPM software is going to be improved in that regard. But the other lesson is
that _projects should have fewer dependencies_. Using a library may be as
simple as adding one line to a package configuration file, but using a library
_properly_ requires substantial due diligence on the library, its license, its
bug tracker and its author.

~~~
draw_down
No, no. This is about whether people should be able to unpublish from the
registry, or how that should be handled since it's problematic in any case.

~~~
apalmer
you are part of the problem here. Many folks are refusing to even consider the
fundamental issue because it is different from the mindset they are used to.

Yes this particular episode is related to the unpublishing results... however
the underlying issue is not only about unpublishing results. The underlying
issue is:

number 1, Having thousands of dependencies is a software engineering trade
off, their is a upside and a downside of that trade off. Having Thousands of
dependencies is fundamentally more 'risky' than have a few. Period. End Of
Story. It is ok to accept the trade off based on what you are optimizing for.
It is not ok to refuse to accept the fact you are making a tradeoff.

number 2, is you should not be running production builds or builds for
important components based on dependencies on the naked internet. This is also
an engineering tradeoff but is firmly in the camp of what is considered 'bad
practice'. This is fundamentally the same exact underlying reason why we have
build servers instead of just builds from developer work stations. Developer
workstations are not controlled environments, which means the builds are not
guaranteed repeatable. A build server that depends on the state of the naked
internet is not a controlled environment. It blows up today because of
unpublishing, it will blow up tomorrow because of something else.

~~~
Wintamute
I agree with what you're saying. But I think the "grand experiment" of npm and
modern javascript development is to go "all in" on the "lots of small modules"
approach. Having many small dependencies is, and always has been, a trade off.
The question is how far can we get optimising away from the pitfalls, while
still retaining the benefits?

I think it's a worthy exercise, since the prize is no less than efficiently
distributing coding effort across the globe.

Problems like we've seen today are a double edged sword. On the one hand
they're troubling, but it'll focus the community on the problems, and
hopefully npm will make a few changes too.

> A build server that depends on the state of the naked internet

Whether npm based or not, don't the vast majority of build servers, for
whatever language or platform, rely on the state of the naked internet?
Whether that's downloading binaries, compiling from source, or whatever?

~~~
clappski
Your build servers shouldn't really be exposed to the public internet, best
practise would be to get all dependencies/binaries of a local network.

------
_Marak_
I've been on the receiving end of a NPM name dispute violation handed down by
Izs.
[https://docs.npmjs.com/misc/disputes](https://docs.npmjs.com/misc/disputes)

Was on vacation and found out that I had lost a published package name within
24 hours of the dispute request. Broke a few production systems. Really messed
up my day.

Ended up having to beg with the person who filed the original request and they
eventually gave me the package back.

Honestly, the whole process was a bit personal and I felt like I was being
singled out as an individual by NPM, rather than being treated like a
developer who was using the service. Not a nice feeling.

------
SlashmanX
It's insane that NPM allows anybody to just take over a module name if the
original is unpublished, without even a warning to users.

~~~
henrikfr
Insane, yes, but I guess it's just never really been that much of a problem
until now. Hopefully something good will come out of this..

~~~
CorpOverreach
You would think this is part of security 101 for these things...

And people wonder why big enterprises are scared of touching open source
stuff.

~~~
nyan4
> And people wonder why big enterprises are scared of touching open source
> stuff.

 _some_ open source stuff. Most enterprises dig distributions, especially with
LTS.

------
zamalek
Edit: I'm definitely wrong. The person who published these was merely parking
the packages. Leaving the existing (inaccurate, see response) message as one
example of how badly this could have turned out.

 _> and the content of the files is suspicious_

The script seems as though it might publish your entire codebase to NPM.
Sorting NPM packages by creation date[1] reveals[2] a[3] few[4] potential
victims. Filtering by the ISC license also seems to work.

[1]:
[https://libraries.io/search?order=desc&platforms=NPM&sort=cr...](https://libraries.io/search?order=desc&platforms=NPM&sort=created_at)

[2]: [https://libraries.io/npm/alaska-dev](https://libraries.io/npm/alaska-
dev) \- internally hosted repo, edit: license doesn't match other projects by
the same developer

[3]: [https://libraries.io/npm/b3app-
prototype](https://libraries.io/npm/b3app-prototype) \- private bitbucket
repo, edit: deleted from npmjs

[4]: [https://libraries.io/npm/nodework](https://libraries.io/npm/nodework) \-
private bitbucket repo

~~~
zwily
Installing one of these packages doesn't execute the script though, you'd have
to do that yourself. (It could be updated to do that though, which is
terrifying.)

~~~
zamalek
I wonder if the author is possibly proving a point. Regardless, it seems as
though having an NPM user set up on your CI server is a big risk.

~~~
NathanKP
You have to have an NPM user setup on your CI server in order to use private
NPM packages, which some companies do instead of hosting their own onsite NPM.

------
dustinmoorenet
As shitty as unpublishing is, I think the best thing the npm community needs
to take away from this is auto updating is bad. Remove the ~ and ^ from your
dependencies so that only a package of a specific version can be installed.
"This or better" thinking doesn't work if "better" is unknown. I know that the
version I am using currently is fine but I don't know about future updates.
Even if we had signed packages, we are still installing unknown software if we
just trust other devs. I lock my dependency version and then use
[https://www.npmjs.com/package/npm-check-
updates](https://www.npmjs.com/package/npm-check-updates) to figure out what
needs updating, then I test my code. This should not be done as an automatic
part of the build process.

*edited npm capitalization

~~~
spankalee
Dependency version ranges should be a _wide_ as possible, so that users of
your libraries have flexibility when selecting versions.

Rather than artificially constrict your version ranges, NPM should support
real version locking, and applications should check in their lock file.

~~~
dustinmoorenet
Known ranges are fine. e.g. It is fine to accept known published versions
0.0.1 to 0.0.4, but not unknown future versions 0.0.5 and up, which ^ and ~
allow.

------
heavenlyhash
I challenge someone to tell me the difference between npm and an RCE.

"npm" is two things in this picture: the server and centralized service, and
the software tool on everyone's build/dev machines.

Folks have historically been happy trusting the centralized npm server to
behave consistently and pleasantly, and some opinions have recently shifted on
that. But frankly, the server doesn't matter, in the big picture. The npm tool
on your computer does. It's the one _executing code on your computer_ with all
of your local user's privileges.

This tool starts executing new code from a new author on my host as my user
without any authentication except "trust the server". This is exactly the same
words we would use to describe behavior of $script_kiddie_virus_of_the_week:

> "download code from C&C server; run it, thanks:D"

What's the difference here? "good intentions"?

I'd rather have something more than "good intentions" controlling what code
ends up running on my computer. Wouldn't you?

------
drinchev
Author of the post here. According to a tweet [1], the user @nj48 seems to be
non-malicious.

I updated the blog post.

Nevertheless I find his actions dangerous and irresponsible.

[1]
[https://twitter.com/seldo/status/712673227630313472](https://twitter.com/seldo/status/712673227630313472)

~~~
tombrossman
Curious, should those of us using their Linux PPAs disable them until this is
sorted? The idea of re-using disabled package names is out there now and I
wonder how long it is before someone malicious tries this. Is this an
unreasonable concern?

~~~
drinchev
Not sure about that. I'm away of the PPA's + NodeJS's NPM packaging model.

------
dontscale
For those of us who are pissed that this is going down but need the status to
get on with our lives:

nj48 is a known friendly who has identified himself to us. We're going to
clarify later today.

[https://twitter.com/seldo/status/712673227630313472](https://twitter.com/seldo/status/712673227630313472)

~~~
newman314
I bet the orig dev was considered a known friendly until he decided to
unpublish.

Relying on the notion of a "known friendly" to protect packages and namespace
does not strike me as a sound practice.

As others may have mentioned, publishing packages really should be fire and
forget. If something bad goes out, a replacement should be sent out. And for
the life of me, I don't understand why they did not go with the
<author/package> scheme.

------
gmisra
It's worth noting that the official NPM dispute resolution policy makes the
following very clear
([https://docs.npmjs.com/misc/disputes](https://docs.npmjs.com/misc/disputes))

> Some things are not allowed, and will be removed without discussion if they
> are brought to the attention of the npm registry admins, including but not
> limited to:

...

4\. "Squatting" on a package name that you plan to use, but aren't actually
using. Sorry, I don't care how great the name is, or how perfect a fit it is
for the thing that someday might happen. If someone wants to use it today, and
you're just taking up space with an empty tarball, you're going to be evicted.

5\. Putting empty packages in the registry. Packages must have SOME
functionality. It can be silly, but it can't be nothing. (See also:
squatting.)

------
tomku
Looks like the author of the modules wrote a shell script to generate a
package.json file and publish empty modules to npm to grab up all the
unpublished names. However, when they ran it, they ran it in the same folder
with their shell script and list of available modules and `npm publish`
included them in the published modules as it does by default.

------
raesene4
A big problem with Software repositories that don't allow for /enforce
cryptographic signing by the developer is that this can happen...

Ideally the developer would sign before publishing and the consumer could
check the signature to validate before using.

Whilst not a silver bullet this is a kind of essential part of a secure
package management solution.

~~~
pvg
Plenty of repositories require signatures.

~~~
raesene4
for NPM? As far as I'm aware it's not even an available feature. None of
rubygems/PyPi/NuGet require digital signatures...

What repositories were you thinking of that do require that?

~~~
pvg
NPM doesn't. Maven does. Debian has authentication of the repository itself.

~~~
raesene9
yep the linux repositories are generally way ahead of the programming language
lib ones in this regard (evidently with the exception of Maven), one of the
reasons that it's a shame to see newer ones not learn the lessons that
previous repo's have on security

------
pluma
Overly dramatic. The content is not suspicious at all, it's clearly a script
to generate the package.json for an arbitrary package name passed in as an
argument to the script.

I'm guessing @nj48 used a script to go over the official list of unpublished
modules and attempt to generate a placeholder for each of them.

The same user also published some actual (unmanipulated) forks of the original
modules, so I'm guessing this is mostly a quick move to preempt any malicious
hijacking by others.

There is no reason to assume the "hijacking" is malicious. Certainly not in
the scripts. The user is active on GitHub and shows no indication of malicious
intent.

However it IS worth pointing out that the unpublished modules should now be
treated with caution if you still rely on them because even if the
replacements are identical and benevolent you probably need to take action.

~~~
rhinoceraptor
> a script to generate the package.json for an arbitrary package name

Yep, that and it ___publishes your project to NPM!!!_ __

edit: I was wrong, the x.sh script looks malicious but appears not to be? In
any case it shows that installing NPM modules is just as unsafe as 'curl |
sh'.

Ways to be safe are to first check what scripts will be run by a package: 'npm
show $MODULE scripts'. There is also the '\--ignore-scripts' flag[1].

[1]: [https://blog.liftsecurity.io/2015/01/27/a-malicious-
module-o...](https://blog.liftsecurity.io/2015/01/27/a-malicious-module-on-
npm)

~~~
jessaustin
_If_ you're logged in, _if_ you call it with an argument that isn't already in
use as a module name, and _if_ you specifically enter the full path to the
script (you don't have cwd on your $PATH, do you?). TFA would make more sense
if it contained a warning not to run random scripts that one downloads without
reading them.

As it is, TFA seems like an attempt to invent malicious rumors about a
completely innocent person.

[EDIT:] you're still wrong; in order to be equivalent to "curl | sh", x.sh or
its equivalent would have to be referenced in the "scripts" object in
"package.json".

------
askyourmother
There are some very shaky bits in the JS dev arena. Just a little earlier, we
read about how a developer unpublished his libraries from NPM, the fallout
from this affected numerous high profile projects like node.js, which were
relying on a left pad "library" that basically was a small string padding
function.

~~~
SlashmanX
This is the same story... It's a module that the developer unpublished

------
kylehotchkiss
Noticed another random package was uninstalled from NPM. Please oh please
don't let this thing become a trend.

------
spriggan3
Sorry but the elephant in the room IS the lack of namespacing. There is no
namespacing on NPM. If there were something like that this issue would have
never happened. This is not a problem of distributed vs non distributed, NPM
doesn't need a "blockchain" or whatever. Packages SHOULD by namespaced period
and any serious package manager uses namespaces. I (and many others) called it
from the very beginning and warned NPM authors that the lack of namespace
would eventually lead to this kind of issue. NPM authors didn't give a damn (
there are other issues that have been known for years but they fell on deaf
ears ). Packages should be resolved by a namespace + the name of the package.
Now everybody is in panic mode because nobody knows what one is fetching from
NPM anymore.

Now I hope NPM author will come to their senses and change the way NPM works.
But the trust is broken, no question. Between stuff like that, people selling
"realestate" on NPM for real money... Nodejs has been the least professional
platform I have ever used. Everybody's out there to make a quick buck, nobody
gives a damn, this is whole thing will collapse sooner or latter.

Finally people need to stop with the "unix philosophy" excuse. Importing 10
lines of code from a random package is not the "unix philosophy". Splitting a
100 loc module into 20 packages is not the "unix philosophy". Packages have so
many dependencies it's getting ridiculous.

edit: corrected

~~~
joslin01
Sorry, 100% agree with you but with your life going forward, it's "fell on
deaf ears"

~~~
spriggan3
Oh, sorry, I'm not a native English speaker so yeah I tend to make stupid
mistakes like these.

------
odinduty
Name squatting in those package managers is a real problem. I found this on
pypi and it was a very unpleasant surprise.
[https://sourceforge.net/p/pypi/support-
requests/571/](https://sourceforge.net/p/pypi/support-requests/571/)

------
BinaryBullet
In the root project folder (containing package.json and ./node_modules), you
can run the following:

    
    
        comm -12 <(ls ./node_modules) <(curl https://gist.githubusercontent.com/azer/db27417ee84b5f34a6ea/raw/50ab7ef26dbde2d4ea52318a3590af78b2a21162/gistfile1.txt) 
    
    

It will output any of the modules that @azer unpublished yesterday (that are
being used by your project).

~~~
BinaryBullet
NOTE: this only works for NPM 3's flat node_module structure

------
ErikAugust
Anything wrong with checking your dependencies into your repo? That way, you
know, they can't go away or be hijacked.

------
ktRolster
As a rule of thumb, if a dependency would take you less than two days to
rewrite (one day for writing, one day for testing), it's better to do it
yourself and avoid the problems of dependencies.

~~~
spriggan3
How many nodejs developers actually audit their dependencies ? In my
experience not many. it's just "npm search" without thinking. then "my problem
is somebody else now". Frankly the whole ecosystem is just scary.

------
kofejnik
PSA: you should be keeping your dependencies in git

~~~
davexunit
Bundling is _not_ the answer.

~~~
bazqux2
It worked for me. After countless injections of errors after updating a large
list dependencies we made the decision to stop updating and freeze the
versions, patch remaining errors ourselves and leave it alone. Worked so well
we now have time to rebuild the whole front end on a new stack as an
experiment instead wasting time with endless bug hunts.

~~~
davexunit
Maybe bundling is fine for your in-house proprietary software, but it's
absolutely not OK for free software where users and administrators _need_ to
keep on top of things like security updates. When projects bundle their
dependencies, users become dependent on that project to provide critical
updates to software that the project didn't even write. This multiplies for
each piece of software that bundles their dependencies. It's simply
unsustainable and irresponsible.

~~~
bazqux2
I agree. Someone making free OS software for others to use shouldn't bundle.

I made the assumption on the top post that they were in-house proprietary
software given the reference to keeping everything in git.

~~~
davexunit
I guess we're on the same page! Sorry!

