Solana web3.js npm Publish-Account Compromise / Private-Key Exfiltration (2024-12-03)
- Name: Solana web3.js npm publish-account compromise / private-key exfiltration
- Date: 2024-12-03
- Protocol:
@solana/web3.js - Chain: Solana ecosystem / npm supply chain
- Category: software supply-chain compromise / publish-account compromise / private-key exfiltration / backend signer compromise
- Loss: at least roughly
$160k-$190kpublicly traced to the attacker wallet, with broader latent exposure for any bots, backends, multisigs, or program authorities that loaded the poisoned package and had not yet rotated keys - Summary: A compromised npm publish-access account let an attacker ship malicious
@solana/web3.jsversions1.95.6and1.95.7for roughly five hours on2024-12-03. Instead of rewriting front-end wallet prompts the way Ledger Connect Kit had, the attacker injected obfuscated exfiltration logic directly into key-handling paths such asKeypair.fromSecretKeyandKeypair.fromSeed, sent stolen secret material towardsol-rpc[.]xyz, and tied the campaign to Solana walletFnvLGtucz4E1ppJHRTev6Qv4X7g8Pw6WPStHCcbAKbfx. The preserved lesson is sharper thannpm got hacked: a shared SDK used by bots and backend signers became live custody infrastructure, so a registry-publishing compromise could immediately become theft from applications that handled raw authority keys in process. It is also a clean release-provenance failure cousin: the package name, import path, and semver stream stayed canonical while the published artifact and the executed key-handling bytes drifted underneath them. - Trigger / entry point:
- Solana maintainers disclosed that a publish-access account for
@solana/web3.jshad been compromised. - The attacker published unauthorized malicious versions
1.95.6and1.95.7to npm. - Maintainers said affected projects were those that updated during the exposure window from roughly
15:20 UTCto20:25 UTCon2024-12-03. - The impacted population was not ordinary non-custodial wallet users, but applications, bots, and backends that imported the package and handled private keys directly.
- Solana maintainers disclosed that a publish-access account for
- Root cause:
- The decisive failure was not in Solana consensus or in one downstream onchain protocol. It was an upstream software-supply-chain failure in a shared client library trusted by a large part of the Solana application stack.
- Publishing authority over the npm package was strong enough to change the executable key-handling logic used by downstream apps.
- Some downstream consumers were willing to ingest newly published package versions quickly enough that a five-hour malicious window still mattered.
- The preserved invariant is
a shared cryptographic client library must never be mutable by an attacker into a private-key exfiltration path. Once that failed, every bot or backend signer that loaded the malicious code effectively exposed custody material.
- Exploit path:
- The attacker compromised npm publish access for
@solana/web3.js. - They published malicious versions
1.95.6and1.95.7to npm. - Downstream developers, bots, or services that installed or updated during the exposure window pulled those versions into production or local environments.
- The malicious package injected an obfuscated helper commonly described as
addToQueueinto code paths that touched raw key material, includingKeypair.fromSecretKeyandKeypair.fromSeed. - When affected applications initialized or used those key paths, secret material was exfiltrated to attacker-controlled infrastructure associated with domain
sol-rpc[.]xyz, disguised behind CloudFront-looking traffic patterns. - The attacker then used compromised keys to drain funds from the corresponding wallets or authorities, with public tracking centering on wallet
FnvLGtucz4E1ppJHRTev6Qv4X7g8Pw6WPStHCcbAKbfx. - Maintainers unpublished the bad versions and released
1.95.8, but any already-exposed authority keys still needed rotation because removing the package did not un-leak prior secrets.
- The attacker compromised npm publish access for
- What the attacker needed to be true:
- npm publishing authority for the package had to be weak enough to capture through account compromise.
- Affected downstream projects had to install or auto-upgrade to
1.95.6or1.95.7during the short publication window. - Those projects had to handle raw secret keys inside the same JavaScript process rather than isolating signing in hardware, a dedicated signer service, or a non-extractable wallet boundary.
- Operators had to miss the compromise long enough for exposed keys to remain usable before rotation.
- Technical anatomy worth remembering:
- Solana maintainers said the malicious versions were live only for a short window, but that was still enough because
@solana/web3.jssat in hot code paths for bots and backend infrastructure with hundreds of thousands of weekly downloads. - The clearest preserved technical distinction from Ledger Connect Kit is where the stolen authority lived: Ledger poisoned browser prompts to trick end users into signing, while this incident stole secret key material from applications that already possessed the keys.
- This keeps Solana web3.js inside release-provenance failure as well as the broader supply-chain family: downstream teams kept trusting the familiar
@solana/web3.jspackage identity, but the actual npm artifact resolved during the exposure window had different custody semantics than the library they believed they were importing. Inside that broader family, Solana web3.js is the cleansame package name, different custody semanticscousin. - Public malware analyses described an obfuscated
addToQueuefunction inserted into secret-key access paths and a command-and-control path atsol-rpc[.]xyzhidden behind CloudFront-looking headers. - The attacker wallet most widely cited in public reporting was
FnvLGtucz4E1ppJHRTev6Qv4X7g8Pw6WPStHCcbAKbfx, with reported theft estimates ranging from about$130kto over$190kdepending on timing and valuation. - Maintainers explicitly said non-custodial wallets were generally not affected because they do not expose raw private keys to the library during normal transaction signing.
- Solana maintainers said the malicious versions were live only for a short window, but that was still enough because
- Representative artifacts and addresses:
- Malicious package versions:
1.95.6,1.95.7 - Safe remediation version:
1.95.8 - Exposure window cited by maintainers: roughly
2024-12-03 15:20 UTCto2024-12-03 20:25 UTC - Hardcoded / attributed attacker wallet:
FnvLGtucz4E1ppJHRTev6Qv4X7g8Pw6WPStHCcbAKbfx - Exfiltration / C2 domain reported by multiple analyses:
sol-rpc[.]xyz - Malicious helper highlighted in public writeups:
addToQueue
- Malicious package versions:
- Response / mitigation:
- Solana maintainers unpublished versions
1.95.6and1.95.7and released clean version1.95.8. - They told developers to rotate any suspect keys, explicitly including multisigs, server keypairs, and program authorities.
- Security researchers and ecosystem operators publicized the attacker wallet and the affected version window so downstream teams could audit lockfiles and deployments.
- The command-and-control endpoint was later reported offline, but that did not reduce the need for key rotation where exposure had already happened.
- That makes this incident the clean backend-signer companion to exact production artifact attestation and rollback discipline: publishing a fixed package and watching the C2 go dark did not itself prove recovery unless operators also proved which exact artifact versions had executed and rotated every key that those bad bytes could already have observed.
- Solana maintainers unpublished versions
Pattern tags
- software-supply-chain-compromise
- release-provenance-failure
- Same package name, different custody semantics: downstream bots and backends kept importing canonical
@solana/web3.js, but the resolved npm artifact during the exposure window had silently become key-exfiltration code - Shared SDK publication became live backend-signer authority: one compromised publish-access account was enough to rewrite secret-handling paths across unrelated Solana applications without touching their own repos or infrastructure first
- Recovery required authority rotation, not only package rollback: uninstalling the bad version or seeing
sol-rpc[.]xyzgo dark did not un-leak any server keypair, multisig signer, or program authority that the malicious package had already observed
Why the exploit worked
- Solana applications trusted
@solana/web3.jsas a canonical dependency identity rather than as one exact artifact lineage. That meant a compromised publish-access account could change secret-handling behavior underneath the same familiar import path, version stream, and package reputation. - The victims that mattered were exactly the ones holding raw authority in-process. Solana’s own advisory drew the boundary clearly: ordinary non-custodial wallets were generally safe, but bots, server-side signers, multisigs, and program-authority tooling that called
Keypair.fromSecretKeyorKeypair.fromSeedgave the poisoned package direct line-of-sight to replayable secrets. - The malware sat in hot cryptographic helper paths rather than in obviously optional telemetry or UI code. Once the compromised package hooked key-material constructors, ordinary application startup and signing flows became exfiltration events.
- Short publication windows were still enough because backend dependency updates and automated deployments can move quickly, and because one successful install could leak long-lived authority that remained monetizable after the package was unpublished.
- The remediation asymmetry was severe:
1.95.8restored a clean package stream, but it did not prove which environments had executed1.95.6or1.95.7, and it did not revoke any key material the bad versions had already exported.
Detection and audit pivots
- Inventory every service that allows general-purpose dependency code to touch raw Solana authority material — market-making bots, relayers, backend signers, deploy tooling, multisig helpers, and program-authority scripts — and treat those environments as custody systems rather than ordinary app servers.
- Diff cryptographic helper paths across dependency upgrades, not just transaction-building or RPC-facing code. Secret-material constructors like
Keypair.fromSecretKeyandKeypair.fromSeedshould be treated as signer-critical surfaces with extra review and alerting. - Preserve exact package lineage for signer-critical dependencies: reviewed source, published tarball, lockfile resolution, deployed artifact, and runtime environment should all answer the same
which bytes handled this key?question. If those objects are not tied together, rollback claims will stay fuzzy. - During incident response, separate
registry cleaned upfromauthorities now safe. Solana’s own guidance to rotate multisigs, server keypairs, and program authorities is the key operational lesson: once a malicious package touched replayable secrets, package rollback alone is incomplete containment. - Ask whether raw private keys need to exist in-process at all. Remote signing, hardware-backed key custody, and narrower signer services are design questions here, not optional hardening, because the decisive theft rail was secret observability inside ordinary JavaScript runtime.
Failure-prevention checklist
- Treat shared cryptographic SDKs that can construct or import private keys as custody-critical dependencies with stricter publication controls, artifact attestation, and release gating than ordinary RPC or utility packages.
- Pin exact signer-critical package versions and preserve the full lineage from reviewed source to published tarball to deployed lockfile; do not let bots, relayers, or deploy tooling float onto fresh dependency releases without an explicit promotion step.
- Require proof at the executed-artifact layer for signer-critical upgrades: the package version in source control, the tarball fetched by CI, and the bytes deployed into production should all answer the same
which exact code touched this key?question. - Move replayable Solana authority material out of general-purpose application runtime where possible. Hardware-backed custody, remote signers, tighter signing daemons, or program-specific authority isolation all reduce the blast radius of a poisoned JavaScript dependency.
- Inventory every environment allowed to hold raw Solana authority keys and classify them by rotation difficulty before an incident: multisigs, bots, deploy scripts, relayers, treasury backends, and program-authority workflows should already have rehearsed emergency replacement paths.
- Monitor signer-critical dependency publication, version resolution, and unexpected diff surfaces such as
Keypairconstructors, seed derivation helpers, secret serialization paths, and outbound network calls. - Design incident response around the asymmetry between package rollback and key recovery: the runbook should force
was a bad package executed anywhere?before it ever allowsupgrade completeto count as closure. - Keep deployment and lockfile telemetry long enough to reconstruct exactly which services resolved malicious versions during a short compromise window.
Audit prompts
- Which packages in this stack can touch raw signing keys, seed phrases, signer derivation, or exported secret material, and are those dependencies governed like custody infrastructure or like ordinary developer tooling?
- Can the team prove which exact tarball, lockfile resolution, and deployed artifact each signer-critical service executed during a given release window?
- If npm publish access for a core SDK were compromised today, which production services would ingest the release automatically, and how quickly could operators identify them?
- Do bots, multisig helpers, deploy scripts, or backend signers still materialize replayable private keys in the same runtime that ingests broad dependency trees?
- What outbound-network, diff-review, or runtime-policy controls would make a new secret-exfiltration path in
Keypair.fromSecretKey,Keypair.fromSeed, or adjacent helpers unusually visible rather than ordinary release noise? - How would the team rotate every exposed authority type — server keypairs, program authorities, multisig signers, treasury bots — if a malicious dependency had already observed the secrets?
- Is
package unpublished and clean version releasedtreated as recovery, or does the incident process force a second proof that no live authority remained exposed? - Which services depend on
latest, broad semver ranges, or low-friction auto-updates for signer-critical libraries, and why are those paths still allowed?
Lessons that should already be standard
- Shared cryptographic SDK publication is custody authority when downstream applications let those SDKs observe raw keys.
We upgraded to the fixed versionis not the same statement asno replayable secret was already exported.- A short-lived dependency compromise can still be a full-severity custody incident if the bad code lives on hot key-handling paths.
- Package identity, semver familiarity, and repository reputation are not enough for signer-critical trust; teams need artifact-level lineage and runtime proof.
- Backend signers, bots, and deployment tooling deserve the same supply-chain paranoia that teams usually reserve for browser wallet prompts.
- The fastest honest boundary in incidents like this is often
who held raw keys in-process?, because that boundary determines whether rollback is routine maintenance or authority rotation. - If a service cannot answer
which exact dependency bytes touched this key?, it is already under-instrumented for custody work.
Why this incident matters
- It is a clean supply-chain cousin to Ledger Connect Kit, but the monetization rail is different enough that the pattern note becomes sharper: a poisoned dependency can steal private authority itself, not just manipulate what users are asked to sign.
- It preserves the backend / bot / infrastructure side of crypto supply-chain risk, where package updates can silently compromise hot wallets, program authorities, and automated trading or settlement systems.
- It is also the clean backend-runtime exemplar for replayable-secret non-observability and telemetry-exclusion discipline: once applications were willing to hold raw signing keys in ordinary JavaScript process memory, a short-lived malicious publish could turn familiar SDK code into immediate key-exfiltration custody authority.
- It also preserves a backend-facing release-provenance failure branch: the trusted package name stayed the same while the actually published artifact rewrote secret-handling behavior during a short but still dangerous resolution window.
- It also shows why
quickly unpublishedis not a complete success metric for dependency compromises. A five-hour malicious window is plenty if the package lives in custody-adjacent code paths and the real remediation step is key rotation, not just reinstalling a fixed version.
Internal linkages
- Core recurring pattern: software-supply-chain-compromise.
- Sharper release-integrity lens: release-provenance-failure — the useful preserved question is not only
how did npm publish access get compromised?, butwhich exact package artifact and executed key-handling bytes differed from the library downstream teams thought they had authenticated. - Positive-design secret-boundary companion: replayable-secret-non-observability-and-telemetry-exclusion-discipline — the sharper healthy-side question is why downstream bots and backends were still willing to materialize replayable private keys inside general-purpose JavaScript runtime space that one compromised dependency could stringify and export.
- Positive-design recovery companion: exact-production-artifact-attestation-and-rollback-discipline.
- Useful contrast: ledger-connect-kit-npm-supply-chain-wallet-drainer-2023-12-14 — both incidents begin with poisoned npm publication, but Ledger mainly weaponized browser-delivered signing prompts while Solana web3.js stole backend-held private keys directly.
- Adjacent family: frontend-compromise-approval-phishing — useful for the user-facing wallet-drainer cousin, but not the primary classification here because the decisive theft primitive was secret exfiltration from applications that already held the keys.
Control surface
-
The real leverage sat in npm publishing authority, dependency-update discipline, secret-key handling inside JavaScript applications, and the absence of stronger boundaries between shared SDK code and hot signing material.
-
Once a widely trusted crypto client library could mutate its own key-handling functions, package publication effectively became custody authority over any downstream system willing to ingest the update.
-
Sources:
- https://github.com/solana-foundation/solana-web3.js/security/advisories/GHSA-jcxm-7wvp-g6p5
- https://github.com/solana-foundation/solana-web3.js/releases/tag/v1.95.8
- https://socket.dev/blog/supply-chain-attack-solana-web3-js-library
- https://www.mend.io/blog/the-solana-web3-js-incident-another-wake-up-call-for-supply-chain-security/
- https://threats.wiz.io/all-incidents/solana-web3js-supply-chain-attack
-
Last reviewed: 2026-07-26 UTC