Fail the build on a narrow, agreed set of findings, such as the highest severities with a fix available, and warn on everything else. A scan that never fails is a report nobody must act on. A scan that fails on everything gets disabled. The skill is choosing the middle.
What the tools themselves say
npm's audit command exits with a non-zero code by default if any vulnerability is found, and its documentation points out that in CI you may want the audit level option to set the minimum severity that causes a failure. The same page notes that the option does not filter the report, only the failure threshold. That split is a good design principle: report broadly, block narrowly.
GitHub's dependency review action behaves similarly. By default its check fails if it finds vulnerable packages, and a failed check blocks merging when the check is required.
Decision table
| Finding type | Suggested action | Why |
|---|---|---|
| Critical or high severity, fix available, in a reachable path | Fail | Clear, fixable, relevant |
| Critical or high, no fix available | Warn and track with an owner | Blocking creates a stalemate nobody can resolve |
| Medium and below | Warn | Fix in normal maintenance |
| Known malicious package | Fail, always | No tuning needed |
| Licence outside policy | Fail or warn per your policy | Decide with legal input |
| Vulnerability in a dev only dependency | Warn | Lower exposure, but review |
Reachability changes this table. If analysis shows the vulnerable code is not called, the finding can drop from fail to warn with a recorded reason.
How to avoid the two failure modes
Failure mode one: the gate that nobody can pass. This happens when a gate is switched on against a large existing backlog. Scope blocking to what the change introduces, and handle the backlog through scheduled work.
Failure mode two: the gate that never fires. This happens when every finding is a warning. Teams stop reading warnings quickly.
A rollout that works
- Run in warn mode for one to two weeks and look at what would have failed.
- Set the fail rule to the narrow set from the table.
- Add an exception process: named approver, reason, and expiry date.
- Review exceptions on a schedule so they do not become permanent.
- Tighten the rule gradually, one severity level or category at a time, and tell developers before you do.
Make failures actionable
A failure message should say which package, which version, what the issue is, and what to do about it, ideally the first version that fixes it. A failure without a next step produces bypass requests, not fixes.
Where Safeguard fits
Safeguard lets you set policies and gates, and reachability analysis helps separate findings that matter from those that do not. Autonomous remediation with fix pull requests is available too, off by default, with every category set to Manual. Run a free scan at gold.safeguard.sh/scan to see what your own repository would trigger.
Quick check
Is warn only ever the right setting?
During a short baseline period, yes. After that, keep it only for categories you have decided are not worth blocking on.
What should we do when no fix exists?
Warn, assign an owner, record a mitigation or compensating control, and set a date to re-check. Blocking on it just freezes delivery.
Sources
- npm Docs, npm audit
- GitHub Docs, About dependency review
Last reviewed: 19 October 2026.