Safeguard
Developer Tools•

Manifest range or lockfile: which version did the scanner judge?

A finding that vanishes after a lockfile commit may come from a version range. How to tell which version a scanner judged and fix the mismatch.

Safeguard Security Team
3 min read

A scanner can judge the version range in your manifest or the exact version pinned in your lockfile. If it reads only the manifest, a range like a caret can look vulnerable even when the lockfile installs a patched release. Check which file the scanner used before you call a finding a false positive.

Two files, two answers

A manifest, such as package.json, states what you accept: a range. A lockfile states what you got: an exact version. The npm documentation says the lockfile exists so that later installs produce identical trees regardless of intermediate dependency updates. That makes it the best record of what actually ships.

If a scanner reads only the manifest, it has to guess. Some pick the lowest version in the range, which can be old and vulnerable. Some pick the highest. Neither is what you deployed.

How the mismatch shows up

  • A finding names version 1.2.0, but your lockfile says 1.4.3.
  • A finding disappears after you commit the lockfile.
  • Two scanners disagree and one of them did not find a lockfile.
  • A monorepo package has a manifest but its lockfile lives at the repository root.

A five step check

  1. Read the finding. Note the package and the version it reports.
  2. Find the resolved version. In your lockfile, search for the package name. In a project with several lockfiles, check each one.
  3. Compare. If they match, the finding stands. If not, the scanner used the wrong source.
  4. Look at the scanner setup: does it point at the lockfile, the manifest, or an installed tree? Fix the configuration rather than suppressing.
  5. Rescan. The finding should now match reality.
Scanner inputWhat it can tell youWeak point
Manifest onlyDirect dependencies and rangesCannot know the resolved version
LockfileExact versions, including transitiveStale if not committed after changes
Installed tree or built artifactWhat is truly presentNeeds a build step

Why not just suppress it

A suppression hides the symptom. If the scanner keeps reading the manifest, every new advisory will produce the same noise, and a real vulnerable version could hide among it. Fixing the input is a one time job.

The reverse is also true: a clean scan on the manifest alone can miss a vulnerable transitive version pinned in the lockfile. Our post on lockfiles for apps and libraries explains when to commit each.

Libraries are different

A published library ships a range, because its consumers resolve their own tree. For a library, what the consumer resolves matters more than your own lockfile. Scan both: your lockfile for your tests and build, and a fresh install for what a new consumer would get.

Try it yourself

Click through it at your own pace, or open it full screen. Look at the resolved versions in the inventory and compare them with what a range alone would suggest.

Quick check

Should I commit the lockfile so scans are accurate?

For applications, yes. It gives scanners exact versions. For libraries, scan a fresh install as well.

Why do two scanners report different versions?

One may read the manifest and the other the lockfile or installed tree. Compare their inputs first.

Sources

Last reviewed: 19 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.