Posted by tosh 4 days ago
We all dodged a bullet - https://news.ycombinator.com/item?id=45183029 - Sept 2025 (273 comments)
NPM debug and chalk packages compromised - https://news.ycombinator.com/item?id=45169657 - Sept 2025 (719 comments)
PyPI also now requires 2FA for everyone and makes other proactive attempts to hunt down malware (https://blog.pypi.org/posts/2023-05-25-securing-pypi-with-2f...) in addition to responding to reports.
There was still a known compromise recently: https://blog.pypi.org/posts/2025-07-31-incident-report-phish... (`num2words` gets millions of monthly downloads, but still for example two orders of magnitude less than NumPy). Speaking of the communication I mentioned in the first paragraph, one of the first people reporting seeing the phishing email was a CPython core developer.
Malware also still does get through regularly, in the form of people just uploading it. But there are automated measures against typo-squatting (you can't register a name that's too similar to existing names, or which is otherwise blacklisted) and for most random crap there's usually just no reason anyone would find out about it to install it.
I wonder if it really is only npm that got compromised.
This is absolutely wild that this did not raise _any_ red flags to this person.
red flag: random reset for 2FA ??? red flag: npmjs.help ??? red flag: user name and password not autofilled by browser ??? red flag: copy and pasting u/p combo into phishing site
If _developers_ can't even get this right. Why do we expect dumb users to get this right? We are so cooked.
I cannot be bother to remember every hole name. They're all USB anyway, the difference is that some are A, C, or Lightning, I bought a new MacBook and it has that magnet hole, what is that called? I'm not following.
The stuff I deal with every day is centering divs
> it's too hard to keep track of the names of the three different ports
it's more than three ports.
> do you now need to maintain two keys for every service?
I do maintain multiple keys for every service. I wouldn't say it's a lot of maintenance, any more than a far more secure "remember me" box is "maintenance".
When I register for a new service, I add my hardware token on my keychain as a passkey. I sign in on my laptop for the first time for a service I'll use there more than once, I make a passkey. I sign in on my desktop for the first time, I make a passkey, maybe make a spare in my password manager. Maybe if it's something I use on my phone, I'll make a passkey there as well when I sign in for the first time. When I get around to it, I'll add the spare hardware token I keep in a drawer. But its not like "I just signed up for a new service, now I must go around to every device and make a new passkey immediately. As long as I've got a couple of passkeys at registration time, I'm probably fine.
Lose my laptop? Its ok, I've got other passkeys. Lose my keys? Its ok, I've got other passkeys. My laptop and keys get stolen at the same time? Its ok, I've got other passkeys.
Its really not that hard.
Yes, they support NFC
> or do you now need to maintain two keys for every service?
I maintain 4 keys so I have backups. In most cases registering additional keys is no problem, and this is only needed when signing up.
The idea is that if your password manager doesn't show the usual list of accounts (regardless if the actual autofill after clicking the account works or not), you double-check the domain.
Not at all? The password manager handles that automatically, have you never used a password manager before?
> Passkeys will automate and enforce the check
What happens to the passkey when the origin changes, is it automatically recognising it as the new domain without any manual input? Curious to see what magic is responsible for that
Yes: '...you double-check the domain.' That's manually checking for mistakes.
> What happens to the passkey when the origin changes,
The passkey won't work at all. You will just have to create a new one.
Yes, but that's only when the origin changed compared to when you added it to the password manager. Same thing for Passkeys, won't work if the origin is different, so you double-check that the domain in your browser address bar is the correct one.
Obviously normally you don't do anything except click on the account that shows up, since the domain matches.
You could claim that a phishing site could set up their own passkey registration system–but that still wouldn't give them access to the target's real account.
So exactly the same as password managers, there is no functional difference if you were using a password manager...
Considering that today it'd add work for me today, and future work, with no additional security benefits compared to my current approach, it just don't seem worth it.
A few concrete datapoints from our analysis of this incident that may help cut through the hand-waving:
1. This is the same campaign that hit Qix yesterday (https://socket.dev/blog/npm-author-qix-compromised-in-major-...). The injected payload is byte-for-byte behaviorally identical. It hooks fetch, XMLHttpRequest, and common wallet provider APIs and live-rewrites transaction payloads to attacker addresses across ETH, BTC, SOL, TRX, LTC, BCH. One tell: a bundle of very distinctive regexes for chain address formats, including multiple Solana and Litecoin variants.
2. Affected versions and timing (UTC) that we verified:
- duckdb@1.3.3 at 01:13
- @duckdb/duckdb-wasm@1.29.2 at 01:11
- @duckdb/node-api@1.3.3 at 01:12
- @duckdb/node-bindings@1.3.3 at 01:11
Plus low-reach test shots: prebid@10.9.1, 10.9.2 and @coveops/abi@2.0.1
3. Payout so far looks small. Tracked wallets sum to roughly $600 across chains. That suggests speed of discovery contained damage, not that the approach is harmless.
What would actually move the needle:
=== Registry controls ===
- Make passkeys or FIDO2 mandatory for high-impact publisher accounts. Kill TOTP for those tiers.
- Block publishing for 24 hours after 2FA reset or factor changes. Also block after adding a new automation token unless it is bound by OIDC provenance.
- Require signed provenance on upload for popular packages. Verify via Sigstore-style attestations. Reject if there is no matching VCS tag.
- Quarantine new versions from being treated as “latest” for automation for N hours. Exact-version installs still work. This alone cuts the blast radius of a hijack.
=== Team controls ===
- Do not copy-paste secrets or 2FA. Use autofill and origin-bound WebAuthn.
- Require maker-checker on publish for org-owned high-reach packages. CI must only build from a signed tag by an allowed releaser.
- Pin and lock. Use `npm ci`. Consider an internal proxy that quarantines new upstream versions for review.
=== Detection ===
- Static heuristics catch this family fast. Wallet address regex clusters and network shims inside non-crypto packages are a huge tell. If your tooling sees that in a data engine or UI lib, fail the build.
Lastly, yes, training helps, but the durable fix is making the easy path the safe path.
This should not be considered high effort or a sophisticated attack. The attacker probably used a mitm proxy which can easily replicate every part of your site, with very little initial configuration. Evilginx is the most popular one I could think of
A week waiting period would not be enough. On average, npm malware lingers on the registry for 209 days before it's finally reported and removed.
Source: https://arxiv.org/abs/2005.09535
So, regrettably, we're back to "train users" and all the pitfalls that entails
[0]: legacy 1.x projects aside