$1,000,000 in security audit grants are live now, Apply here →

← Resource Hub

dApp Frontend Supply Chain Security: npm Attack Mitigation

By the Guardian team Updated 6 min read

dApp Frontend Supply Chain Security: npm Attack Mitigation

Quick answer. Build only from a committed lockfile with npm ci, block dependency install scripts and delay new releases. Keep secrets out of install jobs, publish with trusted publishing, restrict connect-src in your CSP and alert on new dependency versions.

Watch: dApp Frontend Supply Chain Security: npm Attack Mitigation 1:37
Video transcript

A dApp frontend is mostly other people's code. One bad npm release can run on your build machines, and in your users' browsers beside their wallets.

Each attack here began with an attacker publishing under a trusted name, not a code bug. Every app that pulled the new version ran their code.

In September 2025, phishing one maintainer compromised chalk, debug and 16 other packages, with over two billion weekly downloads. The payload swapped wallet addresses in the browser.

Decide exactly what you install. Build from a committed lockfile, pin critical packages, never load the latest version at runtime, add a release cooldown, and verify signatures.

Install scripts are where npm malware runs. Block dependency scripts, keep deploy keys and tokens out of install jobs, and limit outbound traffic. Use trusted publishing and phishing-resistant two-factor authentication.

Malicious code in your bundle runs from your own origin, so subresource integrity won't block it. A tight connect source limits where it can send data. The wallet stays the final check.

Alert on every new dependency version. When a bad one lands, find where it was installed, rebuild clean, rotate every secret installs could read, then redeploy and tell users.

Guardian's offchain team, led by HackTricks creator Carlos Polop, pentests supply chain exposure in your bundle and CI runners. Read the full guide, or talk to Guardian.

A dApp frontend is mostly other people's code. Every package in its lockfile can run on your build machines, and in your users' browsers next to their wallets.

Attackers have used both. Compromised npm releases have drained wallets through a Ledger library, stolen Solana keys and swapped addresses in the browser.

This guide covers the npm layer: how a bad release reaches a dApp, and the controls that stop it. For hosting, build provenance, SRI and signer checks, see our guide to signing interface security.

How npm Attacks Reach a dApp

Each incident below began with an attacker publishing under a trusted name, not with a code bug. Every app that pulled the new version ran their code.

IncidentDateWay inPayload
Ledger Connect KitDec 2023Former employee's npm access phishedWallet drainer in dApps
@solana/web3.jsDec 2024Publish account compromisedPrivate key theft
chalk, debug and 16 moreSep 2025Maintainer phished via npmjs.helpBrowser address swapper
Shai-HuludSep 2025Maintainer accounts, then self-spreadingSecrets stolen at install
Shai-Hulud 2.0Nov 2025New variant of the wormCloud and CI secrets
axiosMar 2026Direct npm publish, no GitHub tagRemote access trojan

Those releases reach a dApp in two ways.

  • Build time. Install scripts run on laptops and CI runners, where npm tokens, cloud keys and deploy credentials live.
  • Run time. Bundled code runs in the user's browser, beside the wallet, and can change what gets signed.

Run time: Ledger and chalk

On December 14, 2023, Ledger Connect Kit versions 1.1.5 to 1.1.7 shipped the Angel Drainer, which routed funds through a rogue WalletConnect project.

Most dApps loaded the kit at runtime from a CDN through Connect-Kit-loader, Ledger said. They received the malicious code without rebuilding anything.

On September 8, 2025, 18 packages including chalk and debug were compromised after their maintainer was phished. Together they had over 2 billion weekly downloads.

The payload hooked window.ethereum, fetch and XMLHttpRequest, swapped wallet addresses and altered transactions before signing, Aikido found.

Build time: Shai-Hulud and axios

Shai-Hulud hit npm in mid-September 2025. Its install script used TruffleHog to find secrets, then republished packages its stolen npm tokens could reach.

GitHub removed more than 500 compromised packages.

A second wave in November 2025 trojanized packages from projects including ENS Domains. It exposed secrets in over 25,000 GitHub repositories, Wiz reported.

In March 2026, two axios releases added a new dependency, plain-crypto-js. Its postinstall script dropped a remote access trojan, Socket reported.

Pin, Delay and Verify

The first control is deciding exactly which code you install, and refusing anything new by default.

  • Build with npm ci. It fails if the lockfile and package.json disagree, and never rewrites either.
  • Pin critical packages exactly. Socket noted any project on ^1.14.0 would pull the bad axios on its next install.
  • Never load the latest version at runtime. The Ledger loader turned one npm publish into a live change in every dApp using it.
  • Add a release cooldown. pnpm's minimumReleaseAge holds back new versions; its current docs list a default of one day.
  • Check signatures. npm audit signatures verifies registry signatures and provenance attestations.
  • Refuse trust downgrades. pnpm's trustPolicy: no-downgrade fails an install when a package's trust level drops.

Provenance shows where a package was built, not that it is safe. npm's docs say it "does not guarantee the package has no malicious code."

A cooldown buys time for detection. Socket flagged axios's malicious dependency six minutes after it was published. The @solana/web3.js advisory covers a window of about five hours.

Harden Installs and CI

Install scripts are where npm malware runs at build time. Shai-Hulud and the axios dropper used postinstall; Shai-Hulud's second wave ran at preinstall.

  • Block dependency scripts. Use npm ci --ignore-scripts, or pnpm, which blocks build scripts not listed in allowBuilds.
  • Install without secrets. Run install and build in a job with no deploy keys, npm tokens or cloud credentials.
  • Limit egress. Wiz advises restricting CI outbound traffic to trusted domains.
  • Use trusted publishing. OIDC replaces long-lived npm tokens, and npm "strongly" recommends then restricting token publishing.
  • Use phishing-resistant 2FA. GitHub said in September 2025 it would move npm from TOTP to FIDO-based 2FA.

Tokens matter. In the axios case, Socket reported early discussion that a long-lived npm token, kept alongside trusted publishing, "may have allowed unauthorized access."

Contain Code in the Browser

Some malicious code will reach a bundle. The usual browser controls do less here than you might expect.

SRI blocks a swapped file, and a strict script-src blocks scripts from other hosts. Bundled malware sits inside your own file, so both let it run.

Two controls still help.

  • A tight connect-src. This CSP directive limits where fetch, XHR, WebSockets and beacons can connect.
  • The wallet as the final check. The chalk payload altered transactions before signing, so users must verify on the device.

Monitor and Respond

Watch releases

  • Alert on every new version of a direct dependency, and on any publish under your own npm scope.
  • Diff each production bundle against the last, and flag new network hosts.
  • Follow advisories for the wallet, signing and RPC libraries you ship.

When a bad version lands

  1. Find exposure. Search lockfiles, branches and open PRs for the bad versions, as Socket advised for axios.
  2. Rebuild clean. Delete node_modules, clear the npm cache and move to a clean release, per Wiz.
  3. Rotate what installs could read. npm and GitHub tokens, SSH keys and cloud credentials.
  4. Rotate onchain authorities if keys were reachable. The @solana/web3.js advisory names multisig keys, program authorities and server keypairs.
  5. Audit GitHub. Look for unfamiliar workflows and repositories; Shai-Hulud created both.
  6. Redeploy and tell users. Ship a clean build, then say which versions and dates were affected.

Caches slow a response. Ledger deployed a fix within 40 minutes of becoming aware, but CDN caching kept the bad file reachable a little longer.

How Guardian Helps

Guardian's offchain department is led by Carlos Polop, creator of HackTricks and the PEASS privilege escalation suite.

Its web app pentests cover the client-side surface, including "supply-chain exposure in the bundle". Infrastructure pentests cover CI/CD runners and "dependency and artifact integrity".

Managed Security matches vulnerability disclosures against your system in real time, and an engineer confirms any exposure. The March 2026 axios compromise is one example on its page.

The supply chain is one layer of a wider attack surface. See what offchain security covers.

Frequently Asked Questions

How do I protect my dApp frontend from compromised npm packages?

Build from a committed lockfile with npm ci, block dependency install scripts and hold back brand-new releases. Keep secrets out of install jobs, publish with trusted publishing, set a strict CSP with connect-src, and alert on every new dependency version.

Does a lockfile stop npm supply chain attacks?

Partly. With npm ci, a lockfile stops builds pulling a newer malicious version. It cannot help if the locked version is malicious, or if the app loads code from a CDN at runtime, as with Ledger Connect Kit.

What is npm provenance?

A signed attestation linking a package to its source repository and the CI build that produced it. You can check it with npm audit signatures. npm's docs note that it does not guarantee the package has no malicious code.

Can a Content Security Policy stop a malicious npm package?

Not on its own. Code bundled into your app runs from your own origin, so script-src allows it. A tight connect-src limits where it can send data, and the wallet remains the final check on what gets signed.

Sources

Test the code your users actually load

Guardian's offchain team, led by Carlos Polop, pentests your web app, its build pipeline and the infrastructure behind it.