How to Prioritise Snyk Alerts When Everything Is Critical
The first Snyk scan on a repo that has been shipping for three years typically returns 200 to 600 vulnerabilities. Half of them are in dev dependencies nobody ships. A quarter have no fix. Sorting that pile is the real work; the scan itself is trivial.
Direct answer: prioritise Snyk alerts by running snyk test --reachability to drop vulnerabilities in code you never call, then fix in this order: runtime dependencies with an available upgrade, then high-severity transitive issues with an override, then everything else on a quarterly cadence. Ignore the rest with a documented expiry date.
Why is severity alone a bad sort order?
Because CVSS scores model a generic deployment. A path-traversal bug in a static site generator scores 9.8 and cannot be exploited on your server, which never runs the generator in production.
Snyk’s reachability analysis (available on the Team plan and above) walks your call graph and tells you whether the vulnerable function is actually invoked. In one Node service, enabling it cut a 340-item backlog to 41 that mattered.
Without reachability, approximate it yourself: anything in dependencies beats anything in devDependencies. That single filter usually removes 40% of a backlog.
What is a workable triage order?
The order matters more than the tooling:
- Critical + runtime + fix available. Fix today. There are usually fewer than five of these.
- High + runtime + fix available. Batch into the next release, same week.
- Any severity + fixed version exists but is a major bump. Schedule it; read the changelog first.
- No fix available + runtime. Check for mitigation. Often the answer is a WAF rule or disabling a feature flag.
- Dev-only or unreachable. Ignore with an expiry.
Steps 1 and 2 are usually 10-15% of the total and represent nearly all the real risk. Working the list top-down without this grouping means spending a day on a dev-dependency mock library.
How do you ignore something without losing track?
Snyk stores ignores as policy, and every ignore supports an expiry. Use them.
snyk ignore --id=SNYK-JS-MINIMIST-559764 --expiry=2027-01-31 --reason="not reachable from server entrypoint"
The .snyk policy file gets committed, so the reason travels with the repo and survives staff turnover. An ignore without an expiry is a bug you will find again in eighteen months with no memory of why it exists.
For dev dependencies, set the policy at the organisation level rather than per-issue. Hundreds of individual ignores is how the file becomes unreviewable.
Which metrics are worth tracking?
Not the total count. That number goes up when you add a dependency and down when you refactor, and it tells you nothing.
Track these four instead:
| Metric | Target | Why |
|---|---|---|
| Median days to fix critical | under 7 | the only number executives care about |
| % of runtime deps on latest minor | above 70% | predicts future backlog |
| Open ignores past expiry | 0 | drift you can measure |
| PRs blocked by Snyk | under 10% | above that, the team disables it |
That last one is the leading indicator. A check that blocks a quarter of PRs gets disabled within a month, and then you have zero coverage instead of partial coverage.
How do you keep the backlog from regrowing?
Renovate or Dependabot, configured to open PRs for patch bumps weekly. Most CVEs are fixed by a patch release you did not apply, and automated patch PRs with a green CI run merge without anyone thinking about them.
{"extends": ["config:recommended"], "packageRules": [{"matchUpdateTypes": ["patch", "pin"], "automerge": true}]}
Automerge patches only. Minor and major updates need a human, because the failure mode of an automerge on a major bump is a production incident at 3 AM.
Where the process breaks
Reachability analysis fails on dynamic imports and reflection. If your framework resolves modules at runtime, Snyk cannot see the call path and reports “not reachable” for code that absolutely runs. Treat not-reachable as a strong hint, not proof.
Monorepos complicate things further. Scanning the workspace root gives one giant report with no ownership. Run Snyk per package with separate projects so each team sees its own issues.
And ignore the temptation to fix everything before the next release. A security backlog is permanently open; the goal is a stable rate of closure, not zero.
Key Takeaways
- Severity alone misranks: a 9.8 in a dev dependency can be safely ignored, a 6.5 in a request handler cannot.
- Reachability analysis cut one real backlog from 340 issues to 41 worth fixing.
- Filter dev dependencies first — usually 40% of the list, near-zero real risk if nothing ships them.
- Every ignore needs an expiry and a written reason; Snyk stores them in a committed
.snykfile. - Automate patch updates with Renovate; keep minors and majors manual.
