Start with the cheapest move that actually removes the vulnerable version. Bump if a fix exists in range, override if a parent blocks it, replace or fork if the library is abandoned, and remove if nothing needs it. Pinning alone holds a version steady but does not fix anything.
The six moves, defined
- Bump: raise the version of a package you declare, or of the parent that brings it in, to a release that contains the fix.
- Pin: fix a package at an exact version so it cannot drift. A pin can lock in a fixed version or, by mistake, freeze a vulnerable one.
- Override: tell your package manager to use a specific version of a package wherever it appears in the tree, regardless of what parents request. The npm documentation describes overrides as a way to replace a version with a known security issue, or replace a dependency with a fork.
- Replace: swap the library for a different one, usually with a code change.
- Fork: take a copy of the source, fix it yourself, and depend on your copy.
- Remove: delete the dependency and the code that used it.
Decision table
| Situation | First move | Why |
|---|---|---|
| Fixed release exists and your range allows it | Bump | Cheapest, reviewed by upstream |
| Fixed release exists but a parent caps the range | Bump the parent, else override | Keeps the tree consistent |
| Fixed release is a new major version | Bump with a migration plan | Needs code changes and tests |
| No fix, change is small | Patch file, then pursue upstream | Short term stopgap |
| Project is abandoned, API is simple | Replace | Stops carrying unpatched code |
| Project is abandoned, you need it exactly | Fork | You own the maintenance |
| Nothing in your code uses it | Remove | Smallest attack surface |
| Fixed version is known good and you want stability | Pin the fixed version | Prevents drift after the fix |
Cost and risk, in short
| Move | Effort | Ongoing duty | Main risk |
|---|---|---|---|
| Bump | Low to medium | None | Breaking change |
| Pin | Low | Revisit later | Freezing a vulnerable version |
| Override | Low | Remove when parents catch up | Untested combination |
| Replace | Medium to high | None once done | Behavior differences |
| Fork | High | You patch it forever | Falling behind upstream |
| Remove | Low if unused | None | Hidden usage |
Pinning is the one people confuse with fixing. A lock file pins everything already. What changes the outcome is which version the pin points at.
A sequence that works
- Confirm the finding is real for your build: is the package in the shipped artifact, and is the vulnerable code reachable.
- Check whether anything uses the dependency at all. If not, remove it.
- Look for a fixed version your ranges allow. If yes, bump.
- If a parent blocks it, upgrade the parent. If the parent has no newer release, use an override, and write down why and when to remove it.
- If no fix exists anywhere, decide between a patch, a replacement and a fork, and note the choice in the exception register with a review date.
- After the change, test (see the guide on what counts as a breaking change in a fix PR), rescan, and record the result.
Each ecosystem names these moves differently. The guides on overrides, constraints, patch sections and exclusions linked from this blog cover the syntax. This post is the decision layer above them.
Try it yourself
Click through it at your own pace, or open it full screen. Pick a finding and decide which of the six moves applies before you read the suggested action.
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
Is pinning a fix?
Only if the pin points at a fixed version. A pin on a vulnerable version just keeps it.
When is a fork better than a replacement?
When you need the library's exact behavior and its API is too large to migrate, and you accept maintaining it.
Which move is cheapest when the library is unused?
Removing it. It also shrinks the attack surface without any compatibility risk.
Sources
Last reviewed: 19 October 2026.