Check that each package.json has a matching lockfile, that only one package manager owns each directory, and that the lockfile has been updated since the last dependency change. Old lockfiles are common in legacy monorepos, and a scanner will faithfully report whatever stale versions they hold.
What npm says about its lockfile
The npm documentation says package-lock.json is generated automatically for any operation where npm modifies the node_modules tree or package.json. It also says that when npm meets a lockfile from version 6 or earlier during an install, it updates the file to fetch missing information, from node_modules or from the registry.
Two lessons follow. A lockfile can change on its own during an install, so an old file in the repository may not match what developers actually run. And an old format is not unusual, so your scanner should handle it or tell you it cannot.
Four checks
- Pairing. List every package.json and check for a lockfile in the same directory, or in a workspace root that covers it. Mark pairs that are missing.
- One owner per directory. Look for more than one lockfile type in the same place, such as package-lock.json beside yarn.lock. Two lockfiles mean two possible truths.
- Freshness. Compare the last commit date of package.json with that of the lockfile. If package.json changed much later, the lockfile is likely out of date.
- Format. Open a few lockfiles and note the format version. Very old ones may lack fields a scanner relies on.
Reading the results
| Check result | What to do |
|---|---|
| No lockfile | Scan the manifest, mark as approximate, plan to add one |
| Two lockfile types | Ask the team which one CI uses; delete the other |
| Lockfile older than manifest | Regenerate in CI and review the diff |
| Very old format | Regenerate with a current npm in a clean environment |
Workspaces change the picture
In a monorepo that uses workspaces, one lockfile at the root can cover many packages. A scanner that only looks beside each package.json will think those packages have no lockfile. Find out whether your repository uses workspaces before you read the pairing results.
Regenerating safely
Regenerating an old lockfile can pull in newer versions of transitive packages. That is usually good, but it is a change. Do it in a branch, run the tests, and read the diff for major version jumps. Do not combine regeneration with feature work.
For services you will not rebuild, leave the lockfile alone and record the scan as based on the committed file. Changing lockfiles on code you cannot test creates risk without benefit.
Make it a standing check
Add a lightweight CI check that fails when package.json changes without a lockfile change in the same pull request. It prevents the problem from returning after you clean it up.
Where Safeguard fits
Safeguard's dependency scanning and SBOM generation work from lockfiles and manifests, and policies can gate pull requests on what a change introduces. The CLI 1.4.0 installs with curl or PowerShell, and a free scan is at https://gold.safeguard.sh/scan.
Quick check
Is a missing lockfile a vulnerability?
Not by itself. It means installs are not repeatable, so what you scan may not match what ships. That makes findings less reliable.
Can I just delete old lockfiles and regenerate?
You can, but review the resulting diff and run tests. Never do it on code that cannot be rebuilt and tested.
Sources
Last reviewed: 19 October 2026.