Safeguard
Developer Tools•

Why did npm update not fix my vulnerable dependency?

npm update respects the semver ranges in package.json and does not edit them by default. Why a vulnerable version stays put, and the steps that move it.

Safeguard Security Team
4 min read

npm update only moves a package to the newest version that your declared range allows. If the fixed release sits outside that range, nothing changes. By default it also leaves the range in package.json untouched. To reach the fix, change the range, use the save option, or install the fixed version by name.

What npm update promises

The npm documentation says the command updates the listed packages to the latest version, respecting the semver constraints of both your package and its dependencies when they also require the same package. If you do not name a package, everything in the location is updated.

Two details explain most surprises. First, by default npm update does not update the semver values of direct dependencies in package.json. The docs say you can add the save option if you also want those values updated. Second, the range type changes how far it can go.

Why a range blocks the fix

The docs walk through examples. A caret range on a 1.x package allows newer minor and patch versions of that major series, and a tilde range allows only patch changes. Caret ranges below 1.0.0 are tighter: a caret on 0.2.0 stays within the 0.2 series, and a caret on 0.4.0 moves only within the 0.4 series, so a 0.3 release is out of reach.

Declared rangeFixed releaseDoes npm update reach it?
Caret 1.1.01.1.5Yes
Tilde 1.1.01.2.0No, minor change
Caret 1.1.02.0.0No, new major
Caret 0.2.00.3.0No, 0.x is tighter

The lock file also matters. If the fixed version satisfies the range but your lock file records an older version, the update command is what refreshes it, and a plain install keeps the locked version.

Steps to move it

  1. Check the advisory for the first fixed version.
  2. Compare it to your declared range for the package.
  3. If it fits, run the update for that package only, then review the lock file diff.
  4. If it does not fit, install the fixed version by name so the manifest range changes with it.
  5. If the package is transitive, find the parent that sets its range. Updating the parent may be enough, otherwise an override applies (see npm overrides).
  6. Run your tests and rescan.
npm update somepackage
npm install somepackage@2.0.1

A note on majors

Moving to a new major version is not an update, it is an upgrade with a migration cost. Read the changelog first, and see the guide on whether to upgrade a major version dependency.

Verify

After the command, list the package and confirm the version at every path. A fix that applied to one path and not another is common when two parents require different ranges. The lock file diff is the record of what actually changed, so read it.

Try it yourself

Click through it at your own pace, or open it full screen. Compare a fixed version with the range you have today.

Where Safeguard fits

Safeguard scans dependencies, runs reachability analysis to show which findings your code can actually reach, and can open fix pull requests through autonomous remediation. That last feature is off by default and every category starts on Manual, so a person approves each change. You can try a free scan on a repository first.

Quick check

Does npm update edit package.json?

Not by default. The docs say you need the save option to update the declared ranges.

Why does a caret range on 0.x move so little?

For versions below 1.0.0, the caret allows only changes within the same minor series, so it is tighter than on 1.x and above.

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.