NPM debug and chalk packages compromised
aikido.dev
aikido.dev
More info:
- https://github.com/chalk/chalk/issues/656
- https://github.com/debug-js/debug/issues/1005#issuecomment-3...
Affected packages (at least the ones I know of):
- ansi-styles@6.2.2
- debug@4.4.2 (appears to have been yanked as of 8 Sep 18:09 CEST)
- chalk@5.6.1
- supports-color@10.2.1
- strip-ansi@7.1.1
- ansi-regex@6.2.1
- wrap-ansi@9.0.1
- color-convert@3.1.1
- color-name@2.0.1
- is-arrayish@0.3.3
- slice-ansi@7.1.1
- color@5.0.1
- color-string@2.1.1
- simple-swizzle@0.2.3
- supports-hyperlinks@4.1.1
- has-ansi@6.0.1
- chalk-template@1.1.1
- backslash@0.2.1
It looks and feels a bit like a targeted attack.
Will try to keep this comment updated as long as I can before the edit expires.
---
Chalk has been published over. The others remain compromised (8 Sep 17:50 CEST).
NPM has yet to get back to me. My NPM account is entirely unreachable; forgot password system does not work. I have no recourse right now but to wait.
Email came from support at npmjs dot help.
Looked legitimate at first glance. Not making excuses, just had a long week and a panicky morning and was just trying to knock something off my list of to-dos. Made the mistake of clicking the link instead of going directly to the site like I normally would (since I was mobile).
Just NPM is affected. Updates to be posted to the `/debug-js` link above.
Again, I'm so sorry.
https://socket.dev/blog/npm-author-qix-compromised-in-major-...
While it sucks that this happened, the good thing is that the ecosystem mobilized quickly. I think these sorts of incidents really show why package scanning is essential for securing open source package repositories.
In this incident, we detected the packages quickly, reported them, and they were taken down shortly after. Given how high profile the attack was we also published an analysis soon after, as did others in the ecosystem.
We try to be transparent with how Socket work. We've published the details of our systems in several papers, and I've also given a few talks on how our malware scanner works at various conferences:
Most people who get phished aren’t using password managers, or they would notice that the autofill doesn’t work because the domain is wrong.
Additionally, TOTP 2FA (numeric codes) are phishable; stop using them when U2F/WebAuthn/passkeys are available.
I have never been phished because I follow best practices. Most people don’t.
But google comes with its own privacy nightmares.
Also, junon.support++ – big thanks for being clear about all this.
So if the hacker did an npm publish from local it would show up.
With nodejs packages, I can open up node_modules and read the code. But packages get a chance to run arbitrary code on your computer after installation. By the time you can read the source code, it may be too late.
If there's any ideas on what I should be doing, I'm all ears.
EDIT: I've heard back, they said they're aware and are on it, but no further details.
Please take care and see this as things that happen and not your own personal failure.
I figure you aren't about to get fooled by phishing anytime soon, but based on some of your remarks and remarks of others, a PSA:
TRUSTING YOUR OWN SENSES to "check" that a domain is right, or an email is right, or the wording has some urgency or whatever is BOUND TO FAIL often enough.
I don't understand how most of the anti-phishing advice focuses on that, it's useless to borderline counter-productive.
What really helps against phishing :
1. NEVER EVER login from an email link. EVER. There are enough legit and phishing emails asking you to do this that it's basically impossible to tell one from the other. The only way to win is to not try.
2. U2F/Webauthn key as second factor is phishing-proof. TOTP is not.
That is all there is. Any other method, any other "indicator" helps but is error-prone, which means someone somewhere will get phished eventually. Particularly if stressed, tired, or in a hurry. It just happened to be you this time.
Good luck and well done again on the response!
Login using one off email links (instead of username + password) is increasingly common which means its the only option.
1. You just requested it, I'm not saying to never click link on transactional emails you requested. You still need to click on those verify email links
2. It replaces entering your password, so you're not entering your password on a link from an email, which is the very wrong thing.
Have the TOTP in the same/another password manager (after considering the tradeoffs) and that can also not be entered unless the domain is right :)
Passkeys seem like the best solution here where you physically can not fall for a phishing attack.
Folks from multi-billion dollar companies with multimillion dollar packages should learn a few things from this response.
> The author appears to have deleted most of the compromised package before losing access to his account. At the time of writing, the package simple-swizzle is still compromised.
Is this quote from TFA incorrect, since npm hasn’t yanked anything yet?
npm does appear to have yanked a few, slowly, but I still don't have any insight as to what they're doing exactly.
I’m extremely security conscious and that phishing email could have easily gotten me. All it takes is one slip up. Tired, stressed, distracted. Bokm, compromised
Great of you to own up to it.
Screenshot here: https://imgur.com/a/q8s235k
Do we just run:
npm list -g #for global installs
npm list #for local installs
And check if any packages appear that are on the above list?
Thanks!
Does anyone know how this attack works? Is it a CSRF against npmjs.com?
It wasn't a single-click attack, sorry for the confusion. I logged into their fake site with a TOTP code.
You login with your credentials, the attacker logins to the real site.
You get an SMS with a one time code from the real site and input it to the fake site.
The attacker takes the code andc finishes the login to the real site.
I actually got hit by something that sounds very similar back in July. I was saved by my DNS settings where "npNjs dot com" wound up on a blocklist. I might be paranoid, but it felt targeted and was of a higher level of believability than I'd seen before.
I also more recently received another email asking for an academic interview about "understanding why popular packages wouldn't have been published in a while" that felt like elicitation or an attempt to get publishing access.
Sadly both of the original emails are now deleted so I don't have the exact details anymore, but stay safe out there everyone.
phishing is too easy. so easy that I don't think the completely unchecked growth of ecosystems like NPM can continue. metastasis is not healthy. there are too many maintainers writing too many packages that too many others rely on.
thanks for your efforts!
Don't do security things when you're not fully awake, too. Lesson learned.
The email was a "2FA update" email telling me it's been 12 months since I updated 2FA. That should have been a red flag but I've seen similarly dumb things coming from well-intentioned sites before. Since npm has historically been in contact about new security enhancements, this didn't smell particularly unbelievable to my nose.
The email went to the npm-specific inbox, which is another way I can verify them. That address can be queried publicly but I don't generally count on spammers to find that one but instead look at git addresses etc
The domain name was `npmjs dot help` which obviously should have caught my eye, and would have if I was a bit more awake.
The actual in-email link matched what I'd expect on npm's actual site, too.
I'm still trying to work out exactly how they got access. They didn't technically get a real 2FA code from the actual, I don't believe. EDIT: Yeah they did, nevermind. Was a TOTP proxy attack, or whatever you'd call it.
Will post a post-mortem when everything is said and done.
Can't really tell you what not to do, but if you're not already using a password manager so you can easily avoid phishing scams, I really recommend you to look into starting doing so.
In the case of this attack, if you had a password manager and ended up on a domain that looks like the real one, but isn't, you'd notice something is amiss when your password manager cannot find any existing passwords for the current website, and then you'd take a really close look at the domain to confirm before moving forward.
want to stress everyone it can happen to. no one has perfect opsec or tradecraft as a 1 man show. its simply not possible. only luck gets one through and that often enough runs out.
And because it could happen to anyone that we should be doing a better job using AI models for defense. If ordinary people reading a link target URL can see it as suspicious, a model probably can too. We should be plumbing all our emails through privacy-preserving models to detect things like this. The old family of vulnerability scanners isn't working.
It actually calculates the Levenshtein distance between the legitimate address and every address in its own list. It then selects the attacker's address that is visually most similar to the original one.
This is a brilliant piece of social engineering baked right into the code. It's designed to specifically defeat the common security habit of only checking the first and last few characters of an address before confirming a transaction.
We did a full deobfuscation of the payload and analyzed this specific function. Wrote up the details here for anyone interested: https://jdstaerk.substack.com/p/we-just-found-malicious-code...
Stay safe!
> Our package-lock.json specified the stable version 1.3.2 or newer, so it installed the latest version 1.3.3
As far as I've always understood, the lockfile always specifies one single, locked version for each dependency, and even provides the URL to the tarball of that version. You can define "x version or newer" in the package.json file, but if it updates to a new patch version it's updating the lockfile with it. The npm docs suggest this is the case as well: https://arc.net/l/quote/cdigautx
And with that, packages usually shouldn't be getting updated in your CI pipeline.
Am I mistaken on how npm(/yarn/pnpm) lockfiles work?
In my experience, it's common for CI pipelines to be misconfigured in this way, and for Node developers to misunderstand what the lock file is for.
Thank you!
The npm team eventually seemed to settle on requiring someone to bring an RFC for this improvment, and the RFC someone did create I think has sat neglected in a corner ever since.
The package.json locked the file to ^1.3.2. If a newer version exists online that still satisfies the range in package.json (like 1.3.3 for ^1.3.2), npm install will often fetch that newer version and update your package-lock.json file automatically.
That’s how I understand it / that’s my current knowledge. Maybe there is someone here who can confirm/deny that. That would be great!
That way it's much harder to make one hash look like another.
This is smart, but not really unusual.
"we kindly ask that you complete this update your earliest convenience".
The email was included here: https://cdn.prod.website-files.com/642adcaf364024654c71df23/...
From this article: https://www.aikido.dev/blog/npm-debug-and-chalk-packages-com...
I don't agree that the exuberance over the brilliance of this attack is warranted if you give this a moment's thought. The web has been fighting lookalike attacks for decades. This is just a more dynamic version of the same.
To be honest, this whole post has the ring of AI writing, not careful analysis.
No it doesn't?
It has been what, hours? since the discovery? Are you expecting them to spend time analysing it instead of announcing it?
Also, nearly everyone has AI editing content these days. It doesn’t mean it wasn’t written by a human.
I want no part of AI in any form of my communication, and I know many which espouse the same.
I will certainly agree on "many", but not "nearly everyone".
Again, this is not the failure of a single person. This is a failure of the software industry. Supply chain attacks have gigantic impacts. Yet these are all solved problems. Somebody has to just implement the standard security measures that prevents these compromises. We're software developers... we're the ones to implement them.
Every software packaging platform on the planet should already require code signing, artifact signing, user account attacker access detection heuristics, 2FA, etc. If they don't, it's not because they can't, it's because nobody has forced them to.
These attacks will not stop. With AI (and continuous proof that they work) they will now get worse. Mandate software building codes now.
These can exclude a lot of common systems and software, including automations. If your heuristic is quite naive like "is using Linux" or "is using Firefox" or "has an IP not in the US" you run into huge issues. These sound stupid, because they are, but they're actually pretty common across a lot of software.
Similar thing with 2FA. Sms isn't very secure, email primes you to phishing, TOTP is good... but it needs to be open standard otherwise we're just doing the "exclude users" thing again. TOTP is still phishable, though. Only hardware attestation isn't, but that's a huge red flag and I don't think NPM could do that.
I don't disagree, but this sentence is doing a lot of heavy lifting. See also "draw the rest of the owl".
It's not that simple. You can implement the most stringent security measures, and ultimately a human error will compromise the system. A secure system doesn't exist because humans are the weakest link.
So while we can probably improve some of the processes within npm, phishing attacks like the ones used in this case will always be a vulnerability.
You're right that AI tools will make these attacks more common. That phishing email was indistinguishable from the real thing. But AI tools can also be used to scan and detect such sophisticated attacks. We can't expect to fight bad actors with superhuman tools at their disposal without using superhuman tools ourselves. Fighting fire with fire is the only reasonable strategy.
That was more than ten days ago, and yet major packages were compromised yesterday. How?
You’re right, this will only get a lot worse.
Why in the world would they NEED to stop? It apparently doesn't harm their "business"
What kind of crazy AI could possible have noticed that on the NPM side?
This is frustrating as someone that has built/published apps and extensions to other software providers for years and must wait days or weeks for a release to be approved while it's scanned and analyzed.
For all the security wares that MS and GitHub sell, NPM has seen practically no investment over the years (e.g. just go review the NPM security page... oh, wait, where?).
> Things were fine before they became mainstream
As in, things were fine before we had commonplace tooling to fetch third party software?
> package files that are set to grab the latest version
The three primary Node.js package managers all create a lockfile by default.
You can run the following to check if you have the malware in your dependency tree:
`rg -u --max-columns=80 _0x112fa8`
Requires ripgrep:
`brew install rg`
https://github.com/chalk/chalk/issues/656#issuecomment-32668...
`Get-ChildItem -Recurse | Select-String -Pattern '_0x112fa8' | ForEach-Object { $_.Line.Substring(0, [Math]::Min(80, $_.Line.Length)) }`
Breakdown of the Command:
- Get-ChildItem -Recurse: This command retrieves all files in the current directory and its subdirectories.
- Select-String -Pattern '_0x112fa8': This searches for the specified pattern in the files.
- ForEach-Object { ... }: This processes each match found.
- Substring(0, [Math]::Min(80, $_.Line.Length)): This limits the output to a maximum of 80 characters per line.
---
Hopefully this should work for Windows devs out there. If not, reply and I'll try to modify it.
https://gist.github.com/edgarpavlovsky/695b896445c19b6f66f14...
Although I'll still be told that using single-header libraries and avoiding the C standard library are regressive and obsolete, so gotta wait 10 more years I guess.
But maybe I'm misunderstanding the feature
That sounds great in theory. In practice, NPM is very, very buggy, and some of those bugs impact pulling deps from git repos. See my issue here: https://github.com/npm/cli/issues/8440
Here's the history behind that:
Projects with build steps were silently broken as late as 2020: https://github.com/npm/cli/issues/1865
Somehow no one thought to test this until 2020, and the entire NPM user base either didn't use the feature, or couldn't be arsed to raise the issue until 2020.
The problem gets kinda sorta fixed in late 2020: https://github.com/npm/pacote/issues/53
I say kinda sorta fixed, because somehow they only fixed (part of) the problem when installing package from git non-globally -- `npm install -g whatever` is still completely broken. Again, somehow no one thought to test this, I guess. The issue I opened, which I mentioned at the very beginning of this comment, addresses this bug.
Now, I say "part of of the problem" was fixed because the npm docs blatantly lie to you about how prepack scripts work, which requires a workaround (which, again, only helps when not installing globally -- that's still completely broken); from https://docs.npmjs.com/cli/v8/using-npm/scripts:
prepack
- Runs BEFORE a tarball is packed (on "npm pack", "npm publish", and when installing a git dependencies).
Yeah, no. That's a lie. The prepack script (which would normally be used for triggering a build, e.g. TypeScript compilation) does not run for dependencies pulled directly from git.Speaking of TypeScript, the TypeScript compiler developers ran into this very problem, and have adopted this workaround, which is to invoke a script from the npm prepare script, which in turn does some janky checks to guess if the execution is occuring from a source tree fetched from git, and if so, then it explicitly invokes the prepack script, which then kicks off compiler and such. This is the workaround they use today:
https://github.com/cspotcode/workaround-broken-npm-prepack-b...
... and while I'm mentioning bugs, even that has a nasty bug: https://github.com/cspotcode/workaround-broken-npm-prepack-b...
Yes, if the workaround calls `npm run prepack` and the prepack script fails for some reason (e.g. a compiler error), the exit code is not propagated, so `npm install` will silently install the respective git dependency in a broken state.
How no one looks at this and comes to the conclusion that NPM is in need of better stewardship, or ought to be entirely supplanted by a competing package manager, I dunno.
[1] https://www.debian.org/doc/manuals/securing-debian-manual/de...
I guess having some cool down period after some strange profile activity (e.g. you've suddenly logged from China instead of Germany) before you're allowed to add another signing key would help, but other than that?
Hell no. CI needs to be a clean environment, without any human hands in the loop.
Publishing to public registries should require a chain of signatures. CI should refuse to build artifacts from unsigned commits, and CI should attach an additional signature attesting that it built the final artifact based on the original signed commit. Public registries should confirm both the signature on the commit and the signature on the artifact before publishing. Developers without mature CI can optionally use the same signature for both the source commit and the artifact (i.e. to attest to artifacts they built on their laptop). Changes to signatures should require at least 24 hours to apply and longer (72 hours) for highly popular foundation packages.
It removes _most_ of the release friction while still adding the "human has acknowledged the release" bit.
Why does the mobile app use a completely different domain? Who designed this thing?
Password managers themselves have had vulnerabilities, browser autofill can fail, and phishing can bypass even well-trained users if the attack is convincing enough.
Good hygiene (password managers, MFA, domain awareness) certainly reduces risk, but it doesn’t eliminate it. Framing security only as a matter of 'individual responsibility' ignores that attackers adapt, and that humans are not perfect computers. A healthier approach would be: encourage best practices, but also design systems that are resilient when users inevitably make mistakes.
Now? Why aren't everyone setting up own GitHub mirrors is beyond me, almost. They were 100% right.
There was no way to quickly visualize that the site was fake, because it was in fact, "actually" amazon.com.
Phishing sucks. Sorry to read about this.
Edit: To other readers, yes, the exploit failed to use an additional TLS attack, which was how I noticed something was wrong. Otherwise, the site was identical. This was many years ago before browsers were as vocal as they are now about unsecured connections.
the actual code only runs in a browser context - it replaces all crypto addresses in many places with the attacker's.
a list of the attacker's wallet addresses: https://gist.github.com/sindresorhus/2b7466b1ec36376b8742dc7...
Mempool.space - no Blockchair - no Tronscan - no Blockcypher.com - no Blockread.io - no
As for developers trusting a plugin that reaches out to an external location to determine the reputation of every website they visit seems like a harder sell though.
Like the need to constantly explain himself because of one single blunder.
It shows how much so many open source projects rely on dependencies which are owned by one person and they can be pwned and (maybe hacked too)
Everyone can get pwned I suppose. From a more technical perspective though, from the amounts of times I am listening AI,AI & AI BS, Couldn't something like deno / node / bun etc. just give a slight warning on if they think that the code might be malware or, maybe the idea could be that we could have a stable release that lets say could be on things like debian etc. which could be verified by external contributors and then instead of this node world moving towards @latest, we move towards something like @verified which can take builds / source from something like debian maintained or something along that way...
I hope people can understand that author is a human too and we should all treat him as such and lets treat him with kindness because I can't imagine what he might be going as I said. Woud love a more technical breakdown once things settle and we can postmortem this whole situation.
So I guess a lot more accounts/packages might be affected than the ones stated in the article
The GitHub page (https://github.com/advisories/GHSA-hfm8-9jrf-7g9w) says to treat the computer as compromised. What does this mean? Do I have to do a full reset to be sure? Should I avoid running the app until the version is updated?
1. The version matching was wrong (now fixed).
2. The warning message is (still) exaggerated, imo, though I understand why they’d pass the liability downstream by doing so.
>Any computer that has this package installed or running should be considered fully compromised. All secrets and keys stored on that computer should be rotated immediately from a different computer. The package should be removed, but as full control of the computer may have been given to an outside entity, there is no guarantee that removing the package will remove all malicious software resulting from installing it.
It sounds like the package then somehow executes and invites other software onto the machine. If something else has executed then anything the executing user has access to is now compromised.
My worst nightmare is to wake up, see an email like that and hastily try to recover it while still 90% asleep, compromising my account in the process.
However, I think I can still sleep safe considering I'm using a password manager that only shows up when I'm on the right domain. A 2FA phishing email sending me to some unknown domain wouldn't show my password manager on the site, and would hence give me a moment to consider what's happening. I'm wondering if the author here wasn't using any sort of password manager, or something slipped through anyways?
Regardless, fucking sucks to end up there, at least it ends up being a learned lesson for more than just one person, hopefully. I sure get more careful every time it happens in the ecosystem.
I generally recommend Google's to any Android users, since it suggests your saved password not only based on domain in Chrome browser, but also based on registered appID for native apps, to extend your point. I'm not sure if third party password managers do this, although perhaps it's possible for anti-monopoly reasons?
If you're doing financial transactions using a big pile of NPM dependencies, you should IMHO be financially liable for this kind of thing when your users get scammed.
- Don't update dependencies unless necessary
- Don't use `npm` to install NPM packages, use Deno with appropriate sandboxing flags
- Sign up for https://socket.dev and/or https://www.aikido.dev
- Work inside a VM
And get yourself drowning in insurmountable technical debt in about two months.
JS ecosystems moves at an extremely fast pace and if you don't upgrade packages (semi) daily you might inflict a lot of pain on you once a certain count of packages start to contain incompatible version dependencies. It sucks a lot, I know.
Once upon a time, I used a software called passwordmaker. Essentially, it computed a password like hash(domain+username+master password). Genius idea, but it was a nightmare to use. Why? Because amazon.se and amazon.com share the same username/password database. Similarly, the "domain" for Amazon's app was "com.amazon.something".
Perhaps it's time for browser vendors to strongly bind credentials to the domain, the whole domain and nothing but the domain, so help me Codd.
Kudos to you for owning up to it.
As others have said, it's the kind of thing that could happen to anyone, unfortunately.
Hey, that's a pretty good reproduction of npmjs
That page says that the affected versions are ">=0". Does that seem right? That page also says:
> Any computer that has this package installed or running should be considered fully compromised. All secrets and keys stored on that computer should be rotated immediately from a different computer. The package should be removed, but as full control of the computer may have been given to an outside entity, there is no guarantee that removing the package will remove all malicious software resulting from installing it.
Is this information accurate?
Edit: However, I think the reason the security advisory marks the entire package at the moment, is because there is no mechanism in npm to notify users a version with an exploit is currently installed. `npm audit` looks at the versions configured, not installed.
The security advisory triggering this warning forces everyone to reinstall packages today, in case 4.4.2 was installed.
- https://github.com/advisories/GHSA-hfm8-9jrf-7g9w
- https://github.com/advisories/GHSA-5g7q-qh7p-jjvm
- https://github.com/advisories/GHSA-8mgj-vmr8-frr6
- https://github.com/advisories/GHSA-m99c-cfww-cxqx
I wonder if they're all from the same thing, they all popped up at the same time.
edit: they do appear to all be the same thing, and the advisory version wildcard is wrong: https://github.com/github/advisory-database/issues/6099
[0]: https://gist.github.com/martypitt/0d50c350aa7f0fc73354754343...
grep -r "_0x112fa8"
Most of those attacks are detected and fixed quickly, because a lot of people check newly published packages. Also the owners and contributors notice it quickly. But a lot of consumers of the package just install the newest release. With some grace period those attacks would be less critical.
Another good read is at https://www.aikido.dev/blog/npm-debug-and-chalk-packages-com...
I use bun, but similar could be done with npm
Add to .bashrc:
alias bun='docker run --rm -it -u $(id -u):$(id -g) -p 8080:8080 -v "$PWD":/app -w /app my-bun bun "$@"'
then you can use `bun` command as usual.Dockerfile:
FROM oven/bun:1 AS base
VOLUME [ "/app" ]
EXPOSE 8080/tcp
WORKDIR /app
# Add your custom libs
# RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get -y install \
# ... \
Create once the container: $ docker build -t "my-bun" -f "Dockerfile" .All these Chrome, VSCode, Discord, Electron-apps, browser extensions, etc – they all update ± every week, and I can't even tell what features are being added. For comparison, Sublime updates once a YEAR and I'm totally fine with that.
Got it from the "simple-swizzle" package that hasn't been taken down by NPM.
https://github.com/naugtur/running-qix-malware?tab=readme-ov...
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?
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.
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...
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-.
> (function() { return Array.isArray(arguments); })()
falseOn 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.
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.
Edit: As of this morning, `npm audit` will catch this.
https://github.blog/changelog/2025-07-01-dependabot-supports...
How long before npm mandates using phishing resistant mfa? At least for accounts that can publish packages with this may downloads.
> Used by 9.9m
Return-Path: <ndr-6be2b1e0-8c4b-11f0-0040-f184d6629049@mt86.npmjs.help> X-Original-To: martin@minimum.se Delivered-To: martin@minimum.se Received: from mail-storage-03.fbg1.glesys.net (unknown [10.1.8.3]) by mail-storage-04.fbg1.glesys.net (Postfix) with ESMTPS id 596B855C0082 for <martin@minimum.se>; Mon, 8 Sep 2025 06:47:25 +0200 (CEST) Received: from mail-halon-02.fbg1.glesys.net (37-152-59-100.static.glesys.net [37.152.59.100]) by mail-storage-03.fbg1.glesys.net (Postfix) with ESMTPS id 493F2209A568 for <martin@minimum.se>; Mon, 8 Sep 2025 06:47:25 +0200 (CEST) X-SA-Rules: DATE_IN_PAST_03_06,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,FROM_FMBLA_NEWDOM,HTML_FONT_LOW_CONTRAST,HTML_MESSAGE,MIME_HTML_ONLY,SPF_HELO_NONE,SPF_PASS X-RPD-Score: 0 X-SA-Score: 1.1 X-Halon-ID: e9093e1f-8c6e-11f0-b535-1932b48ae8a8 Received: from smtp-83-4.mailtrap.live (smtp-83-4.mailtrap.live [45.158.83.4]) by mail-halon-02.fbg1.glesys.net (Halon) with ESMTPS id e9093e1f-8c6e-11f0-b535-1932b48ae8a8; Mon, 08 Sep 2025 06:47:23 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; x=1757637200; d=smtp.mailtrap.live; s=rwmt1; h=content-transfer-encoding:content-type:from:to:subject:date:mime-version: message-id:feedback-id:cfbl-address:from; bh=46LbKElKI+JjrZc6EccpLxY7G+BazRijag+UbPv0J3Y=; b=Dc1BbAc9maHeyNKed/X7iAPabcuvlgAUP6xm5te6kkvGIJlame8Ti+ErH8yhFuRy/xhvQTSj8ETtV f3AElmzHDWcU3HoD/oiagTH9JbacmElSvwtCylHLriVeYbgwhZVzTm4rY7hw/TVqNE5xIZqWWCMrVG wi+k9uY+FUIQAh7Ta2WiPk/A4TPh04h3PzA50zathvYcIsPC0iSf7BBE+IIjdLXzDzNZwRmjgv2ZHW GAx/FRCPFgg0PbVvhJw98vSHnKmjPO/mmcotKFG+MUWkCtTu28Mm46t7MI7z5PrdCXZDA7L1nVnIwE ffIf0zED32Z6tFSJFNmYgFZlD6g+DnQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; x=1757637200; d=npmjs.help; s=rwmt1; h=content-transfer-encoding:content-type:from:to:subject:date:mime-version: message-id:feedback-id:cfbl-address:from; bh=46LbKElKI+JjrZc6EccpLxY7G+BazRijag+UbPv0J3Y=; b=DyWvxSOjMf7WfCVtmch+zw63kZ/OOBjcWnh1kIYs/hozgemb9mBIQCMqAdb4vSZChoW5uReVH5+k5 Jaz7UodbPJksVkYWqJOVg6nyx5EaYMYdgcw1+BCct/Sf2ceFwWurhupa6y3FBTFWBYLhcsAXERlx2l IuxWlpZoMDEBqDxjs8yvx/rkBrcd/2SNTcI+ooKJkrBIGBKuELOd3A5C6jlup6JNA4bE7vzP3FUfKw y0357UMnn45zWHm9HvudO4269FRlNjpiJaW7XF1/ANVrnDlNWfUGNQ5yxLZqmQDTtxFI7HcOrF3bTQ O/nrmVOvN9ywMvk/cJU4qGHqD9lT32A== CFBL-Address: fbl@smtp.mailtrap.live; report=arf X-Report-Abuse-To: abuse@mailtrap.io Received: from npmjs.help by smtp.mailtrap.live with ESMTPSA 6aee9fff-8c4b-11f0-87bb-0e939677d2a1; Mon, Sep 08 2025 00:33:20 GMT Feedback-ID: ss:770486:transactional:mailtrap.io Message-ID: <6be2b1e0-8c4b-11f0-0040-f184d6629049@npmjs.help> X-Mt-Data: bAX0GlwcNW6Dl_Qnkf3OnU.GLCSjw_4H01v67cuDIh2Jkf52mzsVFT_ZEVEe0W6Lf3qzW2LP_TCy93I46MCsoT0pB9HozQkvCw22ORSCt3JBma1G3v9aDEypT1DLmyqlb6hYLF3H7tJCgcxTU5pbijyNaOFtoUMdiTA6jxaONeZbBj.SKUa5CLT5TMpeNHG6oGIiY_jqlU.nQkxGPY3v9E34.Nz4ga8p9Pd_BplftaE~--2CLrluJMY65S5xFl--IISg0olYJu6DVyVDEcJ.AQ~~ MIME-Version: 1.0 Date: Mon, 08 Sep 2025 00:33:20 +0000 Subject: Two-Factor Authentication Update Required To: "molsson" <martin@minimum.se> From: "npm" <support@npmjs.help> Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable
There are ways to detect a replaced/proxied global window function too, and that's another arms race.
Was caught quickly (hours? hard to be sure, the versions have been removed/overwritten).
Attacker owns npmjs.help domain.
Kinda "proud" on it haha :D
So let me raise a different concern. This looks like an exploit for web browsers, where an average user (and most above average users) have no clue as to what's running underneath. And cryptocurrency and web3 aren't the only sensitive information that browsers handle. Meaning that similar exploits could arise targeting any of those. With millions of developers, someone is bound to repeat the same mistake sooner or later. And with some packages downloaded thousands of times per day, some CI/CD system will pull it in and publish it in production. This is a bigger problem than just a developer's oversight.
- How do the end user protect themselves at this point? Especially the average user?
- How do you prevent supply chain compromises like this?
- What about other language registries?
- What about other platforms? (binaries, JVM, etc?)
This isn't a rhetorical question. Please discuss the solutions that you use or are aware of.
Unless this is a situation that could've been easily avoided with a password manager since the link was from a website not in your manager's database, so can't happen to anyone following security basics, and the point of discussing the oversight instead of just giving up is to increase the share of people who follow the basics?
You could imagine that a compromised pad-left package could read the contents of all password inputs on the page and send it to an attacker server, but if you don't let that package access the document, or send web requests, you can avoid this compromise.
Don't use unregulated financial products. The likelihood of a bank being hit by this isn't zero - but in most parts of the world they would be liable and the end user would be refunded.
> How do you prevent supply chain compromises like this?
Strictly audit your code.
There's no magic answer here. Oh, I'm sure you can throw an LLM at the problem and hope that the number of false positives and false negatives don't drown you. But it comes down to having an engineering culture which moves slowly and doesn't break things.
- Install as little software as possible, use websites if possible.
- Keep important stuff (especially cryptocurrency) on a separate device.
- If you are working on a project that pulls 100s of dependencies from a package registry, put that project on a VM or container.
Most people writing JavaScript code for employment cannot really program. It is not a result of intellectual impairment, but appears to be more a training and cultural deficit in the work force. The result is extreme anxiety at the mere idea of writing original code, even when trivial in size and scope. The responses vary but often take the form of reused cliches of which some don't even directly apply.
What's weird about this is that it is mostly limited to the employed workforce. Developers who are self-taught or spend as much time writing personal code on side projects don't have this anxiety. This is weird because the resulting hobby projects tend to be substantially more durable than products funded by employment that are otherwise better tested by paid QA staff.
As a proof ask any JavaScript team at your employment to build their next project without a large framework and just observe how they respond both verbally and non-verbally.
A comprehensive library might offer a more neat DX, but you'd have to ship library code you don't use. (Yes, tree-shaking exists, but still is tricky and not widespread.)
I'm not saying it is safer, just to the tired grug brain it can feel safer.
The rust docs, a static site generator, pull in over 700 packages.
Because it’s trivial and easy
Why do "Java people" depend on lowrie's itext? Remember the leftpad-esque incident he initiated in 2015?
Debug, chalk, ansi-styles?
---
You can pretend like this is unique to JS ecosystem, but xz was compromised for 3 years.
is there a runnable command to determine if the package list has a compromised version of anything?
Is there a way to not accept any package version less than X months old? It's not ideal because malicious changes may still have gone undetected in that time span.
Time to deploy AI to automatically inspect packages for suspect changes.
Another one for “web3 is going great”…