Safeguard
Software Supply Chain•

How do you manage JavaScript dependencies securely with npm?

A practical npm workflow: commit the lockfile, install with npm ci, audit with a failure threshold, verify signatures, and control install scripts in CI.

Safeguard Security Team
4 min read

Manage JavaScript dependencies securely by committing your lockfile, installing from it with npm ci, running npm audit with a failure threshold in CI, verifying registry signatures, and deciding deliberately whether install scripts may run. Each step is documented in npm's own manuals.

Why does the lockfile come first?

package.json states ranges. The lockfile states what was actually resolved. The npm documentation for package-lock.json says each entry records where the artifact came from and an integrity field holding a standard Subresource Integrity string, a sha512 or sha1, for the artifact that was unpacked. For git dependencies the resolved field holds the full git URL with commit sha.

So the lockfile is both a version pin and a tamper check. If a tarball changes under the same version number, the integrity string no longer matches and installation fails.

What does npm ci add?

The npm docs say npm ci suits automated environments such as test platforms, continuous integration and deployment, and any case where you want a clean install. Three differences from npm install: the project must already have a lockfile, npm ci exits with an error if the lockfile does not match package.json instead of updating it, and it installs the whole project, never single packages.

The second difference is the security feature. A pull request that changes package.json without the lockfile cannot slip through CI.

How do you use npm audit in CI?

The audit command submits a description of your dependencies to your registry and asks for a report of known vulnerabilities. By default it exits with a non zero code if any are found. The documentation suggests the --audit-level option in CI, which sets the minimum level that fails the build, and notes that it changes only the failure threshold, not the report. It also warns that bypassing the lockfile with --no-package-lock can give different results every run, since npm rebuilds the tree.

An audit tells you a version is known to be vulnerable. It does not tell you whether your code reaches the vulnerable function, so triage the results before you decide what blocks.

Can you verify what you downloaded?

Yes, in two ways the npm docs describe.

  • Audit signatures: npm audit signatures verifies registry signatures of downloaded packages, for the public registry or any registry that supports signatures.
  • Provenance: publishers can generate provenance statements that publicly establish where a package was built and who published it. Check them when a package you depend on offers them.

What about install scripts?

The ignore-scripts config, false by default, stops npm from running scripts listed in package.json. Commands you invoke explicitly, like npm test, still run their intended script. Scripts are a real route for malicious code, since they run at install time on developer laptops and build servers. Turning them off in CI is a common choice. Some packages need a build step at install, so keep an allow list and review it.

Can you delay new releases?

The before option tells npm install to rebuild the tree using only versions available on or before a given date. Used carefully, a date a few days old gives the community time to notice a malicious release, at the cost of delayed fixes. Use it as a deliberate policy, with an exception path for urgent security updates.

How to check or apply this

  1. Commit package-lock.json and require lockfile changes in the same pull request as package.json changes.
  2. Use npm ci in every pipeline.
  3. Add npm audit --audit-level=high as a CI step and agree who triages failures.
  4. Run npm audit signatures in CI.
  5. Set ignore-scripts for CI installs and maintain a reviewed exception list.
  6. Pin direct dependencies exactly where stability matters, and review lockfile diffs like code.
  7. Keep an inventory of the full dependency tree for each release. Safeguard's free scan at gold.safeguard.sh/scan reads up to 100 dependencies in the browser if you want a quick look.

Try it yourself

Open the full demo.

Quick check

What is the difference between npm install and npm ci?

npm ci requires a lockfile, fails if it does not match package.json, and never rewrites it. npm install can change the lockfile.

Does a clean npm audit mean the project is safe?

No. It only reports vulnerabilities already known to the registry's advisory data for the versions you resolved.

Sources

Last reviewed: 18 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.