Shai-Hulud malware attack: Tinycolor and over 40 NPM packages compromised

jamesberthoty | 1086 points

As a user of npm-hosted packages in my own projects, I'm not really sure what to do to protect myself. It's not feasible for me to audit every single one of my dependencies, and every one of my dependencies' dependencies, and so on. Even if I had the time to do that, I'm not a typescript/javascript expert, and I'm certain there are a lot of obfuscated things that an attacker could do that I wouldn't realize was embedded malware.

One thing I was thinking of was sort of a "delayed" mode to updating my own dependencies. The idea is that when I want to update my dependencies, instead of updating to the absolute latest version available of everything, it updates to versions that were released no more than some configurable amount of time ago. As a maintainer, I could decide that a package that's been out in the wild for at least 6 weeks is less likely to have unnoticed malware in it than one that was released just yesterday.

Obviously this is not a perfect fix, as there's no guarantee that the delay time I specify is enough for any particular package. And I'd want the tool to present me with options sometimes: e.g. if my current version of a dep has a vulnerability, and the fix for it came out a few days ago, I might choose to update to it (better eliminate the known vulnerability than refuse to update for fear of an unknown one) rather than wait until it's older than my threshold.

kelnos | 17 hours ago

This happens because there's no auditing of new packages or versions. The distro's maintainer and the developer is the same person.

The general solution is to do what Debian does.

Keep a stable distro where new packages aren't added and versions change rarely (security updates and bugfixes only, no new functionality). This is what most people use.

Keep a testing/unstable distro where new packages and new versions can be added, but even then added only by the distro maintainer, NOT by the package developers. This is where the audits happen.

NPM, Python, Rust, Go, Ruby all suffer from this problem, because they have centralized and open package repositories.

Meneth | a day ago

I'm coming to the unfortunate realizattion that supply chain attacks like this are simply baked into the modern JavaScript ecosystem. Vendoring can mitigate your immediate exposure, but does not solve this problem.

These attacks may just be the final push I needed to take server rendering (without js) more seriously. The HTMX folks convinced me that I can get REALLY far without any JavaScript, and my apps will probably be faster and less janky anyway.

codemonkey-zeta | a day ago

This vulnerability was reported to NPM in 2016: https://blog.npmjs.org/post/141702881055/package-install-scr... https://www.kb.cert.org/vuls/id/319816 but the NPM response was WAI.

paulirish | a day ago

It's crazy to me that npm still executes postinstall scripts by default for all dependencies. Other package managers (Pnpm, Bun) do not run them for dependencies unless they are added to a specific allow-list. Composer never runs lifecycle scripts for dependencies.

This matters because dependencies are often installed in a build or development environment with access to things that are not available when the package is actually imported in a browser or other production environment.

theodorejb | a day ago

When the left-pad debacle happened, one commenter here said of a well known npm maintainer something to the effect of that he's an "author of 600 npm packages, and 1200 lines of JavaScript".

Not much has changed since then. The best counter-example I know is esbuild, which is a fully featured bundler/minifier/etc that has zero external dependencies except for the Go stdlib + one package maintained by the Go project itself:

https://www.npmjs.com/package/esbuild?activeTab=dependencies

https://github.com/evanw/esbuild/blob/755da31752d759f1ea70b8...

Other "next generation" projects are trading one problematic ecosystem for another. When you study dependency chains of e.g. biomejs and swc, it looks pretty good:

https://www.npmjs.com/package/@biomejs/biome/v/latest?active...

https://www.npmjs.com/package/@swc/types?activeTab=dependenc...

Replacing the tire fire of eslint (and its hundreds to low thousands of dependencies) with zero of them! Very encouraging, until you find the Rust source:

https://github.com/biomejs/biome/blob/a0039fd5457d0df18242fe...

https://github.com/swc-project/swc/blob/6c54969d69551f516032...

I think as these projects gain more momentum, we will see similar things cropping up in the cargo ecosystem.

Does anyone know of other major projects written in as strict a style as esbuild?

homebrewer | a day ago

I set "ignore-scripts=true" (https://docs.npmjs.com/cli/v11/using-npm/config#ignore-scrip...) in npmrc(5). This changed the defaults for npm(1).

The Semgrep blog under "Additional NPM Registry Security Advice / Reducing Run Scripts" says "reducing" not "ignoring". I need to check if there are still "run scripts" even with this setting.

Also I need to check if there is the same class of vulnerabilities in other package managers I use, like emacs(1) (M-x package-install), mvn(1) (Maven, Java), clj(1) (deps.edn, Clojure), luarocks(1) (Lua), deps(1) (deps.fnl, Fennel), nbb(1) (deps.edn, Node.js babashka). Although some do not have "run scripts" feature, I need to make sure.

david-james-2 | 4 hours ago

I try to stay as far from web development as possible in my programming career (kernel/drivers and most recently reverse engineering) so maybe I'm ill-informed here but this npm thing seems to be uniquely terrible at security and i cannot fathom why the entire web seems to be automatically downloading updates from it and pushing them into production with no oversight.

I've always worked at companies where we use third party open source libraries utilities and its true that they get less-than-ideal amount of auditing when they get updated but at least we're not constantly pushing updates of to our customers solely for the sake of using the latest version. In fact usually they're out of date by several years which is also a problem but generally there'll be a guy following the mailing lists for updates in case there's a known exploit that needs to be patched.

snickerbockers | 7 hours ago

In the story about the Nx compromise a few weeks ago someone posted a neat script that uses bubblewrap on Linux to run tools like npm more safely by confining their filesystem access. https://news.ycombinator.com/item?id=45034496

I modified the script slightly based on some of the comments in the thread and my own usage patterns:

  #!/usr/bin/env bash
  #
  # See: https://news.ycombinator.com/item?id=45034496
  
  bin=$(basename "$0")
  
  echo "==========================="
  echo "Wrapping $bin in bubblewrap"
  echo "==========================="
  
  exec bwrap \
    --bind ~/.cache ~/.cache \
    --bind "${PWD}" "${PWD}" \
    --dev /dev \
    --die-with-parent \
    --disable-userns \
    --new-session \
    --proc /proc \
    --ro-bind /etc/ca-certificates /etc/ca-certificates \
    --ro-bind /etc/resolv.conf /etc/resolv.conf \
    --ro-bind /etc/ssl /etc/ssl \
    --ro-bind /usr /usr \
    --setenv PATH /usr/bin \
    --symlink /usr/bin /bin \
    --symlink /usr/bin /sbin \
    --symlink /usr/lib /lib \
    --symlink /usr/lib64 /lib64 \
    --tmpfs /tmp \
    --unshare-all \
    --unshare-user \
    --share-net \
    /usr/bin/env "$bin" "$@"
Put this in `~/.local/bin` and symlink it to `~/.local/bin/npm` and `~/.local/bin/yarn` (and make sure `~/.local/bin` is first in your `$PATH`). I've been using it to wrap npm and yarn successfully in a few projects. This will protect you against some attacks that use postinstall scripts to do nefarious things outside the project.
aorth | 8 hours ago

According to Aikido Security the attack has now targeted 180+ packages: https://www.aikido.dev/blog/s1ngularity-nx-attackers-strike-...

chillax | a day ago

I wonder who actually discovered this attack? Can we credit them? The phrasing in these posts is interesting, with some taking direct credit and others just acknowledging the incident.

Aikido says: > We were alerted to a large-scale attack against npm...

Socket says: > Socket.dev found compromised various CrowdStrike npm packages...

Ox says: > Attackers slipped malicious code into new releases...

Safety says: > The Safety research team has identified an attack on the NPM ecosystem...

Phoenix says: > Another supply chain and NPM maintainer compromised...

Semgrep says: > We are aware of a number of compromised npm packages

cddotdotslash | a day ago

It's probably not trivial to implement and there's already a bunch of problems that need solving (e.g., trusting keys etc.) but... I think that if we had some sort of lightweight code provenance (on top of my head commits are signed from known/trusted keys, releases are signed by known keys, installing signed packages requires verification), we could probably make it somewhat harder to introduce malicious changes.

Edit: It looks like there's already something similar using sigstore in npm https://docs.npmjs.com/generating-provenance-statements#abou.... My understanding is that its use is not widespread though and it's mostly used to verify the publisher.

kafrofrite | 15 hours ago

> Shai Hulud

Clever name... but I would have expected malware authors to be a bit less obvious. They literally named their giant worm after a giant worm.

> At the core of this attack is a ~3.6MB minified bundle.js file

Yep, even malware can be bloated. That's in the spirit of NPM I guess...

GuB-42 | a day ago

I think these kinds of attack would be strongly reduced if js had a strong standard library.

If it was provided, it would significantly trim dependency trees of all the small utility libraries.

Perhaps we need a common community effort to create a “distro” of curated and safe dependencies one can install safely, by analyzing the most popular packages and checking what’s common and small enough to be worth being included/forked.

kace91 | a day ago

Letting upstream authors write code that the package manager runs at install time isn't a sane thing for package managers to allow. It promotes all kinds of hacky shit and makes packages harder to work with programmatically, and it also provides this propagation vector. Packages also shouldn't have arbitrary network access at build time for both of those two same reasons!

There's been a lot of talk here about selecting and auditing dependencies, which is fine and good. But this attack and lots of other supply chain attacks would also be avoided with a better-behaved package manager. Doesn't Deno solve this? Do any other JS package managers do some common-sense sandboxing?

Yes, migration is painful. Yes, granular permissions are more annoying to figure out than anything-can-do-anything. But is either as painful as vendoring/forking your dependencies without the aid of a package manager altogether? If you're really considering just copying and pasting instead of using NPM, maybe you should also consider participating in a saner package ecosystem. If you're ready to do the one, maybe you're ready to do the other.

pxc | 8 hours ago

Is there any way to install CLI tools from npmjs without being affected by a recent compromise?

Rust has `cargo install --locked`, which will use the pinned versions of dependencies from the lockfile, and these lockfiles are published for bin packages to crates.io.

But it seems npmjs doesn't allow publishing lockfiles, neither for libraries nor for CLI tools, so if you try to install let's say @google/gemini-cli, it will just pull the latest dependencies that fit the constraints in package.json. Is that true? Is it really this bad? If you try to install a CLI tool on a bad day when half of npmjs is compromised, you're out of luck?

How is that acceptable at all?

Liskni_si | 20 hours ago

Last week someone wrote a blog post saying "We dodged a bullet" because it was only a browser-based crypto wallet scrape

Guess we didn't dodge this one

brundolf | a day ago

I knew npm was a train wreck when I first used it years ago and it pulled in literally hundreds of dependencies for a simple app. I avoid anything that uses it like the plague.

jbd0 | a day ago

New Npm vuln? Other shocking news: today is Tuesday

huem0n | 35 minutes ago

For years everyone in the programming community has been pushing for convenience and features and code reuse and its got to the point I think the ease of adding a third party package from the languages package manager or github needs to be seriously questioned by security conscious devs. Perhaps we made the wrong things easy.

shirro | 9 hours ago

You guys win, JS is actually fantastic and this headline is great.

user3939382 | an hour ago

Isn’t this a good case for LLMs? Audit at compile time all of the dependencies?

whatever1 | an hour ago

So, other packaging environments have a tendency to slow down the rate of change that enters the user's system. Partly through the labor of re-packaging other people's software, but also as a deliberate effort. For instance: Ubuntu or RedHat.

Is anyone doing this in a "security as a service" fashion for JavaScript packages? I imagine a kind of package escrow/repository that only serves known secure packages, and actively removes known vulnerable ones.

pragma_x | 16 hours ago

Related (7 days ago):

NPM debug and chalk packages compromised (1366 points, 754 comments): https://news.ycombinator.com/item?id=45169657

redbell | a day ago

Warning: LLM-generated article, terribly difficult to follow and full of irrelevant details.

thegeomaster | a day ago

We've seen many reports of supply chain attacks affecting NPM. Are these symptoms of operational complexity, which can affect any such service, or is there something fundamentally wrong with NPM?

gchamonlive | a day ago

My main takeaway from all of these is to stop using tokens, and rely on mechanisms like OIDC to reduce the blast radius of a compromise.

How many tokens do you have lying around in your home directory in plain text, able to be read by anything on your computer running as your user?

madeofpalk | a day ago

Yes, cybersecurity is absolutely a cost center. You can pay for it the easy way, the hard way, or the very hard way. Looks like we're fixing NPM the very hard way.

1970-01-01 | 18 hours ago

Blog author company's runner detects anomalies in them, but we shouldn't need a product for this.

Detecting outbound network connection during an npm install is quite cheap to implement in 2025. I think it comes down to tenant and incentives, if security is placed as first priority as it should, for any computing service and in particular for supply chain like package management, this would be built in.

One thing that comes to mind that would make it a months long deabte is the potential breakage of many packages. In that case as a first step just make an eye catching summary post install, with gradual push to totally restriction with something like a strict mode, we've done this before.

Which, reminds me of another long standing issue with node ecosystem toolings, information overload. It's easy to bombard devs with thesis character count then blame them for eventually getting fatigue and not reading the output. It takes effort to summarize what's most important with layered expansion of detail level, show some.

utbabya | 12 hours ago

Anyone know if there is a public events feed/firehouse for npm ecosystem system? Similar to GitHub public events feed?

We, at ClickHouse, love big data and it would be super cool download and analyse patterns of all these data & provide some tooling to help with combatting this wide spread issue.

ebfe1 | 20 hours ago

NPM belongs to Microsoft. What kind of security do you expect?

amai | 2 hours ago

Languages/VMs should support capability-based permissions for libraries, no library should be able to open a file or do network requests without explicit granular permissions.

nahuel0x | a day ago

post-install seems like it shouldn't be necessary anyway, let alone need shell access. What are legitimate JS packages using this for?

philipwhiuk | a day ago

This seems like a great opportunity for someone to push a smaller but fully audited subset of the npm repos.

Corporations would love it.

joelthelion | 7 hours ago

Be accountable for what deploy if paid, except explicit other deal. Like in real jobs. Next...

enricotr | an hour ago

So glad I left JS for backend last year. It was a big effort switching to a new language and framework (still is) but it looks like so far the decision was worth it.

I'm still looking at Bun and all the effort they're doing with built-in APIs to reduce (and hopefully eliminate) third party deps. I would prefer using TS for the whole stack if possible but not at the expense of an insecure backend ecosystem.

pier25 | 17 hours ago

Code signing, 2FA, and reducing dependencies are all incomplete solutions. What we need is fine-grained sandboxing, down to the function and type level. You will always be vulnerable as long as you're relying on fallible humans (even yourself) to catch or prevent vulnerabilities.

Apparently they've tried to implement this in JavaScript but the language is generally too flexible to resist a malicious package running in the same process.

We need to be using different languages with runtimes that don't allow privileged operations by default.

cyrnel | 11 hours ago

I’m not sure language package mangers were a good idea at all. Dependencies were supposed to be painful. If the language needed some functionality built in it was supposed to go into the standard library, I understand that for JS this isn’t feasible.

hacker_homie | 14 hours ago

I was just reading an article in Foreign Affairs that was discussing a possible future with an increased separation of science and technological developments between China and The West. And it occurred to me, what would such a siloed landscape mean for OSS and basically the whole web infrastructure as it is today, shared and open for anyone in any country. I think this kind of malware becoming pervasive could be the failure state if this future becomes reality.

totetsu | 12 hours ago

My problem is that, in the JS ecosystem, every single time you go through a CI/CD pipeline, you redownload everything. We should only download the first time and with the versions that are known to work. When we make a manual update to version, than only that should be downloaded once more.

I just checked one of our repos right now and it has a 981 packages. It's not even realistic to vet the packages or to know which one is compromised. 99% of them are dependencies of dependencies. Where do we even get started?

foxfired | 15 hours ago

How many packages now have been compromised over the past couple of weeks? The velocity of these attacks are insane. Part of me believes state actors must be involved at this point.

In any case, does anyone have an exhaustive list of all recently compromised npm packages + versions across the recent attacks? We need to do an exhaustive scan after this news...

zelias | a day ago

Ironically I started seeing a message in GitHub saying 2fa will be auto-enforced shortly. Wonder if that is a sign of similar for npm packaging?

Or wonder if GitHub is enforcing 2fa soon because of the NPM CVEs potential to harvest GitHub creds?

indigodaddy | 18 hours ago

NPM needs some kind of attestation mechanism. There needs to be an independent third party that that has the fingerprint, and then npm must verify it before a change is published. It could even be just DNS or well-known URI that, if changed, triggers lockdown. Then, even in the case of a successful compromise of an NPM account or source control, whether via phishing like the last one or token exfiltration like this one, it will remain unpublished.

ibejoeb | 14 hours ago
[deleted]
| 11 hours ago

I haven't dug into the specifics but technical props and nostalgia to the "self propagating" nature. Reminds of the OG "Worm" - the https://en.wikipedia.org/wiki/Morris_worm

keepamovin | a day ago

Maybe stupid question here. And forgive my ignorance.

But does yarn or deno suffer from the same issues? That is do they get their packages from npm repositories? I've never used these.

racl101 | 18 hours ago

For a large subset of packages (like the browser ones), as a layman, it seems feasible to do static analysis for:

1) fetch calls

2) obfuscation (like sketchy lookup tables and hex string construction)

Like for (1) the hostname should be statically resolvable and immutable. So you can list the hostnames it fetches from as well.

Is this feasible or am I underestimating the difficulty? Javascript seems to have no shortage of static analysis tools.

parhamn | 15 hours ago

Wow it got everything, aws keys, gcp keys, github tokens, thats a lot of cryptocoin mining instances that are going to be spun up. And a lot of unexpected bills people are going to be getting...

They really shouldn't have been stored unencrypted on peoples machines.... Ouch.

DarkmSparks | 12 hours ago

At this time should we just consider all of npm unsafe for installing new packages? Installing a single package could install hundreds of transient dependencies.

illusive4080 | 17 hours ago

Just notice guys it did not started with tinycolor. I had first reported it here, I am just not as popular haha

My posts way before the issue was created: https://news.ycombinator.com/item?id=45252940 https://www.linkedin.com/posts/daniel-pereira-b17a27160_i-ne...

danieldspx | a day ago

For those of you without a security dept, hopefully this is of some help: https://github.com/Cobenian/shai-hulud-detect

more updates soon and PRs welcome.

MonkeyIsNull | 12 hours ago

I guess it's still spreading? those blogs seem to list differences packages

liveoneggs | a day ago

It's amazing how we attack normies for downloading random software but we will load our projects with hundred of dependencies we don't audit ourselves.

2OEH8eoCRo0 | 16 hours ago

Each one of these posts makes me feel better about having no dependencies on my current project, other than Gulp, which I could replace if I had to.

But also I miss having things like spare time, and sleep, so perhaps the tradeoff wasn't worth it

ayaros | 16 hours ago

Perhaps set `minimumReleaseAge > 1440` in pnpm config until this is fixed.

swatkat7 | 15 hours ago

I'm surprised this is happening now, and not 10 years ago.

lxe | 15 hours ago

The number of packages is now up to 180 (or more, depending on which source you're looking at)

achristmascarl | 21 hours ago

Are Python packaging systems like pip exposed to the same risks?

Is anybody looking at this?

g42gregory | 19 hours ago

Soon we'll see services like, havemysecretsbeenpwned.com check it against with your secrets xD given the malw seeks local creds.

To my experience 80% of companies do not care about their secrets will/being exposed.

There is this shallow belief that production will never be hacked

simultsop | a day ago

Does anyone know when @ctrl/tinycolor 4.1.1 was released exactly? Trying to figure out the infection timeline relative to my tools.

foobarbecue | 16 hours ago

Would strict containerization help here? (rootless, read-only partial fs access, only the necessary env variables passed, etc)

zemlyansky | 16 hours ago

It's high time we took this seriously and required signing and 2FA on all publishes to NPM and NPM needs to start doing security scanning and tooling for this that they can charge organisations for.

deanc | a day ago

I wouldn't mind a simple touch id (or password) requirement every time I run `npm publish` to help prevent such an attack.

herpdyderp | 18 hours ago

As a developer, is there a way on mac to limit npm file access to the specific project? So that if you install a compromised package it cannot access any data outside of your project directory?

pingou | a day ago

Why did the socket.dev story from last night get flagged off the front page?

https://news.ycombinator.com/item?id=45256210

seanieb | a day ago

npm considered harmful

kklisura | a day ago

This blog post and others are from 'security saas' that also try to make money off how bad NPM package security safety is.

Why can't npm maintainers just implement something similar?

Maybe at least have a default setting (or an option) that packages newer than X days are never automatically installed unless forced? That would at least give time for people to review and notice if the package has been compromised.

Also, there really needs to be a standard library or at least a central community approved library of safe packages for all standard stuff.

gg2222 | a day ago

I had just seen some guy on TikTok pushing `mcp-knowledge-graph` the other day

diffrinse | 16 hours ago

This is a product of programming languages continuing to ignore the lessons from capability security. The fact that packages in your programming language even have the ability to any of the things listed in these articles by default is an embarrassing, abject failure of our profession.

naasking | 17 hours ago

This seems like something that can be solved with reproducible builds and ensuring you only deploy from a CI system that verifies along the way.

In fact this blog post appears to be advertising for a system that secures build pipelines.

Google has written up some about their internal approach here: https://cloud.google.com/docs/security/binary-authorization-...

ants_everywhere | a day ago

Is there a theoretical framework that can prevent this from happening? Proof-carrying code?

l___l | a day ago

Time for a Butlerian Jihad.

easterncalculus | 11 hours ago

At least they're not re-inventing the wheel though!!

LAC-Tech | 13 hours ago
[deleted]
| a day ago

> It deliberately skips Windows systems

Reminds me of when I went to a tech conference with a Windows laptop and counted exactly two like me among the hundreds of attendees. I was embarrassed then but I'd be laughing now :D

mrbluecoat | a day ago

Related:

Active NPM supply chain attack: Tinycolor and 40 Packages Compromised

https://news.ycombinator.com/item?id=45256210

ChrisArchitect | a day ago

I have been telling people for ages - Javascript is a pack of cards. We have progressed as a society and have so many alternatives for everything, and yet, we still haven't done anything about Javascript being forced down onto us by browsers. If it wasn't for web browsers, JS would have become irrelevant so fast because of how broken it is - both as a language and its ecosystem.

On the contrary - almost being a decade into Elixir - most of the time, I don't need (and I don't like) using external dependencies. I can just write something myself in a matter of just an hour or so because it's just so easy to do it myself. And everything I've written till date hasn't required an audit or re-write every 6 months or sometimes, even for years.

We all seem to hate the concept of Nazis and yet somehow we have done nothing about the Nazi-est language of them all which literally has no other alternatives to run on web browsers?

neya | 13 hours ago
[deleted]
| 16 hours ago

Unless npm infrastructure will be thoroughly curated and moderated, it always going to stay a high risk threat.

cynicalsecurity | a day ago

Need to stop using javascript on desktop ASAP. Also Rust might be a bit dangerous now?

ozgrakkurt | a day ago

Jesus Christ. Another one? What the fuck?

This isn't a JavaScript problem. What, structurally, stops the same thing happening to PyPI? Or the Rust ecosystem? Or Lisp via QuickLisp? Or CPAN?

This whole mess was foreseeable. So what's to be done?

Look. Any serious project needs to start vendoring its dependencies. People should establish big, coarse grained meta-distributions like C++ Boost that come from a trustable authority and that get updated infrequently enough that you can keep up with release notes.

quotemstr | a day ago

Is using any type of NPM type stuff a no go? Who reads the code and verifies is secure?

m3kw9 | 21 hours ago

npm should be banned and illegal to work with.

devwastaken | 17 hours ago
[deleted]
| a day ago

New day, new npm malware. Sigh..

freakynit | a day ago

[dead]

OfficeChad | 16 hours ago

Another day, another npm compromise

Time to add developer ID's verification /s

flykespice | 12 hours ago

[flagged]

sim7c00 | 17 hours ago

Bless the maker and his water.

perdomon | a day ago

My comment yesterday, which received one downvote and which I will repeat if/until they’re gone: HTTP and JS have to go. There are ways to replace them.

user3939382 | a day ago