Safeguard
Security Guides•

Why does my scanner still flag a package I already upgraded?

If a scan still flags a package you upgraded, a nested copy, a stale lockfile or an old build is usually the cause. Use npm ls and npm explain to find it.

Safeguard Security Team
4 min read

A scanner still flags an upgraded package when another copy of it is in the tree, the lockfile was not updated, or the scan ran against an old build. The fix is to find which copy is flagged and which parent pulls it in. In npm, npm ls and npm explain show both.

The usual suspects

CauseWhat you seeHow to confirm
Nested older copyTop level shows the new version, a deeper path shows the old oneList every path to the package
Lockfile not committedYour laptop is clean, CI is notCompare the lockfile in the scanned commit
Old artifact scannedSource is fixed, the image or bundle is notRebuild, then scan the new artifact
Different branch or projectFinding belongs to a service you did not touchCheck which project the finding names

Why a second copy can exist

npm's default install strategy is hoisted. The npm docs describe it this way: non-duplicated packages install at the top level, and duplicated ones are placed within the directory structure as necessary. So if one of your dependencies asks for an older range than the rest of the tree, npm can keep the old version nested under that parent while the top level holds the new one.

You upgraded the direct dependency, but the flagged copy belongs to someone else's range. That is why a quick look at the top of node_modules can mislead you.

Find the copy and its parent

Run these from the project root:

npm ls some-package --all
npm explain some-package

The npm ls docs say the tree it prints is the logical dependency tree, based on package dependencies, not the physical layout of node_modules, and that nested packages also show the paths to the package you name. The npm explain docs describe it as printing the chain of dependencies causing a given package to be installed. Together they tell you which parent holds the old version.

Then fix the right thing

  1. If a parent requests an old range, upgrade that parent first.
  2. If no parent update exists, check whether the ecosystem offers an override or resolution setting, and record why you used it.
  3. Regenerate the lockfile and commit it. The npm docs say the lockfile describes the exact tree that was generated, so later installs reproduce it.
  4. Rebuild the artifact, whether that is a bundle or an image, so the scan sees the new contents.
  5. Rescan the same project and compare the finding list.

Try it yourself

Click through it at your own pace, or open it full screen.

Look at how a fixed version is shown next to the finding, and think about which dependency path would still hold the old one.

Quick check

Is the scanner wrong if it flags the old nested copy?

Usually not. If that copy is in the tree and installed, it is a real component. Whether it is exploitable is a separate question.

Do I need to delete node_modules?

Not always, but a clean install from the committed lockfile removes doubt about leftover files.

Why is the finding gone on my laptop but present in CI?

The two probably resolve different trees. Check that the lockfile in the scanned commit matches the one you tested.

Safeguard offers dependency scanning with SBOM output and reachability analysis, and the free scan lets you try it on your own project.

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.