Triage the first scan in four passes: group findings by package, move anything on CISA's exploited list to the top, check whether your code reaches the vulnerable function, then assign fix, defer or dismiss to each group. Aim to decide, not to fix, in the first afternoon.
Expect a big number
A first scan on an older project often returns hundreds of findings. That is normal, because indirect dependencies and old lockfiles carry history. The number tells you little. The order you work in tells you a lot.
Pass one: group by package
Many findings share one package or one fix. Group them so one upgrade closes several. A list of 200 findings may become 30 packages. Do this first because it is mechanical and shrinks the problem.
Pass two: exploited first
CISA's exploited catalog lists vulnerabilities with evidence of exploitation in the wild, and CISA strongly recommends that organizations monitor it and prioritize those. Check each package's findings against it. Anything that matches goes to the top, whatever its severity score.
EPSS adds a second signal. FIRST describes it as an estimated probability of exploitation in the next 30 days. Use it to order the rest, not to dismiss anything. For a comparison of the signals, see CVSS versus EPSS versus KEV.
Pass three: reachability
For each remaining finding ask three questions.
- Is the package in code that ships, or only in tests and tooling?
- Does your code, directly or through another package, call the vulnerable function?
- Is the vulnerable condition possible in your setup?
Reachability analysis answers the second question by reading the call graph. Without it, search for the vulnerable function name in your code and in the advisory text. If you cannot decide, treat it as reachable.
Pass four: decide
Give every group exactly one decision.
| Decision | When | Record |
|---|---|---|
| Fix now | Exploited, or reachable with a simple upgrade | Owner and ticket |
| Fix this month | Reachable, upgrade needs testing | Owner and date |
| Defer | Not reachable, no fix, low risk | Reason and review date |
| Dismiss | Not in shipped code or not affected | Reason |
Timebox it
Give yourself four hours. If a decision takes more than ten minutes, mark it fix this month and move on. Triage gets worse when you try to understand every advisory.
Keep the record
Write each decision down. A table with package, decision, reason and date is enough. That record is what you show a customer, and it is what lets next month's scan start from a known baseline instead of zero. Dismissals especially need a reason, because someone will ask later.
Afterwards
Fix the exploited items first, wire the scan into pull requests so you stop adding to the pile, and repeat the triage monthly. For the surrounding setup see the first week plan.
Safeguard reachability analysis does the call graph step for you, and the free scan at https://gold.safeguard.sh/scan produces a first list to triage.
Try it yourself
Click through it at your own pace, or open it full screen.
Quick check
What if a finding has no fix available?
Check whether the vulnerable code is reachable. If it is, look for a mitigation or an alternative package, and record a review date.
Can we dismiss low severity findings in bulk?
Only with a recorded reason, such as not in shipped code. Severity alone is a weak reason, since low scores can still be exploited and high ones can be unreachable.
Sources
Last reviewed: 19 October 2026.