Software Supply-Chain Compromise / Poisoned Shared Dependency
- Name: software supply-chain compromise / poisoned shared dependency
- Category: exploit pattern / software supply-chain compromise / shared dependency compromise / custody-adjacent dependency failure
- Summary: Some crypto theft incidents do not begin with a hacked dApp domain or a buggy onchain router. They begin upstream, when an attacker gains publishing or distribution control over a shared JavaScript package, wallet SDK, loader, CDN artifact, or build dependency that many legitimate apps trust. Sometimes the poisoned dependency rewrites wallet prompts in otherwise honest front ends; other times it steals private keys directly from bots, backends, or signer infrastructure that imported the package. The preserved failure is that dependency-distribution authority quietly became wallet authority or signer authority, and that release / artifact integrity sat outside the threat model until users were signing attacker-shaped prompts or operators had already leaked hot keys. The operational sting is that rollback is not symmetric with compromise: publishing a clean version does not by itself prove browsers have stopped receiving bad bytes, and reinstalling a fixed package does not un-leak secrets already exfiltrated.
Three dependency-trust promotions healthy systems should not collapse
Some shared package name, loader identity, or familiar runtime URL exists.That dependency path still counts as the exact reviewed artifact lineage and service-selection bundle downstream users or operators meant to trust.That accepted lineage still deserves this much live wallet-prompt, signer, secret-observation, or runtime-routing authority right now.- This family appears when teams preserve the first claim better than the second, and the second better than the third.
- The dangerous flattening is to treat
we are still using the real package / loader / script URLas if it also provedthe published tarball, runtime-selected bytes, and embedded service selectors still describe the reviewed objectandthat object still deserves broad signing or secret-handling authority even under uncertainty. - Healthy systems separate those promotions on purpose: naming continuity proves only that a familiar dependency path exists, artifact-lineage and runtime-byte integrity prove that the path still resolves to the intended production object, and bounded-authority plus rollback discipline prove how much wallet, signer, or backend power that still-authentic object is allowed to keep.
Quick classifier
-
Stay here when the decisive compromise first lived upstream in a shared dependency, package publisher, runtime loader, CDN-backed SDK path, or other ecosystem component that many otherwise honest downstream apps or backends inherited.
-
Use the shorthand
same package name, different custody semanticsfor backend or library-centric cousins like Solana web3.js, where the familiar dependency identity survived but the published artifact changed what secret-handling or signing code actually did. -
Use the shorthand
same real site, different loader-resolved bytesfor browser/runtime cousins like Ledger Connect Kit or Polyfill.io, where downstream domains stayed honest but signer-critical execution was still delegated to mutable remote package, loader, CDN, or script identities. -
Pivot first to frontend-compromise-approval-phishing when one protocol’s own registrar / DNS / CDN / edge / HTML delivery stack is the decisive compromise surface and the shared-upstream dependency ecosystem is not the main analytical lift.
-
Pivot first to release-provenance-failure when the sharper preserved lesson is which exact source / tarball / loader / service identifier / CDN response / browser-fetched artifact drifted away from the thing people thought they had authenticated, and how rollback had to be proven at the executed-artifact layer.
-
Pivot first to third-party runtime allowance and integrity pinning when the design question is why a signer-facing page was still allowed to execute mutable remote code at all, even if no shared-upstream compromise is needed to tell the story.
-
Polyfill.io is the useful seam case: the compromise began in a shared third-party runtime URL that many downstream sites inherited, but the sharper follow-up quickly becomes release identity and runtime-byte drift under the same familiar service identifier.
-
What it is:
- A shared front-end dependency, backend SDK, runtime-loaded wallet middleware, or signer-adjacent library is trusted across many apps.
- The attacker compromises the package’s publication, distribution, or update path rather than any one downstream protocol contract.
- The malicious artifact injects attacker-controlled approval / permit / transfer logic, or directly exfiltrates secret material from code paths that already hold private keys.
- Users may interact with real dApps on real domains, or operators may run real bots and backends, while the executed dependency code is no longer what those systems expected to load.
- The same upstream compromise can fan out across many protocols at once because the dependency sits in a shared trust bottleneck.
- The key release-provenance lesson is that
reviewed source,published tarball,resolved runtime version, dependent service identifiers such as project IDs, andbrowser-fetched bytesare separate security objects. If any one of those layers becomes attacker-controlled, wallet authority or signer authority can change even while downstream apps still appear honest. - Keep this family mechanically distinct from adjacent browser-delivery notes: stay here when the decisive compromise first lived upstream in a shared package, publisher account, CDN artifact, loader ecosystem, or runtime service that many downstream apps inherited; pivot to frontend-compromise-approval-phishing when one protocol’s own delivery stack was compromised first, to release-provenance-failure when the sharper question is exactly which release-stage object drifted away from the executed artifact, and to third-party runtime allowance and integrity pinning when the sharper question is why a signer-facing page was still allowed to execute mutable remote code in the first place.
-
Typical preconditions:
- A widely reused package, script loader, CDN artifact, wallet SDK, or signer-adjacent client library is fetched dynamically or updated with weak pinning discipline.
- The attacker can publish, replace, or redirect the dependency through compromised maintainer credentials, an offboarding failure, session-token theft, or build/distribution compromise.
- Downstream apps trust the dependency enough that it can influence wallet connection, approval construction, transaction / signature preparation, or direct access to raw private keys.
- Users continue to trust the surrounding dApp because the site URL, branding, and normal workflow remain genuine, or operators continue to trust the backend because it is using a canonical package name and version stream.
- Wallet UX does not make the dangerous spender, permit recipient, or multicall target obvious enough to reliably stop signatures, or backend infrastructure keeps hot keys in the same runtime that now executes attacker-controlled dependency code.
-
Common vulnerable surfaces:
- npm or other package-registry publisher accounts
- dist-tags, mutable semver ranges, and
latest-style runtime resolution that let downstream apps drift onto a poisoned release without a deliberate redeploy - CDN-backed runtime loaders that fetch the latest dependency version on page load — especially convenience loader components whose selling point is
downstream apps get the newest wallet SDK without shipping a new build, because that feature is really delegated signer-surface release authority - wallet-connect and wallet-onboarding SDKs embedded across many dApps
- signer-adjacent SDKs used by bots, relayers, market makers, bridges, custodians, or program-authority tooling
- compromised CI/CD or release pipelines for shared JavaScript artifacts
- maintainer offboarding gaps that leave stale external publishing authority alive
- browser-delivered bundles whose fetched bytes are not pinned with integrity metadata or compared against a locally built artifact
- dependent third-party service identifiers or endpoints baked into the compromised package, such as WalletConnect project IDs, RPC endpoints, or remote config URLs
- incident-response paths that can publish a clean replacement but cannot immediately revoke, purge, or prove disappearance of the poisoned artifact across caches, runtime loaders, or already-exfiltrated secrets
-
Exploit sequence:
- The attacker gains control over a shared dependency’s publishing or distribution path.
- They publish or serve a malicious version that preserves enough expected behavior to keep downstream apps working.
- Legitimate dApps, bots, or backend services load the poisoned package through their normal dependency or runtime-loader flow.
- The malicious code either changes what end users are asked to sign, or captures secret material from code paths that already hold private keys.
- Victims sign approvals, permits, or transaction bundles because the surrounding site and session context are authentic, or operators unknowingly leak hot keys just by running the updated code.
- The attacker drains wallets directly, abuses compromised authorities, or routes value through drainer infrastructure before the compromised package is replaced and caches expire.
- Recovery lags because
clean version publishedandall users now fetch clean bytesare different states, and becausefixed dependency installeddoes not revoke any secrets the malicious version already exfiltrated.
-
Variants:
- Publisher-account compromise — the attacker steals a maintainer account or publishing session and ships a malicious package release.
- Offboarding residue — former employee or contractor access remains live on an external registry even after internal access is revoked.
- Runtime-loader poisoning — downstream apps do not pin a local build and instead fetch mutable dependency code from a CDN or package endpoint at runtime.
- Build-artifact substitution — the source repository may remain benign while the shipped browser bundle or package tarball diverges from the reviewed source tag.
- Transitive dependency compromise — the visible package stays the same, but a nested dependency becomes the malicious execution path.
- Backend-secret exfiltration — the poisoned dependency hooks cryptographic or signing code paths and steals private keys, API secrets, or other authority material from the applications that already handle them.
- Rollback-lag persistence — maintainers republish a good version, but CDN caches, browser caches, mutable loader rules, still-live dependent service credentials, or unrotated exposed keys keep the malicious path alive long after the bad release itself disappears.
-
Detection heuristics:
- Monitor package publication events, maintainer-account changes, token creation / last-use, dist-tag changes, and unexpected release cadence for wallet-critical or signer-critical dependencies.
- Alert when many unrelated dApps suddenly cause approvals, permits, typed-data domains, or multicalls to the same fresh addresses.
- Treat runtime-loaded dependency version drift as a production-security event, not just a front-end release detail.
- Compare reviewed source tags, published tarball hashes, runtime-resolution metadata, dependent service identifiers, and the actual browser-fetched bytes; if those views disagree, assume compromise until proven otherwise. For the sharper release-integrity subfamily that treats those objects as distinct security boundaries in their own right, see release-provenance-failure.
- Diff spender addresses, permit recipients, calldata targets, key-handling code paths, wallet-connection endpoints, and remote loader URLs across dependency upgrades instead of only diffing UI behavior.
- Watch cache behavior during incident response too: a clean re-publish does not mean users have stopped receiving the poisoned artifact if CDN or browser caches still resolve the old bytes.
- Sample the live browser-delivered artifact from multiple regions / edges before reopening the affected flow; rollback claims should be verified at the same layer users actually execute.
- Ask whether downstream apps can keep functioning safely if the shared dependency becomes malicious for one hour, and whether any keys touched during that hour would still be safe without rotation.
-
Defenses:
- Pin audited dependency versions, commit lockfiles, and prefer self-hosted immutable artifacts over mutable runtime loaders for wallet-critical or signer-critical code.
- When the sharper positive-design question is how to prove exact source-to-runtime artifact lineage and how to verify rollback at the same layer users execute, use exact production artifact attestation and rollback discipline.
- Use browser-level integrity controls where possible — content-addressed artifacts, subresource integrity, import-map pinning, or equivalent checks — so a CDN or registry swap cannot silently rewrite wallet-facing code.
- Treat release provenance as its own control plane: source-tag review, tarball publication, dist-tag / loader resolution, CDN distribution, dependent service configuration, and browser delivery should each be monitored and, where possible, independently attestable.
- Harden package publication with strong offboarding, hardware-backed MFA, least privilege, short-lived publishing tokens, and small maintainer sets that are reviewed like production signers.
- Separate
who can merge sourcefromwho can publish artifacts, fromwhat runtime path can become latest automatically, and fromwhich downstream service IDs or remote endpoints the artifact may invoke; compromise at any one of those layers should not be enough to change wallet prompts or signer behavior for production users. - Add integrity monitoring for wallet middleware, spender addresses, typed-data domains, permit recipients, key-handling code paths, signing-flow code paths, and any remote configuration that can redirect wallet traffic.
- Reduce what shared dependencies are allowed to construct, observe, or submit on behalf of users and operators; the more transaction or key authority a package has, the more it should be treated like custody software.
- Isolate hot keys from general-purpose dependency runtime when possible — dedicated signers, hardware-backed keys, remote signing services, and non-extractable key APIs all reduce how much a poisoned package can steal.
- Build rollback playbooks that do more than publish
v+1: disable attacker-controlled service IDs, force exact-version pins, purge CDN caches, fall back to known-good bundled artifacts, rotate exposed secrets, and verify globally that browsers and backends now fetch the expected bytes before telling users the incident is over. - Keep emergency kill-switches, forced-version pins, and coordinated disclosure paths ready for package-level incidents that hit many dApps at once.
What sound design looks like
- A healthy shared-dependency posture treats dependency-path continuity, artifact-lineage truth, and surviving signer authority as separate control questions rather than one vague
we still use the canonical packagecomfort claim. - A healthy shared-dependency posture treats upstream package, loader, CDN, and service operators as signer-adjacent production authority, not as passive developer tooling. The strongest positive-design companion here is exact production artifact attestation and rollback discipline: this family is what breaks when many downstream apps inherit code without preserving one explicit, attestable production object.
- Dependency identity should stay explicit from source to runtime. A secure team can answer
which exact package artifact, loader policy, embedded service identifier, and runtime-fetched bytes did users or bots trust?without swapping between repo tags, semver labels, CDN aliases, and browser-cached payloads as though those were interchangeable. - Shared update convenience should fail closed before it becomes shared wallet authority. If many honest downstream apps depend on one package or runtime loader, healthy design makes version promotion explicit, pins what
latestreally means, and limits what that dependency is allowed to author even when it is functioning normally. - Browser-side prompt construction and backend-side key handling should inherit the same distrust of shared code. The only difference between Ledger Connect Kit and Solana web3.js is whether poisoned bytes shaped wallet prompts or sat beside raw keys; the release and authority boundary should already have been tight enough that both paths were hard to convert into theft.
- Runtime selectors are part of custody. Dist-tags, loader aliases, CDN script URLs, WalletConnect project IDs, RPC endpoints, remote config, and other embedded service identifiers are safe only when they are pinned into the same reviewed production object or fail closed before they can redirect signer-facing behavior.
- Rollback should be designed as ecosystem recovery, not maintainer cleanup. If the compromise path lived in a shared dependency, healthy teams assume recovery is incomplete until downstream clients stop resolving the poisoned artifact, bad service identifiers are disabled, and every secret the package could have observed is rotated or revoked.
- The clean design question is: if a trusted shared package became malicious for one hour, what exact authority could it still exercise across downstream sites, wallets, bots, or custody services, and what independent controls would keep that from turning into approvals, signatures, or key theft?
Failure-prevention checklist
- Inventory every shared dependency, runtime loader, CDN URL, package registry account, dist-tag, and embedded service identifier that can influence wallet prompts, transaction construction, signature requests, or private-key handling. Keep three answers separate for each one:
what familiar dependency path exists,what proves it still resolves to the intended production object, andwhat live authority that object is still allowed to keep. If that inventory is incomplete, the trust boundary is already wider than the team can defend. - Treat
reviewed source,published artifact,resolved version,CDN response, andbrowser/backend executed bytesas separate security objects. Define how each one is pinned, attested, monitored, and rolled back. - Remove automatic
latestbehavior from signer-critical paths. Wallet middleware and signing libraries should move only through explicit version bumps, reviewed lockfile changes, and reproducible artifact promotion. - Prefer shipping signer-facing code as immutable, self-hosted artifacts over runtime-fetched loaders. If a loader must exist, make its resolution policy, hash expectations, and emergency override path explicit before production.
- Require strong offboarding for package registries and other external publishing surfaces, not just internal SSO. Ledger Connect Kit is the reminder that external publisher residue can outlive perfectly clean internal offboarding.
- Separate publishing authority from runtime service authority. A package should not be able to silently switch WalletConnect project IDs, RPC endpoints, remote config URLs, or drainer-controlled downstream services without tripping review and monitoring.
- Keep hot keys and program authorities out of general-purpose dependency runtime whenever possible. Solana web3.js is the reminder that once a poisoned package runs beside raw private keys, package compromise becomes signer compromise.
- Build incident response around the executed artifact, not just the registry event. A clean republish is incomplete until caches are purged, loader rules are pinned, bad service identifiers are disabled, and multiple regions confirm that live clients now fetch known-good bytes.
- Rotate everything the malicious artifact could have observed: private keys, API tokens, project IDs, signing sessions, and any approval or permit authority the bad code could have created or exfiltrated.
- Rehearse ecosystem-wide package incidents ahead of time. Shared-dependency compromise is a many-downstream event, so comms, forced-version pins, temporary feature disablement, and global verification need to work at the same speed as the malicious publish.
Audit prompts
- Which exact shared packages, loaders, SDKs, and CDN-hosted artifacts are currently allowed to shape wallet prompts or touch raw signing material, and where is that list kept current?
- For each signer-critical dependency, what proves that the reviewed source tag, published tarball, lockfile entry, resolved runtime version, dependent service identifiers, and executed bytes still describe the same object?
- Could a compromised maintainer account publish a malicious version or retarget a dist-tag without a second person noticing before users or bots execute it?
- Do any production pages still fetch wallet middleware or approval-constructing code at runtime from mutable third-party URLs, and if so what exact integrity pin or emergency kill switch constrains that fetch?
- If a dependency changed WalletConnect project IDs, permit recipients, spender addresses, RPC endpoints, or remote config URLs, what monitoring would fire before user assets or operator keys were at risk?
- Which services still handle raw private keys in the same runtime that executes ordinary dependency code, and what would stop a poisoned package from exfiltrating them immediately?
- Can incident response prove rollback at the layer users actually execute — including CDN edges, browser caches, runtime loaders, and backend package resolution — or can it only prove that a clean version was published?
- If a malicious package lived for one hour, what authorities would still need rotation afterward even if the package were already unpublished?
- Are external publishing surfaces included in employee offboarding and credential review, or does the organization only strongly govern internal repos and SSO?
- When a shared dependency incident hits many downstream apps at once, who owns coordinated version pinning, wallet warnings, ecosystem notifications, cache purge checks, and cross-region live-byte verification?
Lessons that should already be standard
-
The familiar package / loader path still exists,that path still resolves to the intended artifact lineage, andthat accepted lineage still deserves broad wallet or signer authorityare three different claims. -
Shared dependency publishers are signer-adjacent production operators, not low-risk developer convenience accounts.
-
We reviewed the sourceis not evidence about what users executed. Supply-chain incidents live in the gap between source identity and runtime bytes. -
Runtime loaders are delegated release authority. If a dApp can pull the newest wallet SDK on page load, it has outsourced part of its signing surface to whoever controls that distribution path.
-
Offboarding is not complete until external registries and publishing tokens are gone too. Ledger Connect Kit showed how one stale external account can become ecosystem-wide wallet-drain authority.
-
Replacing a bad package version is not the same as ending the incident. Caches, mutable loader rules, stolen service identifiers, and already-exfiltrated secrets keep the blast radius alive after the registry looks clean.
-
Package compromise splits cleanly into two theft branches: browser-side prompt corruption and backend-side secret exfiltration. The defenses overlap, but the second branch means some teams are still treating custody software like a normal library update.
-
If a package can observe raw private keys, construct arbitrary permit payloads, or select transaction endpoints, it already deserves controls closer to production signer infrastructure than to ordinary front-end tooling.
-
The hardest part of rollback is proving disappearance, not publishing a fix. Teams need a habit of sampling live executed bytes, not just trusting dashboards that say the latest release is good.
-
High-signal incidents:
- flatmap-stream transitive-dependency backdoor (2018-11-26) — the clean transitive-dependency / build-artifact-substitution cousin: social capture of
event-streammaintainership plus maliciousflatmap-stream@0.1.1turned Copay release builds into wallet implants that exfiltrated high-balance BTC/BCH private keys. - Ledger Connect Kit npm supply-chain wallet drainer (2023-12-14) — the clean front-end / wallet-prompt preserved case where a phished former employee’s still-authorized NPMJS publishing access let the attacker ship malicious
@ledgerhq/connect-kitreleases, which many legitimate dApps then loaded through Ledger’s runtime distribution path and turned into wallet-drainer prompts. - Polyfill.io domain-sale runtime-delivery malicious-redirect supply-chain incident (2024-06-25) — the clean
same script URL, different operator, different runtime bytescousin: downstream sites kept trustingcdn.polyfill.io, but domain-ownership drift plus request-time JavaScript generation turned that familiar URL into mobile-targeted redirect and scam-delivery infrastructure. - private-key exfiltration (2024-12-03) — the clean backend-signer / secret-exfiltration cousin: compromised publish access for
@solana/web3.jsturned package publication into direct theft from bots and backends that handled raw private keys in-process. - unresolved secret-extraction drain (2023-06-03) — the unresolved wallet-vendor cousin: the exact intrusion path never received a clean public postmortem, but thousands of wallets were still drained through valid user authority, making it a good reminder that shared wallet software, update, and infrastructure surfaces can become a de facto custody bottleneck even when the vendor calls itself non-custodial.
- Adjacent site-delivery cousin: BadgerDAO Cloudflare Worker injected approval drain (2021-12-02) — same
real site, malicious promptoutcome family, but the compromised control surface was one protocol’s edge-delivery layer rather than a shared upstream dependency.
- flatmap-stream transitive-dependency backdoor (2018-11-26) — the clean transitive-dependency / build-artifact-substitution cousin: social capture of
Internal linkages
- Parent / adjacent family: frontend-compromise-approval-phishing — both classes weaponize user trust in a real interface, but this branch preserves the upstream
shared dependency compromised firstversion rather than theone protocol's site delivery got hijackedversion; if the compromise would still be accurately described even after replacing one dApp with another honest downstream app, stay here first. - Adjacent browser-policy companion: Third-party runtime allowance and integrity pinning — use that note when the sharper preserved lesson is
our wallet page still allowed mutable remote code to executeeven if no ecosystem-wide shared dependency compromise is needed to tell the story; use this note when the compromise first lived upstream in the shared dependency or runtime-service ecosystem itself. - Adjacent deeper cut on release identity drift: release-provenance-failure — the sharper subfamily for cases where source review, tarball publication, loader resolution, CDN delivery, browser-fetched bytes, or embedded service identifiers stop being the same trusted object; use it when the main analytical lift is not merely
shared dependency got poisoned, butwhich exact release-stage object drifted and how rollback had to be proven at the runtime layer users or operators actually executed. - Positive-design companion: Exact production artifact attestation and rollback discipline — the checklist for keeping one explicit production artifact lineage intact and for proving rollback once the bad artifact has already shipped.
- Adjacent pattern: arbitrary-call-token-approval-drain — software supply-chain compromise often ends in the same
transferFrom()theft primitive, but the authority is captured through poisoned interface code instead of a buggy onchain router. - Best transitive-dependency / build-artifact-substitution case so far: copay-event-stream-flatmap-stream-transitive-dependency-backdoor-2018-11-26.
- Best runtime-URL / service-identity drift case so far: polyfill-io-domain-sale-runtime-delivery-malicious-redirect-supply-chain-incident-2024-06-25.
- Best front-end package-loader case study so far: ledger-connect-kit-npm-supply-chain-wallet-drainer-2023-12-14 — the clean
same real site, different loader-resolved bytescousin. - Best backend-signer case study so far: solana-web3js-npm-publish-account-compromise-private-key-exfiltration-2024-12-03 — the clean
same package name, different custody semanticscousin.
Control surface
-
The real leverage sits in whoever can preserve or corrupt those three promotions: package and loader naming continuity, exact artifact-lineage and runtime-byte truth, and the surviving wallet / signer / backend authority budget granted to that accepted lineage.
-
The real leverage sits in package publication, dependency pinning, runtime artifact distribution, wallet middleware, release provenance, dependent service identifiers, and whatever browser or backend code is allowed to shape signing prompts or touch raw private keys.
-
The critical operator boundary is broader than
npm maintainer account: it includes source-tag custody, tarball publication, dist-tag or loader resolution, CDN cache behavior, remote project / service identifiers embedded in the package, and the exact browser-fetched or backend-resolved payload that finally constructs wallet prompts or handles hot keys. -
In this family, source review alone is not enough. The question is whether the exact bytes fetched by the browser or backend still match the reviewed release, whether the runtime path still points at the intended service endpoints, and whether downstream apps have any independent way to notice when that stops being true.
-
Recovery discipline is part of the same control surface. If operators cannot quickly prove that the bad artifact, bad remote config, bad service credentials, and already-exposed secrets are all gone or rotated, the exploit path is still partially live.
-
If a shared wallet-facing or signer-facing dependency can silently change, a whole ecosystem of uncompromised domains and backends can inherit the same theft path at the same time.
-
Sources:
- https://blog.npmjs.org/post/180565383195/details-about-the-event-stream-incident
- https://www.ledger.com/blog/security-incident-report
- https://www.blockaid.io/blog/attack-report-ledger-connect-kit
- https://www.sonatype.com/blog/decrypting-the-ledger-connect-kit-compromise-a-deep-dive-into-the-crypto-drainer-attack
- https://slowmist.medium.com/supply-chain-attack-on-ledger-connect-kit-analyzing-the-impact-and-preventive-measures-1005e39422fd
- https://sansec.io/research/polyfill-supply-chain-attack
- https://blog.cloudflare.com/polyfill-io-now-available-on-cdnjs-reduce-your-supply-chain-risk/
- https://blog.cloudflare.com/automatically-replacing-polyfill-io-links-with-cloudflares-mirror-for-a-safer-internet/
- https://www.sonatype.com/blog/polyfill.io-supply-chain-attack-hits-100000-websites-all-you-need-to-know
- 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
-
Last reviewed: 2026-07-31 UTC