Frequently Asked Questions About npm Supply Chain Lockdown Framework

21 answers covering everything from basics to advanced usage.

// Basics

What is a supply chain attack in npm?

A supply chain attack in npm is when an attacker publishes or modifies a package in the npm registry to execute malicious code on developers' machines. This typically happens through malicious post-install scripts, typosquatted package names, compromised maintainer accounts, or tampered lock files. The attack executes the moment you run `npm install`, before you ever use the package in your code. The npm Supply Chain Lockdown Framework addresses each of these vectors with a dedicated layer of defense.

What is the difference between install scripts and regular package code?

Install scripts (pre-install, post-install, etc.) run automatically during `npm install` — before you ever import or use the package. Regular package code only executes when your application explicitly imports it. This distinction is critical because nearly every supply chain attack uses install scripts as the execution vector: the malicious code runs the moment the package lands on your machine, not when you call a function from it. Blocking install scripts by default eliminates this primary attack surface.

Why does pinning exact versions not fully protect me from supply chain attacks?

Pinning exact versions in your package.json only locks your direct dependencies. Your dependencies' dependencies (transitive deps) still use semver ranges and resolve dynamically. An attacker who compromises a transitive dependency can still inject malicious code into your project. This is why release age gating remains critical even with pinned versions — it protects the entire dependency tree, including transitive packages, by refusing to install anything published too recently.

How many dependencies is too many for a Node.js project?

There is no magic number, but the principle is clear: every dependency is an attack surface, and attacks primarily spread through transitive dependencies. Before adding a package, ask whether a native API (like fetch instead of axios) or a small utility function achieves the same result. In agentic coding contexts, ask the AI to write the function instead of importing a package. Audit your existing dependencies periodically and remove anything replaceable. Fewer dependencies means fewer attack vectors and a smaller blast radius if one is compromised.

// How To

How do I configure release age gating for pnpm?

Add `minPackageAge: 10080` to your pnpm-workspace.yaml or pnpm.config.yaml file. The value is in minutes, so 10080 equals 7 days. Note that pnpm 11 and later defaults to 1 day (1440 minutes) even without this setting, but increasing it to 7 days provides stronger protection. The setting causes pnpm to install the most recent version of a package that is older than the threshold, silently skipping anything published within the gating window.

How do I set up lockfile-lint in a CI pipeline?

Install lockfile-lint as a dev dependency with `npm install --save-dev lockfile-lint`. Add a script to your package.json like `"lint:lockfile": "lockfile-lint --path package-lock.json --type npm --allowed-hosts npm --validate-https"`. Run this script as a step in your CI pipeline before `npm ci`. It will fail the build if any resolved URL points to an untrusted host, if URLs don't match declared package names, or if integrity hashes appear tampered. This catches lock file manipulation attacks before they execute.

How do I alias my install command to Socket Firewall?

Install Socket's CLI tool globally, then create shell aliases so that `npm install`, `pnpm install`, or `bun install` route through Socket first. The exact alias syntax depends on your shell (bash, zsh, fish). After setting up the alias, clear your package manager cache with `npm cache clean --force`, `pnpm store prune`, or equivalent so that all previously cached packages are re-scanned. Socket will then block confirmed malicious packages and warn on AI-detected threats before any package reaches your machine.

How do I switch from npm install to npm ci in GitHub Actions?

In your GitHub Actions workflow YAML, replace every `run: npm install` step with `run: npm ci`. Ensure your `package-lock.json` is committed to version control and not in `.gitignore`. `npm ci` will install exactly what is recorded in the lock file and fail with an error if the lock file and package.json are inconsistent. This guarantees deterministic builds and prevents silent dependency resolution that could introduce unreviewed package versions.

// Troubleshooting

Why is my bun trustedDependencies empty array not blocking install scripts?

This is a known bug in bun. Setting `trustedDependencies` to an empty array (`[]`) in package.json does NOT override bun's built-in curated allow list. The curated list continues to permit scripts for certain well-known packages. To force the override, add at least one explicit package name to the array. If you want to block all scripts, add a single package you actually trust (like `esbuild`) — this triggers the override and blocks everything else. Run `bun pm untrusted` to verify which packages still have pending scripts.

My install fails after enabling ignore-scripts — how do I fix it?

Some packages legitimately need install scripts to compile native binaries or fetch platform-specific assets (e.g., esbuild, sharp, node-sass). After setting `ignore-scripts=true` in .npmrc, install the `allow-scripts` package (Lava Moat) and add an allow list in your package.json specifying only the packages that genuinely need scripts. For pnpm, run `pnpm approve-builds` to interactively review and approve specific packages. For bun, add them to `trustedDependencies`. Only approve packages you've verified need script execution.

lockfile-lint is flagging my lock file but I haven't been attacked — what's happening?

lockfile-lint may flag legitimate issues that aren't attacks but still indicate risk. Common false positives include resolved URLs pointing to a private registry you haven't whitelisted in the lockfile-lint config, or packages using HTTP instead of HTTPS. Add your private registry to the `--allowed-hosts` flag and ensure `--validate-https` is set. If the flag is about a mismatched package name and URL, investigate — even if not malicious, it indicates a lock file integrity problem that should be resolved.

Should I clear my package manager cache after setting up the Lockdown Framework?

Yes, clearing the cache after installing a firewall tool (Socket or npq) is mandatory. Previously cached packages were downloaded without firewall scanning and may include undetected malicious code. If you skip this step, your next install may serve compromised packages from cache without re-scanning them. Use `npm cache clean --force` for npm, `pnpm store prune` for pnpm, or the equivalent bun command. This ensures every package is scanned on the next install.

What happens if I don't commit my lock file to version control?

If your lock file is not committed to git, Steps 5 and 6 of the Lockdown Framework become entirely ineffective. Without a committed lock file, lockfile-lint has nothing to validate, and clean install commands (npm ci) cannot guarantee deterministic builds. Every developer and CI environment resolves dependencies independently, meaning different machines may install different versions. An attacker can exploit this inconsistency. Always ensure your lock file is tracked in version control and is NOT listed in .gitignore.

// Comparisons

How does the npm Supply Chain Lockdown Framework compare to using Snyk or Dependabot alone?

Snyk and Dependabot are reactive vulnerability scanners — they alert you after a known vulnerability is published in a database. The Lockdown Framework is proactive, blocking malicious packages before they execute on your machine. Snyk and Dependabot don't address install script execution, lock file tampering, exotic dependency attacks, or the dangerous window before a malicious package is flagged. The framework complements these tools: use Snyk/Dependabot for known vulnerability tracking and the Lockdown Framework for pre-installation defense against zero-day supply chain attacks.

Is pnpm more secure than npm for supply chain protection?

Yes, pnpm has significantly stronger built-in defaults. It blocks install scripts by default, its lock file format is not vulnerable to URL-swapping attacks (making lockfile-lint unnecessary), it supports trust policies (`no-downgrade`) to catch compromised publisher accounts, and it offers `blockExoticSubdependencies` natively. npm requires manual configuration for each of these protections and depends on third-party tools like allow-scripts and lockfile-lint to achieve parity. If supply chain security is a priority, pnpm provides the strongest foundation.

How does Socket Firewall compare to npq for npm supply chain security?

Both are pre-installation auditing tools but differ in approach. npq checks Snyk's vulnerability database, flags packages under 22 days old, detects typosquatting, verifies registry signatures and provenance, and audits maintainer metadata. Socket Firewall blocks human-confirmed malicious packages immediately and warns on AI-detected unreviewed threats. Socket supports more ecosystems (pip, cargo) in addition to npm/pnpm/bun. npq is lighter-weight and fully open. Attackers have publicly confirmed Socket detects malware before installation. Choose based on your ecosystem breadth and preference for AI-assisted detection.

// Advanced

Can AI coding assistants introduce supply chain vulnerabilities?

Yes. LLM-generated install commands may silently add flags that bypass your age gating settings, installing the latest version of a package even when your config specifies an age window. AI assistants may also suggest unnecessary dependencies when a native API or small utility function would suffice, increasing your attack surface. Always review AI-suggested install commands for flags that override your security config, and ask the AI to write utility code instead of importing a package whenever possible.

How do I handle emergency security patches that are blocked by release age gating?

If a legitimate security patch is published and you need it before the age window expires, bypass the age gating explicitly from the CLI by specifying the exact version. Do not modify your .npmrc or config file to lower the threshold permanently. Do not accept an LLM-suggested command without verifying it doesn't disable your other protections. After installing the patch, verify its provenance and check it with your firewall tool. Document the bypass in your commit message so the team knows it was a deliberate decision.

Does the npm Supply Chain Lockdown Framework work in monorepos?

Yes. For pnpm monorepos, set `minPackageAge`, `blockExoticSubdependencies`, and `trustPolicy` in pnpm-workspace.yaml so they apply workspace-wide. The `approve-builds` workflow and lock file are shared across the monorepo. For npm workspaces, .npmrc settings apply to the root and all workspaces. Lockfile-lint should be configured at the root level. Clean install commands (npm ci) work with the monorepo's single lock file. Firewall tool aliases apply to any install run from any workspace directory.

What is the trust policy no-downgrade setting in pnpm?

The `trustPolicy=no-downgrade` setting is a pnpm-specific config that causes installation to fail if a package's trust level has decreased compared to its previous release. For example, if a previously trusted package suddenly ships without provenance attestation or changes its publisher, pnpm flags this as a potential compromise. This catches attacks where a maintainer account is hijacked. There is no equivalent setting in npm or bun yet, making this a unique security advantage of pnpm.

What are exotic dependencies and why are they dangerous?

Exotic dependencies are packages declared as Git URLs or direct tarball URLs rather than npm registry package names. They are dangerous because they bypass the registry entirely, can ship their own .npmrc config overrides, and can re-enable install scripts even if you've blocked them in your config. An attacker who compromises a Git repository referenced as a dependency can inject code that won't be caught by registry-based scanners. Block them with `allow-git=none` in npm or `blockExoticSubdependencies=true` in pnpm.