DEV Community

Cover image for How to Secure NPM Dependencies ? A Complete Supply Chain Security Guide for API Developers
Wanda
Wanda

Posted on • Originally published at apidog.com

How to Secure NPM Dependencies ? A Complete Supply Chain Security Guide for API Developers

TL;DR

NPM supply chain attacks spiked to over 3,000 malicious packages in 2024. The 2026 Axios compromise proved even top-10 packages are targets. This guide gives API developers practical, actionable defenses: lockfile enforcement, postinstall script blocking, provenance verification, behavioral analysis, and architectural choices to reduce your attack surface.

Try Apidog today

Introduction

The Axios supply chain attack (March 31, 2026) wasn’t the first npm compromise—and won’t be the last. With 83 million weekly downloads and a cross-platform RAT deployed via a single hijacked maintainer, it was a major wake-up call for the JavaScript ecosystem.

This attack bypassed all traditional defenses:

  • Malicious code wasn't in Axios itself.
  • It used a phantom dependency and a postinstall hook.
  • Lockfiles didn’t help if you ran npm install during the attack window.
  • Version pinning didn’t help if you hadn’t already pinned.

API developers are especially exposed—your CI/CD, tests, mock servers, and HTTP clients all install from npm. Any compromised package in your toolchain can leak API keys, database credentials, or cloud tokens from your dev machine.

💡 Apidog eliminates one major attack vector by providing a built-in HTTP client for API testing. You don’t need Axios, node-fetch, or got in your testing stack. Download Apidog free to reduce your npm dependency surface while following the defense strategies below.

This guide covers seven layers of protection, from lockfile hygiene to advanced behavioral analysis.

Layer 1: Lockfile Enforcement

Why lockfiles matter

A lockfile records the exact version of every package and transitive dependency at installation. Without it, npm install resolves the latest version matching your semver range. If your package.json has "axios": "^1.14.0" and a malicious 1.14.1 appears, you get the malicious version.

The rules

1. Always commit your lockfile.

Whether it’s package-lock.json (npm), yarn.lock (Yarn), pnpm-lock.yaml (pnpm), or bun.lock (Bun), put it in version control.

2. Use frozen installs in CI/CD.

Never run npm install in automation. Use these instead:

# npm
npm ci

# yarn
yarn install --frozen-lockfile

# pnpm
pnpm install --frozen-lockfile

# bun
bun install --frozen-lockfile
Enter fullscreen mode Exit fullscreen mode

npm ci deletes node_modules and installs exactly from the lockfile, failing if mismatched. No surprises.

3. Review lockfile diffs in PRs.

If a PR changes package-lock.json, review the diff. New dependencies, version bumps, and registry URL changes all require scrutiny. Tools like Socket.dev can automate flagging suspicious changes.

The lockfile gap

Lockfiles don’t protect against the first install. If you add a new dependency or initialize a project during an attack window, the malicious version gets locked in. That’s why lockfiles are only Layer 1.

Layer 2: Disable Postinstall Scripts

The primary attack vector

The Axios attack, ua-parser-js, event-stream, and many others used the same trick: a postinstall script that runs arbitrary code during npm install—before you see the code or run your app.

Block scripts globally

Add to your .npmrc:

ignore-scripts=true
Enter fullscreen mode Exit fullscreen mode

Or via CLI:

npm config set ignore-scripts true
Enter fullscreen mode Exit fullscreen mode

This blocks all lifecycle scripts (preinstall, install, postinstall, prepare) during install.

Handling packages that need scripts

Some packages (e.g., bcrypt, sharp, sqlite3) require postinstall scripts for compilation. Options:

Option 1: Run scripts only after install

npm ci --ignore-scripts
npm rebuild bcrypt sharp
Enter fullscreen mode Exit fullscreen mode

Option 2: Use an allowlist (npm 10+)

Create .scriptsrc.json:

{
  "allowScripts": {
    "bcrypt": true,
    "sharp": true
  }
}
Enter fullscreen mode Exit fullscreen mode

Option 3: Use prebuilt binaries

Many packages now provide prebuilt binaries (like sharp), so check if you can avoid native compilation.

The PackageGate caveat

In Jan 2026, "PackageGate" zero-days showed: Git-based dependencies can include config files that enable code execution even when lifecycle scripts are disabled. If you use Git URLs for dependencies, pin to specific commit hashes and audit the repo.

Layer 3: Pin Exact Versions

Stop using semver ranges

Default npm install --save adds packages with a caret:

{
  "axios": "^1.14.0"
}
Enter fullscreen mode Exit fullscreen mode

The ^ means “compatible with 1.14.0”—so you'll get the latest 1.x.x, even if it's malicious.

Pin exact versions:

{
  "axios": "1.14.0"
}
Enter fullscreen mode Exit fullscreen mode

Set npm to always save exact versions:

# .npmrc
save-exact=true
save-prefix=''
Enter fullscreen mode Exit fullscreen mode

Use overrides for transitive dependencies

Direct dependencies have their own dependencies. If a transitive dep is compromised, pinning your direct dep isn’t enough.

For npm:

{
  "overrides": {
    "axios": "1.14.0",
    "plain-crypto-js": "npm:empty-npm-package@1.0.0"
  }
}
Enter fullscreen mode Exit fullscreen mode

For Yarn:

{
  "resolutions": {
    "axios": "1.14.0"
  }
}
Enter fullscreen mode Exit fullscreen mode

For pnpm:

{
  "pnpm": {
    "overrides": {
      "axios": "1.14.0"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

The trade-off

Exact pinning blocks automatic patch updates. You'll need to manually bump versions—extra maintenance, but vital for high-security projects.

Layer 4: Verify Package Provenance

What provenance means

Npm provenance attestation links a published package to its source code and build environment using Sigstore signatures. When enabled, you get cryptographic proof of:

  • Source repository
  • CI/CD system
  • Commit that triggered build

How to check provenance

npm audit signatures
Enter fullscreen mode Exit fullscreen mode

This verifies installed packages’ provenance. Malicious Axios versions lacked OIDC provenance and GitHub commits. Automated provenance checks would have flagged the attack.

Enable provenance for your own packages

In your CI/CD, enable provenance:

# GitHub Actions example
- uses: actions/setup-node@v4
  with:
    node-version: 20
    registry-url: https://registry.npmjs.org
- run: npm publish --provenance
  env:
    NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
Enter fullscreen mode Exit fullscreen mode

Add to .npmrc:

provenance=true
Enter fullscreen mode Exit fullscreen mode

Limitations

Provenance is opt-in (most packages don’t have it yet). It proves where a package was built, but not that the code is safe—a compromised CI/CD can still publish malicious code.

Layer 5: Use Behavioral Analysis Tools

Beyond vulnerability scanning

Tools like npm audit and Snyk only catch known vulnerabilities (CVEs). They miss zero-days like the Axios compromise.

Behavioral analysis tools examine what packages do—not just public vulnerability reports.

Socket.dev

Socket analyzes behavior during install and runtime, flagging:

  • Network requests during install
  • File system access outside package directory
  • Shell command execution
  • Environment variable harvesting
  • Obfuscated code

Socket.dev scan example

With GitHub integration, Socket comments on PRs if new dependencies behave suspiciously. The Axios attack’s plain-crypto-js would have triggered multiple Socket alerts.

# Install Socket CLI
npm install -g @socketsecurity/cli

# Scan your project
socket scan
Enter fullscreen mode Exit fullscreen mode

Snyk

Snyk provides vulnerability management for known issues.

# Install Snyk CLI
npm install -g snyk

# Test your project
snyk test
Enter fullscreen mode Exit fullscreen mode

Snyk scan example

Layered approach

Use all three:

# Baseline
npm audit

# Behavioral analysis
socket scan

# Vulnerability management
snyk test
Enter fullscreen mode Exit fullscreen mode

Run these in CI/CD. Any critical finding should block the build.

Layer 6: Minimize Your Dependency Surface

The deeper question

Every package in node_modules is a trust decision. Axios was compromised with 83 million weekly downloads. The average Node.js project has hundreds of transitive dependencies—each a potential attack vector.

Fewer dependencies = less to defend.

Audit your dependency tree

# Count total dependencies
npm ls --all | wc -l

# Check for duplicates
npm ls --all | sort | uniq -c | sort -rn | head -20
Enter fullscreen mode Exit fullscreen mode

For each dependency, ask:

  • Does Node.js provide this natively now? Node.js 18+ includes fetch, crypto, URL, FormData, etc.
  • Does this dependency pull dozens of transitive deps? One package can multiply your attack surface.
  • Can you vendor this? For tiny utilities, copy source into your repo.

Native alternatives for common packages

Package Native alternative Available since
axios, node-fetch, got fetch (global) Node.js 18
uuid crypto.randomUUID() Node.js 19
dotenv --env-file flag Node.js 20.6
chalk util.styleText() Node.js 21.7
glob fs.glob() Node.js 22
path-to-regexp Native URL pattern API Node.js 23

For API testing specifically

API testing often brings in HTTP clients, assertion libs, test runners, and mock servers—each a dependency and attack surface.

API testing stack

Apidog replaces the whole stack with a single platform:

  • HTTP client: Built-in. No npm dependency.
  • Assertions: Visual builder with built-in assertions.
  • Test runner: Automated scenarios with CI/CD via Apidog CLI.
  • Mock server: Dynamic responses, no Express or third-party mock libraries.
  • Documentation: Auto-generated from your API specs.

Move API testing into Apidog to eliminate dozens of npm dependencies. Fewer dependencies = fewer attack vectors.

Try Apidog free to consolidate your API testing stack.

Layer 7: Network and Runtime Monitoring

Block known-bad domains

After a supply chain attack, block C2 infrastructure at the network level:

# Add to /etc/hosts
echo "0.0.0.0 sfrclak.com" | sudo tee -a /etc/hosts
Enter fullscreen mode Exit fullscreen mode

In CI/CD, restrict outbound network access to only allowed domains (npm registry, your git host, deployment targets).

Use StepSecurity Harden-Runner for CI/CD

StepSecurity’s Harden-Runner monitors GitHub Actions workflows, detecting network calls, process exec, and file changes in real time. It caught the Axios dropper’s C2 call within 1.1 seconds.

  • Outbound network monitoring
  • Process execution tracking
  • File integrity monitoring
  • Alerts for anomalous behavior
# GitHub Actions
- uses: step-security/harden-runner@v2
  with:
    egress-policy: audit  # or 'block' for strict mode
Enter fullscreen mode Exit fullscreen mode

Runtime process monitoring

For development machines, use endpoint detection & response (EDR) tools to flag suspicious child processes from Node.js. The Axios RAT spawned osascript (macOS), cscript (Windows), and python3 (Linux) from npm install—these are detectable patterns.

Recommended .npmrc Configuration

A security-hardened .npmrc:

# Pin exact versions
save-exact=true
save-prefix=

# Disable lifecycle scripts
ignore-scripts=true

# Enable provenance for publishing
provenance=true

# Use the official registry
registry=https://registry.npmjs.org/

# Require 2FA for publishing
auth-type=web

# Audit level threshold
audit-level=moderate
Enter fullscreen mode Exit fullscreen mode

Commit this file to your repo so everyone uses the same settings.

CI/CD Security Pipeline Example

A GitHub Actions workflow enforcing all seven layers:

name: Secure Build
on: [push, pull_request]

jobs:
  security-check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: step-security/harden-runner@v2
        with:
          egress-policy: audit

      - uses: actions/setup-node@v4
        with:
          node-version: 22

      # Layer 1+2: Frozen lockfile, no scripts
      - run: npm ci --ignore-scripts

      # Layer 3: Verify no unexpected versions
      - run: npm ls --all > deps.txt

      # Layer 4: Check provenance
      - run: npm audit signatures

      # Layer 5: Behavioral analysis
      - run: npx socket scan

      # Layer 5: Vulnerability scan
      - run: npx snyk test

      # Layer 1: Baseline audit
      - run: npm audit --audit-level=moderate

      # Rebuild only allowed native deps
      - run: npm rebuild sharp bcrypt
Enter fullscreen mode Exit fullscreen mode

What’s Coming Next for npm Security

Mandatory provenance for popular packages

Npm may soon require provenance attestation for high-download packages, blocking manual publishing methods that enabled the Axios attack.

Two-person release approval

Packages with massive downloads may need a second maintainer’s approval for releases—raising the bar for attackers.

Runtime permission scoping

Deno restricts script permissions (network, file system, env vars) unless explicitly allowed. Node.js is exploring similar models. When released, scripts like postinstall will need explicit permissions.

Package manager convergence

pnpm’s strict isolation (packages can only access declared deps) blocks many confusion attacks. Expect npm to adopt similar strictness.

FAQ

What is a supply chain attack in npm?

A supply chain attack targets your dependencies—not your application directly. Attackers compromise maintainer accounts, inject code into packages, or publish typosquats. When you install or update, malicious code runs on your machine or CI/CD, stealing credentials or installing backdoors.

Is npm audit enough to protect against supply chain attacks?

No. npm audit checks public vulnerability databases (CVEs), but zero-days like Axios aren’t listed when they happen. Use behavioral tools like Socket.dev as well. npm audit is the baseline—not your only defense.

Should I stop using npm entirely?

No. npm is the largest package ecosystem and most packages are safe. Reduce exposure with version pinning, lockfile enforcement, script blocking, and minimizing dependencies. Prefer native APIs when possible.

How does Apidog help reduce npm supply chain risk?

Apidog provides a built-in HTTP client, test runner, mock server, and documentation generator for API dev. You don’t need Axios, node-fetch, Jest, Express, or other testing dependencies—so you have fewer npm attack vectors.

What is package provenance in npm?

Provenance uses Sigstore to cryptographically link a package to its source repo and CI/CD build. You can verify with npm audit signatures. Packages published manually lack provenance—a red flag for high-download packages.

How many npm packages are malicious?

Snyk found 3,000+ malicious npm packages in 2024. By Q4 2025, Sonatype blocked over 120,000 malware attacks in package registries. Most are low-download typosquats, but incidents like Axios show even top packages are at risk.

What is the PackageGate vulnerability?

PackageGate is a set of six zero-days (Jan 2026) affecting npm, pnpm, vlt, and Bun. Git-based dependencies can enable code execution even with lifecycle scripts disabled. Pin Git deps to commit hashes and audit contents.

Key Takeaways

  • Commit and enforce lockfiles—but they only protect after first install.
  • Disable postinstall scripts globally with ignore-scripts=true in .npmrc.
  • Pin exact versions using save-exact=true to avoid semver range surprises.
  • Verify provenance with npm audit signatures to catch manual uploads.
  • Layer Socket.dev (behavior analysis) and Snyk (known vulnerabilities) on top of npm audit.
  • Reduce dependency count with Node.js native APIs and integrated platforms like Apidog.
  • Monitor CI/CD network egress with StepSecurity Harden-Runner.

Every dependency is a trust decision. Fewer dependencies = smaller attack surface. More verification layers = harder for attackers. Build defense in depth, not isolation.

Top comments (0)