Yes, a lockfile can carry a bad entry, mostly because people approve lockfile changes without reading them. The file decides what gets installed, so a changed source URL or a swapped package is a code change in disguise. Review lockfile diffs, and install from the lockfile only.
What does a lockfile control?
The npm documentation says package-lock.json is generated whenever npm changes the node_modules tree or package.json. It records the exact tree, so teammates, deployments and CI install the same dependencies. Each entry carries fields such as the version, the place the package was resolved from, and an integrity value, a Subresource Integrity string for the artifact.
That is the strength and the weakness. The lockfile is the real list of what runs in your build. Yet it is long, machine written, and usually collapsed in code review.
Where is the blind spot?
Reviewers read package.json because it is short. A pull request that adds one line there may add dozens of lines to the lockfile, and the lockfile is where a change in origin would appear. The risk is not that the file format is broken. The risk is that a human is asked to trust a diff nobody reads.
Think about what a reviewer would need to notice. A resolved address that points somewhere other than the registry you expect. A package that appears in the lock but not in any dependency path you recognize. An integrity value that changes for a version number that did not change. Each is visible in a diff, and each is easy to scroll past.
The OWASP Top 10 CI/CD Security Risks covers the wider pattern under dependency chain abuse and improper artifact integrity validation. The lockfile is the place where your own pipeline records what it trusted.
Does npm ci help?
Yes, for repeatability. The docs describe npm ci as the command for automated environments. It requires an existing lockfile, errors out if the lockfile and package.json disagree instead of rewriting the lock, and never writes to package.json or the lock. A plain install in CI can quietly update the lock, which hides drift.
It does not decide whether an entry was trustworthy to begin with. It faithfully installs whatever the lockfile says.
A constructed example
A contributor opens a pull request titled fix typo in docs. It also touches package-lock.json, and one entry for a small utility package now has a resolved address on a host that is not your registry. The change is two lines inside a 3,000 line diff. A reviewer who collapses the file approves. A team with a simple check that lists every resolved host in the diff would have flagged it in seconds.
How to check or apply this
- Make lockfile changes visible in review. Do not hide the file by default.
- Add a CI step that lists every resolved host in the lockfile and fails on any host outside your allowed registry.
- Fail a pull request that changes the lockfile without a matching package.json change, unless it is labeled as a lockfile refresh.
- Install with npm ci in all automated builds.
- Require a reviewer who is not the author for dependency changes.
- Scan the resolved tree for known vulnerabilities and review new additions by name.
- Keep the lockfile format current by using a supported npm version, since the format has changed over time.
Safeguard scans the tree that your lockfile describes and can gate a pull request on policy, so dependency changes are checked as well as read. The free scan at gold.safeguard.sh/scan covers up to 100 dependencies.
Quick check
Should I commit package-lock.json?
For applications, yes. The npm docs say it is meant to be committed so that every environment installs the same tree.
Does an integrity value prove a package is safe?
No. It proves the downloaded file matches what was recorded. If the recorded entry was bad, it matches the bad file.
Sources
Last reviewed: 18 October 2026.