Top
Best
New

Posted by universesquid 9/8/2025

NPM debug and chalk packages compromised(www.aikido.dev)
https://github.com/advisories/GHSA-8mgj-vmr8-frr6
1372 points | 757 commentspage 5
naugtur 9/9/2025|
You too can run malware from NPM (I mean without consequences)

https://github.com/naugtur/running-qix-malware?tab=readme-ov...

alaintno 9/8/2025||
How is it possible that this code (line 9 of the index.js) isn't present in the source github repo, but can be seen in the beta feature of npmjs.com?

Also, the package 1.3.3 has been downloaded 0 times according to npmjs.com, how can the writer of this article has been able to detect this and not increment the download counter?

DDerTyp 9/8/2025||
The discrepancy comes from how npm packages are published. What you see on GitHub is whatever the maintainer pushed to the repo, but what actually gets published to the npm registry doesn’t have to match the GitHub source. A maintainer (or someone with access) can publish a tarball that includes additional or modified files, even if those changes never appear in the GitHub repo. That’s why the obfuscated code shows up when inspecting the package on npmjs.com.

As for the “0 downloads” count: npm’s stats are not real-time. There’s usually a delay before download numbers update, and in some cases the beta UI shows incomplete data. Our pipeline picked up the malicious version because npm install resolved to it based on semver rules, even before the download stats reflected it. Running the build locally reproduced the same issue, which is how we detected it without necessarily incrementing the public counter immediately.

Jenk 9/8/2025|||
It can also be that the repo was modified after a release.
alaintno 9/8/2025|||
I see, thanks for the explanations, and thanks for warning us about this!
behindsight 9/8/2025||
> How is it possible that this code (line 9 of the index.js) isn't present in the source github repo, but can be seen in the beta feature of npmjs.com

You may also be interested in npm package provenance [1] which lets you sign your npm published builds to prove it is built directly from the source being displayed.

This is something ALL projects should strive to setup, especially if they have a lot of dependent projects.

1: https://github.blog/security/supply-chain-security/introduci...

nromiun 9/8/2025||
I have nothing to do with this but still I am getting second hand embarrassment. Here is an example, is-arrayish package, 73.8 MILLION downloads per week. The code? 3 lines to check if an object can be used like an array.

I am sorry, but this is not due to not having a good standard library, this is just bad programming. Just pure laziness. At this point just blacklist every package starting with is-.

zahlman 9/8/2025||
Meanwhile in Python: 134 million weekly downloads, seemingly slowly trending upward over time, for https://pypistats.org/packages/six which provides third-party compatibility for a version of Python that dropped support over five years ago.
nromiun 9/8/2025|||
The code is 813 lines [0]. Not saying everyone should use it but these two are not directly comparable.

[0] https://github.com/benjaminp/six/blob/main/six.py

zahlman 9/8/2025||
It is much more code, but it should be even more useless. (No slight intended to Benjamin Peterson.) The 2.7 window was already extended to give everyone a chance to migrate.
rtpg 9/9/2025||||
Was a bit surprised at this, but looking into the packages in a work project that require six, a _huge_ chunk of them are packages that are still explicitly supporting Python 2.7 still (usually stuff related to operations).

I believe if you pay money to certain repo maintainers like red hat you can still have a supported version of Python 2.7.

zahlman 9/9/2025||
> a _huge_ chunk of them are packages that are still explicitly supporting Python 2.7 still

Do you know if they also support 3.x?

Do you know if they're available on PyPI?

> (usually stuff related to operations).

What kind of "operations" do you mean?

rtpg 9/10/2025||
yes they also support python 3.x, are available on PyPI, and are related to operations in the sense of like... infrastructure management and the like.

You have a huge pile of "sysop Python" out there interfacing with various infrastructure providers who are more interested in selling infra usage than getting off of Python 2.

"In order to use our new storage service via our library you need to upgrade to Python 3 first" "ehhhhhhhh kinda annoying"

That interaction has happened in the past. Time marches forward of course but.

sega_sai 9/8/2025|||
Most of these downloads, I would bet, are from CI
zahlman 9/8/2025||
Oh, I don't doubt it at all. But that doesn't make it any less depressing to me. Nor does it matter to Fastly's bandwidth burden.
junon 9/8/2025|||
I wrote it 10 years ago, I think before Node was v1, and forgot about it for a long time. This was back before we had spreads, classes, typescript, and had to use DOM arrays and other weird structures, and where `arguments` wasn't an array but an object.

    > (function() { return Array.isArray(arguments); })()
    false
discomrobertul8 9/9/2025||
Do you think it might be time to deprecate and then retire this package, given that the ecosystem has evolved? Sure, it'll mean downstream packages will need to update their reliance on `is-arrayish` and use some other means suited to their task, but perhaps that's positive design pressure?
junon 9/9/2025||
Even if I sunset those packages, they'd still be downloaded and used in perpetuity, and certainly for many years afterward, even by popular packages, and even by such packages that have removed them in newer versions. Even if I had done this five years ago, I'd wager the scope of this attack would have been similar in size - maybe a billion less, but that's still a billion with a B, at which point I really wonder if it would have mattered as much.

I agree that `is-arrayish` is silly, but that's not really the problem that needs fixing, in my opinion. There's a general, cross-language package management culture that has permeated over the last 10-15 years that is susceptible to this exact problem. It's TOTP today (in my case), something else tomorrow, and it can come to a Package Manager Near You at any time - npm is just a ripe target because of how much it's used, and how concentrated the download counts are for some of its larger packages, especially given how CI has started to operate (re-downloading everything etc).

That's just my $0.02 on it though.

quotemstr 9/8/2025|||
And at the other extreme, it takes TC39 seven years to bikeshed half of a decent implementation of Python's context managers: https://github.com/tc39/proposal-explicit-resource-managemen...

On one extreme, we have standards committees that move glacially, and on the other, we have a chaotic package ecosystem moving faster than is prudent. The two are related.

tkiolp4 9/8/2025|||
You don’t get it. People don’t add “is-arrayish” directly as a dependency. It goes like this:

1) N tiny dubious modules like that are created by maintainers (like Qix)

2) The maintainer then creates 1 super useful non-tiny module that imports those N dubious modules.

3) Normal devs add that super useful module as a dependency… and ofc, they end up with countless dubious transitive dependencies

Why maintainers do that? I don’t think it’s ignorance or laziness or lack of knowledge about good software engineering. It’s because either ego (“I’m the maintainer of N packages with millions of downloads” sounds better than “I’m the maintainer of 1 package “), or because they get more donations or because they are actually planning to drop malware some time soon.

paulddraper 9/9/2025||
I think the real answer is far less nefarious.

They personally buy into modularization, do-one-thing-do-it-well. Also engineering is fun, and engineering more things is more fun.

andrewmcwatters 9/8/2025||
Luckily this seems to be browser-specific, and not cryptocurrency malware that runs in Node.js environments, so it might be wise for us all to do some hardening on our software, and make sure we're doing things like version pinning.

Edit: As of this morning, `npm audit` will catch this.

jbverschoor 9/8/2025|
Run anything in some sort of container or sandbox
mmis1000 9/8/2025||
Seems a quite targeted attack though, the phishing domain is registered just 4 days ago.
alex_suzuki 9/8/2025||
Also reported here: https://socket.dev/blog/npm-author-qix-compromised-in-major-...
koolba 9/8/2025||
Another great example of why things like dependabot or renovate for automatically bumping dependencies to the latest versions is not a good idea. If it's not a critical update, better to let the world be your guinea pig and only update after there's been a while of real world usage and analysis. If it is a critical enough update that you have to update right away, then you take the time to manually research what's in the package, what changed, and why it is being updated.
jakub_g 9/8/2025||
Dependabot now supports "cooldown" config for this case:

https://github.blog/changelog/2025-07-01-dependabot-supports...

chuckadams 9/8/2025||
If the update isn't from a security alert, I let most dependabot PRs marinate for about a week precisely for this reason. Not the most scientific approach, but less stressful for sure.
WesolyKubeczek 9/8/2025||
Ugh, I almost had my github compromised two years ago with a phishing email from circleci dot net. Almost. The github login page still under that domain made me stop in my tracks.
mattbilson 9/9/2025|
Completely understand people getting phished.

How long before npm mandates using phishing resistant mfa? At least for accounts that can publish packages with this may downloads.

More comments...