NPM packages from Red Hat have been compromised(github.com) |
NPM packages from Red Hat have been compromised(github.com) |
Updated:
1. All exploitation techniques used since May 2025: https://npm-supply-chain-attack-techniques.pagey.site/
2. All attacks that happened since May 2025: https://npm-supply-chain-attacks-25-26.pagey.site/
You pay red hat for compliance reasons (availability of a support you'll never call, mostly).
Edit: some people don't understand that it's a defence to https://en.wikipedia.org/wiki/%27No_Way_to_Prevent_This,%27_...
That's an INSANE default. pnpm, by contrast, allows you to essentially "opt-in" only specific packages that need this (e.g. four out of thirty, in one of our projects). Then tacks on tons of other security settings, like minimum age, no trust downgrade, etc etc.
All attackers can attack packages by updating how a package functions; but npm is particularly problematic as it runs non-sandbox scripts as the calling user. Putting not just your project at risk, but your entire machine/network.
And this stuff has been known about for YEARS, they've taken no action.
As opposed to the completely untrusted package supplied arbitrary code that the logged in user executes when they actually use the package immediately after installing it?
In about 99% of cases, I have the option to pick between Microsoft, a 3rd party or myself. I'm picking that first option every time I can. If M$ can't handle it, I'm hand rolling it.
Dapper remains the only constant 3rd party dependency in my projects. I don't know how much longer this will last with LLM assistance. The frontier models are very good at writing repositories over arbitrary sql schemas with low level primitives now.
Regarding npm CLIENTS, PNPM is fundamentally different from (and superior to) npm or yarn.
Strongest possible recommendation to use pnpm.
It's also a good idea to use a private registry (eg via jfrog), acting as a proxy / pull-through cache, and point trad SAST and maybe AI scanners at it.
But dropping the npm client in favor of pnpm is a no-brainer. Speed, disk space, security, determinism, flexibility, fine-grained control over your dependency graph...
This makes it so an update to a popular library can compromise a huge number of packages that depend on it.
In Java for example almost all packages specify a concrete version, even if someone compromises the latest the blast radius is usually pretty small.
Between average hackers and extortion groups, foreign governments and state sponsored actors and last but not least my own government, I don't think there's much room left for non-compromised supply chains these days. Treat everything that can run foreign code as potentially compromized and keep everything compartmentalized. If you keep your crypto wallets or private banking info on the same machine where you do development, you're asking to get shafted one day. Or if you keep your big corporate github keys on the same machine where you do private weekend projects. It doesn't matter what you use in particular, even if some vectors are currently more popular than others.
pnpm can still be exposed, afterall the worm simply have to wait you run tests locally.
Not running lifecycle scripts by default is eventually going to be the default behavior. Late is worse (edit: I meant better) than not at all. https://github.com/npm/rfcs/pull/868
This is semi-common and in no way unique to NPM.
It's also the standard, and by far it's the contrast to not allow this. pnpm has a massive advantage of being the non-standard package manager, npm does not have that - what do you suggest that npm does?
It's not unreasonable: you're already installing software, which presents risks. If post-install scripts were not a thing, a payload could still run because you ran the software you installed. Or because the installer added it to auto-run. Or because the installer placed it somewhere where it would be dynamically loaded all the time.
Cargo,PyPi,Nuget,PHP has had these recent too.
It's not just only NPM. It's frequently repeated here just cause of the average bias against Node.
But this problem isn't isolated to NPM.
It’s frequently repeated here because NPM is where it keeps happening over and over and over and over and over and over again.
Crates.io, May 22 [2]
Composer, May 22 [3]
[1] https://www.tenable.com/blog/mini-shai-hulud-frequently-aske...
[2] https://socket.dev/blog/trapdoor-crypto-stealer-npm-pypi-cra...
[3] https://phoenix.security/laravel-lang-composer-supply-chain-...
So, explicitly:
- pip
- Cargo
- apt/dpkg
- dnf/yum
- Homebrew
- RubyGems
- Composer (limited)
- Maven
...all allow scripts.
We understand the reference, it's just not correct: most package managers allow scripts, npm is the most successful package manager.
npm shouldn't allow scripts, but exploits happen everywhere.
Also not all maintainers always pull in the latest upstream changes, only rebasing to new stable release or when the new features or fixes are actually needed for the distro stack.
Definitely not bulletproof but still IMHO more robust than "Lets just spray latest code from upstream without any review directly to production with a firehose!" that seems to be the norm.
Got downvoted for saying it too. Don't let it discourage you.
You bring up a good point that this class of problem, or related ones can occur with other package managers. It was frustrating how long it took the Crates.io team (Rust manager) to address name squatting, in what appeared to be a "no perfect solution exists, so we won't act" line of reasoning.
Indeed, AUR is bad as a software distribution mechanism (really it's best understood as a proving ground for baby packages before they get real maintainers and distro blessing), but it's less bad than NPM which puts the malware in the trusted/default/automated path.
(Everyone claps.)
How do you propose we address this issue? Instead of policing what people say, are you interested in sharing your or someone else ideas?
https://gist.github.com/mcollina/b294a6c39ee700d24073c0e5a4e...
It does make sense that the right way would be to fork every dependency you use and install from your own repo reviewing and merging from upstream as needed. Would be a giant PITA though. :)
https://www.stepsecurity.io/blog/multiple-redhat-cloud-servi...
1. Dependency cooldowns of 1-2 days seem to be extremely effective without negatively impacting your ability to patch for CVEs.
2. Anywhere you have `npm install` or `npm test` or anything where code executes, that should happen in an environment that has no privileges. In your github actions you can do this semi-straightforwardly by using two separate jobs - one to build the artifacts and test them, another to do any sort of publishing, signing, etc. If you use AI, add a skill / guidance to enforce this pattern.
3. If you use Github Actions, install the latest version of zizmor. It will significantly improve your posture.
(2) means that you are no longer "wormable", which is a massive part of the problem that we have today. (1) gives companies more time to respond to the attacks.
There are some vendors in this space that you can and should evaluate as well.
Thankfully, it's on by default since v11.
0: https://github.com/lovell/sharp/blob/main/install/build.js
Though I would expect that Insights uses RPM packages to ship components and not the public NPM packages.
AbstractFinalFactoryShaiHuludSerialisedFactoryI know of fundamental issues with JavaScript and see no reason why it's still standard on all web browsers.
So if you have an unpinned version of this package and you run 'npm install', you immediately downloaded the compromised version and that's that.
[0] https://github.com/RedHatInsights/javascript-clients/commit/...
This however is only to some degree the package manager's fault. The JavaScript culture is strongly ordering tiny packages by individual people doing small things (left pad) rather than larger utilit libraries maintained by a larger community.
A larger community contributing to a larger library would mean that a larger community feels responsible and checks it.
That small package mentality a trace to web usage: JavaScirpt code is often sent to the client, not having a huge library but having small dedicated libraries means that it is a lot simpler for the bundler to not bundle dead code which is sent to the browser client.
With server side Node.js this lead to tons of dependencies ... which is worsened by npm allowing to have multiple versions of the same package in parallel. So if something depends on leftpad 1.0 and something else in leftpad 1.1 both are fetched and both are available.
IIRC 6 years ago the full dependency tree congealed into more than 2000 packages. One small example is React itself:
- 5 deps: https://www.npmjs.com/package/react/v/15.6.2
- 0 deps: https://www.npmjs.com/package/react/v/19.2.6
Another is switching from create-react-app with its hundreds of transitive dependencies to vite, which, according to the test I've ran just now, currently has 15. Etc.
IME dotnet dependency situation is a tire fire, not a month goes by without another dependency biting the dust or going fully commercial with no notice. Which is fair, I suppose, but Go and Java ecosystems don't have it nearly as bad.
It could require a 48 hour cooldown period on any package update that wants to add an install script that didn't have one before, and has a certain number of downloads. And it could publish the list of these so security researchers have an opportunity to scan them.
It could add an optional key to package.json that allows someone to whitelist which packages can run install scripts.
It could add a Hardened Security program where (1) package maintainers could opt into a program where multi-factor confirmation by maintainers is required on every publish, even those triggered by CI; (2) this hardened package status would be public, and (3) a developer could set a flag in their package.json that causes any npm action to act as if all non-hardened packages had frozen versions.
And so much more.
> It could add a Hardened Security program where (1) package maintainers could opt into a program where multi-factor confirmation by maintainers is required on every publish, even those triggered by CI;
Great, they did this.
> And so much more.
This shit takes time. Yes, they should have done this on day 1. Acting like any of this is easy to retrofit is just nuts though.
1. Lifecycle Hook Execution
2. CI/CD Identity Plane Attacks
3. Maintainer Account Takeover and Malicious Publish
4. Self-Replicating npm Worms
Right now you could audit packages and make sure you don’t get the latest version
Mirror. Buy one.
If there's some change that must get out sooner, then there can be some fee to pay to npm to have their security team do their own review.
Critically, there must be time for someone to review before it's the default to be selected.
I'm sure there are issues with this, this was off my head, but it seems like a really easy step to at least stem the problem for now. And there are a bunch of ideas like this that would help, but NPM doesn't seem willing to take it seriously as an existential threat to the ecosystem, rather than taking trivial steps.
> Critically, there must be time for someone to review
By who? No one at npm is reviewing anything. "Someone" is doing a lot of work here.
Linux distributions have trusted maintainers who are responsible for their packages. People who cared enough to figure out PGP and set up an actual web of trust. That's where the verification happens. All these programming language package managers have nothing of the sort. PyPI, Rubygems, crates, npm, it doesn't matter. I can just make an account and push whatever I want.
These package managers are like this because that's what developers actually want. They don't want to deal with Linux distribution maintainers in order to get their software into the official repositories. They want to just run $packager push and have it out there with zero friction.
They're spreading cheap disdain & scorn for npm ("only package manager" framing). But most other package management systems have similar abilities to run pretty un-sandboxed code.
TrapDoor has hit python, rust, and js repos. https://socket.dev/blog/trapdoor-crypto-stealer-npm-pypi-cra...
`pip install --uploaded-prior-to P7D pre-commit`
https://pip.pypa.io/en/stable/cli/pip_install/#cmdoption-upl...
huh? what do you suggest instead?
There is something to be said that Microsoft should be scanning packages pre-release. They aren't, though, so for right now there is a ton of value with very little downside if people implement a one week cooldown period.
To answer your question directly, though. If everyone else moves to a one week cooldown, I would absolutely suggest a two week cooldown is a good idea. Being the "slow" moving organization is a good security trade-off so long as you don't take it to extremes and have escape hatches when you actually need to be moving quickly.
That is, at least what we do, in theory. In practice, we cross fingers and let the LLM pick dependencies, are satisfied if it just works and we either update our deps frequently or infrequently.
I even managed to make that part of the workflow on one team I worked with but several other teams since thought it was a crazy idea. :)
The comment I replied to is a literal meme. That's as charitable as it gets. Nothing "thought-terminating" about it.
It does not. Opening a project in an IDE has always been dangerous because there are about a thousand language server and analysis tools that run in the background. This is why IDEs ask you whether you trust the contents of a repository.
An even if some automated background execution initiated by the IDE doesn't get you, running `npm run test` 15 seconds later will.
We need to ensure we don't just blindly install the latest, patch every CVE by just bumping everything to the latest even if the vulnerability has nothing to do with their system or use of said library.
We should have rules that we install the latest that's older than three days.
We should be running "npm audit" and other stuff like Trivy.
The three day rule alone could save most people.
* The JS ecosystem has been and will most likely continue to be fast-moving, so it's quite a safe assumption that at no point will a quarantine period be wide-spread.
* This quarantine period is for (semi-)automated scanners to catch the issue. Although considering the above there will always be a non-zero amount of end-user canaries as well.
* Maybe NPM should run scanners before distributing malware?
* If the ecosystem by any chance adopts a week-long quarantine period, you'd be safer if you applied a longer quarantine period.
To give you a context, I get 20-30 PRs a week across all my repos with potentially hundreds of packages (non distinct) from dependabot. I give it a cursory look and try to get a summary of changes. Do I evaluate every single package update? Nope.
None of this is to say I think Microsoft shouldn't be doing something as part of the release process on NPM. However, there is real value in giving more independent third parties a window to do things semi-manually.
https://news.ycombinator.com/item?id=45041798
If you only ever use js/ts for frontend projects (like we do), it closes one major hole that I'm aware of, which still leaves at least two:
- the editor possibly starting random binaries from inside the mode_modules (such as biome, vitest, tsgo)
- escape from sandbox by using some kernel vulnerability, of which there have been many recently
But that's a "Perfect is the enemy of good"-like argument. Wherein: Why even reduce an easy to exploit attack surface when there could be holes elsewhere?! Because, you know, it makes things much more secure even if imperfect.
Plus, to me, it is a culture issue. npm just doesn't take security seriously, so we don't see these improvements, and if there was additional test hardening later, I don't expect we'd see them in npm either. Since, they just don't care.
Meanwhile in the nuget ecosystem is way smaller and have way less mainteners involved for a single given dependency.
Really the reason not to allow that is for robustness, not security. You ideally don't want package installs doing random stuff to your system because package authors are generally bad at doing that sort of thing cleanly.
The security impact is relatively minimal because as other people have said, you just installed a package. What's the very next thing you're going to do? Compile/run it obviously.
You're collapsing two different threat models. The risk isn't that code runs, it's WHEN it runs. This worm spreads because npm install runs arbitrary scripts as you, automatically, just from resolving the tree. You don't have to build it, run it, or even import it. Opening the project in an IDE is enough. apt/dnf scripts run on packages a maintainer signed and a distro gatekept. Not on whatever some rando pushed to a public scope 20 minutes ago that landed in your lockfile six levels deep. "They both technically execute code" is true and beside the point. One runs signed code from a trusted path, the other runs unsigned code from the default automated path. That's the whole ballgame.
> You don't have to build it, run it, or even import it
If you just installed something with npm, chances are you'll be running it shortly, either as a tool or a library, probably minutes or seconds later. I imagine the use cases of explicitly install an npm package you don't plan on using, constitute a small portion of npm installs.