color npm package compromised
Thanks to my sponsors: Guy Waldman, Urs Metz, Jon Gjengset, Nicholas Orta, David E Disch, Arjen Laarhoven, pinkhatbeard, Zachary Thomas, Ula, Aaron Gorodetzky, Marcus Griep, Olly Swanson, Geoffrey Thomas, Tabitha, Mark Old, Richard Stephens, Richard Pringle, Blake Johnson, Christoph Grabo, xales and 279 more
On September 8 2025, around 13:00 UTC, someone compromised Josh Junon’s npm account (qix) and started publishing backdoored versions of his package.
Someone noticed and let Josh know:
Josh confirmed he’d gotten pwned by a fake 2FA (two-factor authentication) reset e-mail:
The phishing e-mail came from npmsj.help
(registered 3 days prior) and claimed
users had to reset their 2FA:
The 2FA phishing e-mail
The raw email is available for the curious — it looks like it was sent via mailtrap (I’ve sent them an e-mail about it).
Over on Mastodon, Kevin Beaumont provided a list of affected packages:
And pointed out the scale of the attack: color
alone has ~32 million weekly
downloads:
The payload
The complete payload is available on pastebin.
According to initial analysis, it appears it’s not meant to be running in a server environment, or on developers’ machines (in other words, not in nodejs/bun/etc.), but in the browser.
Which would mean that for the attack to be successful:
- Someone maintaining a crypto website/web-powered app would have to upgrade to the backdoored dependencies
- Those dependencies would have to be used on the front-end
- The crypto website would have had to be built, packaged, deployed
- Users of the website would’ve had to make transactions with the drainer active
In other terms, I think that if all people did was accept a PR that bumped some dependencies, and some tests ran in CI, then nothing bad has happened, yet. But people are still figuring out exactly what the payload is supposed to do, and all the affected packages.
De-obfuscating the payload through https://obf-io.deobfuscate.io/ yields good results, see this gist.
I went a step further and did a loose port to TypeScript to understand more of what’s going on.
In short, fetch
and XMLHTTPRequest
are hooked so that any crypto addresses
found in the response body that look like Bitcoin, Solana, Litecoin v2 etc. are
modified to be one of the many addresses controlled by the attacker.
Note that only the response body is modified, not the request body. Presumably… this targets API calls that would request which address to send funds to, and do the transfer through some other means?
Additionally, every 500ms up to 50 times, window.ethereum.request
is called to see if
any Ethereum accounts have been authorized for use with Metamask.
If so, window.ethereum
is monkey-patched to alter various transactions to go
attacker-controlled addresses.
In particular, it looks for:
approve(address,uint256)
(0x095ea7b3) — replacing the destination & maxing out the amount- this codepath also logs the DEX name if known: Uniswap, PancakeSwap, 1inch, SushiSwap
permit(address,address,uint256,uint256,uint8,bytes32,bytes32)
(0xd505accf) — replacing the destination & maxing out the valuetransfer(address,uint256)
(0xa9059cbb) — replacing the destination but keeping the amounttransferFrom(address,address,uint256)
(0x23b872dd) — replacing the destination but keeping the amount
There’s a Solana codepath as well, which changes various fields to 19111111111111111111111111111111
, but
it’s unclear to me whether that would do anything successfully.
Current situation
Sep 8, 17:19 UTC
NPM has contacted Josh and told him they are working to the remove the packages.
See Josh’s timestamped comment
Sep 8, 17:11 UTC
- John is still locked out of his npm account
- chalk was patched by Sindre
- simple-swizzle is still compromised
see the obfuscated code starting with const _0x112fa8
The npm team seems rather unresponsive given the urgency of the situation:
It’s been almost two hours without a single email back from npm. I am sitting here struggling to figure out what to do to fix any of this. The packages that have Sindre as a co-publisher have been published over but even he isn’t able to yank the malicious versions AFAIU. If there’s any ideas on what I should be doing, I’m all ears.
The best place to stay informed is probably Kevin’s thread on Mastodon.
Here's another article just for you:
Rust 2020: Funding
Blog posts that praise Rust are many but funding is generally in short supply.
If even a small percentage of the money Rust saves companies was put back into the ecosystem it would help secure the future of the platform tremendously.
Multiple sources of funding
It is unreasonable going forward to expect the same handful of companies to provide all the funding.