All vulnerabilities
CRITICALSupply chainexploited in the wildcurated

NPM-SOLANA-WEB3JS-2024

npm · @solana/web3.js

Summary

In early December 2024, attackers spear-phished a member of the Solana team who had publish rights to @solana/web3.js, the core JavaScript library for building on Solana, downloaded about 350,000 times a week. They pushed two malicious versions carrying a backdoor that quietly stole the private keys any app used to sign transactions and shipped them to the attacker's wallet. It was live for about five hours. It is the npm-account-takeover playbook aimed squarely at crypto, where a poisoned dependency does not just run a miner, it empties wallets.

How it happened

The attackers spear-phished a member of the @solana npm organisation who held publish access, routing them to a clone of the npm website where they entered their password and a one-time 2FA code, which the attacker used to log in. With that access, they published two malicious versions (1.95.6 and 1.95.7) of @solana/web3.js, tracked as CVE-2024-54134.

The payload was tailored to crypto. The malicious versions added a function (addToQueue) that hooked Solana's key-handling routines (account creation, Keypair.fromSecretKey, and the signing-instruction builders), captured the private keys used to sign transactions, and exfiltrated them, disguised as ordinary CloudFlare headers, to an attacker-controlled domain (sol-rpc[.]xyz). Any application or bot that updated to the poisoned version and handled signing keys leaked them straight to the attacker. It is a supply-chain attack on a core crypto SDK, where the backdoor steals keys rather than CPU cycles.

The damage

The malicious versions were live for roughly five hours, and an estimated $130,000 to $190,000 in cryptocurrency was stolen (around $160,000 by most on-chain estimates), mostly from bots and backend services that updated quickly and signed with exposed keys. A clean version (1.95.8) was released once the compromise was found. The loss was limited by the short window and by the fact that it mainly hit projects holding keys server-side; non-custodial wallets, which generally do not expose private keys to the library, were not affected. Given the library's centrality to the Solana ecosystem, though, it could have been far worse.

Why Solana web3.js still matters

It shows the npm-account-takeover attack, the same class as ua-parser-js, aimed specifically at crypto: the payload steals signing keys, not just compute. It also shows that ordinary two-factor authentication is not a silver bullet, because the attacker phished the one-time code along with the password. The defences follow: require phishing-resistant 2FA (FIDO2 or passkeys, which cannot be phished this way) on publish accounts; pin dependencies and review updates so a freshly published core SDK never auto-deploys to systems that hold keys; and keep signing keys out of reach of application and dependency code, in a hardware module or a dedicated signer, so a poisoned library cannot read them. It shares the same late-2024 drainer-via-dependency theme as the Ledger Connect Kit attack.

How to fix it

  • Pin or upgrade to the clean version (1.95.8) and rebuild from a clean lockfile.
  • Treat every private key handled by code that ran a malicious version as compromised: rotate keys and move funds to new wallets immediately.
  • Audit for the injected exfiltration function and any outbound traffic to the attacker's address or domain.

How to avoid it

  • Require phishing-resistant 2FA (FIDO2 or passkeys) on publish accounts; ordinary 2FA codes can be phished by a fake login page, which is how this happened.
  • Pin dependencies and review updates, and never let a freshly published version of a core SDK auto-deploy to systems that hold keys.
  • Keep signing keys out of reach of application and dependency code, in an HSM or dedicated signer, so a poisoned library cannot read them.
  • Monitor your critical dependencies for unexpected releases and pull from a vetted internal mirror.

References

Related vulnerabilities

All Supply chain →