On December 2, 2024, @solana/web3.js versions 1.95.6 and 1.95.7 were published to npm with injected code that exfiltrated Solana private keys. The package is the canonical JavaScript SDK for building on Solana, with over 350,000 weekly downloads. Most dapps, wallets, and on-chain tooling in the Solana ecosystem depend on it directly or transitively. The malicious versions were live for about five hours before being yanked. In that window, any server-side code running @solana/web3.js with a loaded private key was at risk.
This is a consequential incident because the affected packages sit very deep in the Solana dependency graph. Apps three or four levels removed were exposed.
How did the maintainer account get compromised?
A phishing attack against a Solana Foundation-associated maintainer captured an npm publishing token.
The Solana team disclosed that a maintainer was phished and their npm access token was taken. The token had publish rights on the @solana/web3.js package and could push new versions. Whether the phishing was generic credential theft or a targeted operation is not publicly confirmed, but the specificity of the payload (purpose-built for Solana key material) strongly suggests targeted preparation.
The attacker pushed 1.95.6, waited briefly, then pushed 1.95.7 with an identical payload. The second push was likely insurance: if 1.95.6 was yanked quickly, 1.95.7 could propagate as an apparent "fix."
What did the payload do?
A new function in the compiled bundle intercepted calls that handled private keys and sent them to a hardcoded attacker address.
The injected code added a helper that, when invoked during key-related operations, serialized the key material and issued an HTTP request to an attacker-controlled endpoint. The helper was wired into several code paths: Keypair creation, signing operations, and any function that accepted a secret key parameter. Public reverse engineering showed the endpoint to be a domain hosted on a privacy-oriented provider, with the exfiltrated payload base64-encoded and wrapped in a generic-looking JSON body to evade naive network filtering.
Critically, the payload only activated in server-side Node.js contexts. It did not run in the browser. This is a deliberate design choice: server-side code is where hot wallet keys are typically loaded (trading bots, automated market makers, relayer services, custodial wallets). Browsers were not the target here.
How much did the attack actually affect the ecosystem?
Reports suggest around $160,000 in stolen funds, primarily from automated market-making and trading bots that happened to run between the time of publication and the time of yank.
The blast radius would have been much larger except for two factors. First, a significant portion of serious Solana infrastructure uses pinned versions with lockfiles and integrity hashes, which meant most production systems did not actually resolve to the malicious version. Second, the payload required a code path that actually handled a private key to fire, and many dapps build and sign transactions in the browser rather than the server, so their server-side imports of @solana/web3.js never exposed a key.
The affected systems were disproportionately small trading desks and individual bot operators with "latest" or loose semver constraints, which is consistent with the reported loss profile.
Why did detection take five hours?
There was no behavioral alerting for npm packages of this criticality, so detection depended on manual discovery.
A developer noticed odd network activity from a Solana service, traced it to a recent @solana/web3.js upgrade, diffed the package against the previous version, spotted the exfiltration code, and reported it on GitHub. Solana Labs engineers, Anza (the maintainer organization for web3.js), and npm security staff collaborated on takedown. Clean versions shipped shortly after.
There is a larger structural point: @solana/web3.js is critical infrastructure for a multi-billion-dollar ecosystem, and the defense against a targeted maintainer phish was a single human reading network logs. Detection capacity is not keeping pace with the value at risk.
What should Solana teams change?
Four recommendations, all actionable today.
First, pin the exact version of @solana/web3.js in package.json, not a semver range. Combine with a committed package-lock.json that includes integrity hashes, and use npm ci or yarn install --frozen-lockfile in all CI and production builds. This would have blocked the backdoor versions from being installed regardless of detection timing.
Second, segregate key-bearing runtime code. Any process that loads a signing key should run in a hardened, minimal-dependency environment, separate from the application-tier code that handles business logic. A dedicated signer service that imports only @solana/web3.js's cryptographic primitives and has no network egress beyond Solana RPC endpoints would have failed-closed when the backdoor tried to call out.
Third, rotate maintainer credentials on a regular schedule and require hardware-backed 2FA for npm publishing on critical packages. npm supports provenance-based publishing via OIDC federation, which eliminates long-lived tokens entirely.
Fourth, invest in automated behavioral comparison of published packages. Diffing source and compiled output between consecutive versions, running both in sandboxes, and comparing network and filesystem behavior would have caught this attack within minutes of publication. This is not widely deployed, and it should be.
Why are SDKs a disproportionately attractive target?
SDKs are the point in the architecture where sensitive capabilities are centralized, which makes them high-leverage targets for supply chain attackers.
A transaction-signing SDK sits between application code and cryptographic key material. It is the single piece of software that legitimately holds a private key in memory, often for the lifetime of the process. If you are an attacker trying to compromise a Web3 business, you have a few options: compromise the application code (broad, high-noise), compromise the infrastructure (slow, well-monitored), or compromise the SDK that every instance of the application already loads and trusts. The SDK is the efficient target.
This pattern applies beyond Web3. Authentication SDKs, payment SDKs, observability agents, analytics libraries, and cloud-provider SDKs all share the property: they are trusted by thousands of applications, they handle high-value data, and they are typically pulled in with minimal scrutiny because they come from "the official source." Every one of these is a supply chain attacker's preferred target. The @solana/web3.js incident is one instance of a broad class.
The defensive implication is that SDK dependencies should be treated differently from application dependencies. They deserve stricter pinning, more aggressive review of version bumps, and dedicated monitoring of their behavior in your runtime. Generic SCA alerting that treats all dependencies equally will miss the signal that matters: a small behavioral change in a key-handling SDK is far more dangerous than a large change in a logging library.
How Safeguard.sh Helps
Safeguard.sh's reachability analysis would have flagged the new exfiltration paths in @solana/web3.js 1.95.6 as high-priority given the package's key-handling role, leveraging the 60-80% noise reduction to surface this above lower-impact SCA findings. Griffin AI monitors behavioral diffs between package versions and would have detected the new outbound HTTP target and secret-material access independent of public disclosure timing. The SBOM pipeline tracks @solana/web3.js at 100-level depth, so transitive dependents across the Solana ecosystem can answer "are we running a compromised version anywhere" in seconds. TPRM gates critical Web3 suppliers, and container self-healing rolls back affected signer services automatically once anomalous outbound traffic is observed.