Malicious javascript compromise on npmjs.com

These packages, about a billion downloads prior

supports-hyperlinks
chalk-template
simple-swizzle
slice-ansi
error-ex
is-arrayish
wrap-ansi
backslash
color-string
color-convert
color
color-name

Thread follows.

Example change and download stats on one of the 12 packages changed, incident started about 2 hours ago.
Example copy of one of the inserted JS: https://pastebin.com/bwLZrq02
Malicious JS in NPM libraries - Pastebin.com

Pastebin.com is the number one paste tool since 2002. Pastebin is a website where you can store text online for a set period of time.

Pastebin
Just reported to NPM, they work on it.
derekheld (@[email protected])

A bunch of packages published by qix in NPM just got backdoored it looks like. Obfuscated code was added like two hours ago. #threatintel #npm

Infosec Exchange
It's a cryptocurrency wallet drainer, RIP a load of devops dudes crypto.
NPM on it, some packages nuked, more being nuked

If you want an idea of scale of trojan attempt - 'color' alone had 32m downloads in a week, the combined attempt was pushing a billion due to upstream dependencies.

Hunt tip: look for registry.npmjs.org in proxy logs, package names are in the URLs.

additional backdoored packages

ansi-styles
debug
chalk
supports-color
strip-ansi
ansi-regex
has-ansi

Weekly download stats for impacted packages prior to incident

ansi-styles (371.41m)
debug (357.6m)
backslash (0.26m)
chalk-template (3.9m)
supports-hyperlinks (19.2m)
has-ansi (12.1m)
simple-swizzle (26.26m)
color-string (27.48m)
error-ex (47.17m)
color-name (191.71m)
is-arrayish (73.8m)
slice-ansi (59.8m)
color-convert (193.5m)
wrap-ansi (197.99m)
ansi-regex (243.64m)
supports-color (287.1m)
strip-ansi (261.17m)
chalk (299.99m)

Total 2674m

Phishing email sent to maintainers, they basically targeted people with 2FA by getting them to.. reset their 2FA.

@GossiTheDog Ooh, please change your retina every three months...

It's a pretty neat ploy though.

@GossiTheDog It's incredible that high profile targets like npm or GitHub STILL aren't enforcing Security Keys...

@leoluk @GossiTheDog Draconian systems that limit who can write and publish code are NOT the solution here.

The solution is not having LPMs (language package managers) that pull code from unvetted package repositories in an automated manner, and languages that encourage using thousands of random garbage microdependencies rather than well-vetted, versioned libraries.

@dalias @GossiTheDog Security Keys aren't draconian, they're easy to use and there's plenty of open source implementations (both software and hardware). Since LPMs aren't going to disappear overnight, they're really the only practical solution to such targeted phishing attacks.
@leoluk @GossiTheDog Mandating having a "something you have" is draconian and exclusionary of anyone who can't securely have things but can securely know things.

@leoluk @GossiTheDog We should not be placing the burden of "users don't get hit with malware" on maintainers locking down their workflows in ways that might be exclusionary or inaccessible.

Instead, the platforms that want to deliver unvetted code as part of a "supply chain" 🤮 need to get their act together and find a way that newly-published unvetted code doesn't end up as part of anyone's build, but instead goes through multiple layers of delay where it's only available to people who intend to be testing an unvetted bleeding edge and understand the dangers. With channels to request rapid review of tiny security-critical changes when needed for expediting them.

@leoluk @GossiTheDog For the most part, none of these packages have any need for new versions to appear in anyone's builds for *months* if not years after publication, unless someone *specifically* has read the changes to the new version and sees a new feature they want from it.

LPM platforms should be designed around this basic principle that updates are mostly unwanted.

The only way anyone should ever get unexpected updates is if there's a serious security problem, in which case there should be a description of the problem and a small comprehensible patch prominently displayed.

IOW LPMs and similar platforms should behave like Debian Stable.

@dalias @leoluk That approach doesn't work. Suppose you're on version X, and as time goes by versions X+1, X+2... are released. You don't upgrade.

Then they release version X+N which contains a security fix you do need. By delaying your upgrades you now have a pile of unrelated changes to include, at exactly the wrong time.

Regular Releases Reduce Risk – Government Digital Service

GOV.UK came out of beta just over two weeks ago. In that time we've released over 100 updates. I want to talk a little about how we do that, but mainly to focus on why this approach makes for more

@dalias @leoluk @GossiTheDog IBM has a vetted repository for z/OS, once again showing the mainframe in general gives a crap about security.
@dalias @leoluk @GossiTheDog at the very least, lets check GPG signatures rather than just SHA checksums
@stevel @dalias @leoluk @GossiTheDog Given they got 2FA phished, OpenPGP would solve exactly nothing, you'd get a new key with the name of the dev on it and people would just accept it at face value, remember NPM has 0 vetting.

And if you'd want to actually verify it's the correct key… good luck, almost no one makes sure to put copies of their OpenPGP keys in multiple places.
@lanodan @leoluk @GossiTheDog @stevel This. The only real solution is not putting authors in a place of directly being able to push code for immediate automatic consumption. This would have been a non issue if new versions not tagged for immediate review as security fixes and reviewed as such had a 5-10 day waiting period before they'd be pulled. I'm not saying delay is the only or necessarily best way, but you've gotta stop making these gratuitous and dangerous update channels.
@lanodan @leoluk @GossiTheDog @stevel Also let's not forget that no 2FA or signing key security theater would prevent the version of this attack where a maintainer transfers ownership to a malicious party (selling out), decides to go rogue, or whatever.
@dalias @leoluk @GossiTheDog @stevel Yeah, at best is could make it noisier, like with the developer receiving at least one email about account updates, which given the phish they could see as normal given those notifications typically don't tell you what was changed.

In fact it also reminds me that I don't think I've ever seen a website actually verify that the emails listed in the OpenPGP key can actually use said key (I would know, one of the entries in mine isn't email but my fediverse ID).
Something which has been the normal workflow for SSL/TLS certificates for decades.

@dalias @lanodan @leoluk @GossiTheDog I'd add "not need to download everything on every use", the way JS and docker runtimes like. We've grown complacent from high bandwidth downloads and the honesty of the majority of developers.

So looking forward to the first crypto-drainer attack which acquires the US treasury crypto assets and that post mortem which will follow.

@dalias @leoluk @GossiTheDog The thousands of micro dependencies thing. For real. That is the main reason I don’t touch node with a ten foot pole. Just write a dang standard library that does … like even a couple things?

@joby @leoluk @GossiTheDog Or even just copy&paste the 9 lines of code you needed!

It's about the same amount of code as the interface surface declaring the dependency you needed and binding to it - but without introducing any new interface surface or trust surface!

External dependencies that are not c&p into your own code make sense for something large and complex that's likely subject to bugs/fixes, changing requirements of third-party things they interface with, etc. Not for trivial stuff that's a couple lines of js.

@dalias @joby @leoluk @GossiTheDog

Indeed. I've been openly criticizing language built-in package managers for over a decade now. Having them encourages sloppy coding and short circuits developers' brains not to apply due diligence.

NPM, Pip, Cargo… IMHO those are inherently problematic. My personal motto in software development is: Find the dependencies and eliminate them!

@GossiTheDog

That's a clever phish.

It looks similar to requests that companies already make.

I wonder how suspicious that link looked.

@alienghic @GossiTheDog I’ve never seen a legitimate 2FA expiration, only password expirations - tho even there I usually don’t get an email, usually I log in and get sent to a change password page and find that my account is disabled until after I update my password. If I got a 2FA expired email my initial assumption would be that it’s an attack

@ShadSterling @GossiTheDog

I haven't seen a 2 factor authentication rollover email before either, but it only takes a few people to click without thinking carefully.

Github has nagged me about my reviewing my recovery codes both on the site and via email.

@ShadSterling @alienghic @GossiTheDog how would you even rotate a Yubikey, short of buying a new one?

@fazalmajid @ShadSterling @GossiTheDog

That's how you'd have to do it.

I do think Yubikey has a point that one should have a backup yubikey locked up somewhere in case you lose your primary key.

@alienghic @ShadSterling @GossiTheDog I have 6, two of which are not Yubikeys but another brand of FIDO2 hardware keys. The most important thing is you need to keep track of which keys you registered with which site, as the keys themselves can't do this due to storage space limitations, unlike passkeys.

@GossiTheDog But, but, but... They said 2FA prevented phishing!

When is 2FA not 2FA? When it is 2SV.

This npmjs phishing email led to npmjs.help. This site was a one-on-one copy of npmjs.com, even the search was functional. Fortunately, the site is offline now.

@GossiTheDog

Even I got that email and I haven't touched npm since about 2017.

@GossiTheDog

This is called spear phishing: targeting a specific person with a tailored and therefore much more credible phishing attack than the usual broad attack surface.

@GossiTheDog Links in email shouldn't be clickable without the user getting asked if they're a ducking tool who can't think for themselves.

@GossiTheDog Do you have a list of the compromised versions?

A few of these, when I check I see that the version published this morning is still present and the latest version. But a quick glance at the code and I don't see the compromise; I'm just doing a quick scan, but some of these packages are so simple that there's really not many places you could hide it:

https://www.npmjs.com/package/has-ansi?activeTab=code

I'm just trying to compile a list of compromised versions so I can do a quick scan of our systems, but for some of these I haven't been able to find an exploited version.

Maybe the attackers script failed to insert the exploit, as we do see a number of these packages all updated at the same time, but I don't see the exploit code in them. Packages fitting that pattern:

* color
* supports-color
* strip-ansi
* ansi-regex
* has-ansi

(note: all of this is based on a quick glance using the code tab on the NPM registry; it's possible that I could have missed the right file, or missed it when scanning visually, or the code tab might not be showing the version it claims, or the like)

has-ansi

Check if a string has ANSI escape codes. Latest version: 6.0.2, last published: 3 hours ago. Start using has-ansi in your project by running `npm i has-ansi`. There are 422 other projects in the npm registry using has-ansi.

npm

@GossiTheDog Here's my best attempt at a list of the bad versions:

- supports-hyperlinks 4.1.1
- chalk-template 1.1.1
- simple-swizzle 0.2.3
- slice-ansi 7.1.1
- error-ex 1.3.3
- is-arrayish 0.3.3
- wrap-ansi 9.0.1
- backslash 0.2.1
- color-string 2.1.1
- color-convert 3.1.1
- color 5.0.1
- color-name 2.0.1
- ansi-styles 6.2.2
- debug 4.4.2
- chalk 5.6.1
- supports-color 10.2.1
- strip-ansi 7.1.1
- ansi-regex 6.2.1
- has-ansi 6.0.1

Edit: updated with confirmed versions from author who was pwned: https://news.ycombinator.com/item?id=45169794

Hi, yep I got pwned. Sorry everyone, very embarrassing. More info: - https://git... | Hacker News

@GossiTheDog Also, holy hell the left-pad nature of some of these deps. Here's the entire source of has-ansi:

import ansiRegex from 'ansi-regex';

const regex = ansiRegex({onlyFirst: true});

export default function hasAnsi(string) {
return regex.test(string);
}

@GossiTheDog Looks like there's a full list on the orange site: https://news.ycombinator.com/item?id=45169657
NPM debug and chalk packages compromised | Hacker News

@GossiTheDog is this a new attack vector? Typically, I've seen attackers use the NPM install scripts to put malware on systems, and they typically leave the package code itself alone, right?
@sawaba @GossiTheDog npm install scripts are definitely the most common way. But it makes sense to hide it in the actual code as well, especially if it is used in dev dependencies and thus runs frequently on developer machines. As an example the «debug» package has ~60k dependents.

@GossiTheDog We could see that coming for a long time 😢. In a text I published in German magazine last year I even predicted that color packages would be used.

But what good did it do us to foresee it? Rather little or next to none…