Dependency Vulnerability Triage Workflow
Triage scanner findings by exploitability in your context, not CVSS alone: check reachability, exposure, and compensating controls before scheduling fixes.
Objective
Route vulnerability fixes by actual risk in your system, clearing critical-and-reachable items fast while deprioritizing unreachable noise with documented rationale.
Environment
- SCA scanning integrated into CI and scheduled runs
- Access to call graphs or reachability analysis
- A remediation SLA policy per risk tier
Steps
1. Deduplicate and baseline
Collapse duplicate findings across scanners into one issue per (package, vulnerability), with your installed version and the fixed version attached.
Expected state: One canonical list exists, free of the same CVE reported four times.
2. Assess reachability
For each finding, determine whether your code actually calls the vulnerable path: static call graphs, runtime evidence, or the vulnerable feature being enabled.
Expected state: Each finding carries reachable, unreachable, or unknown, with the evidence noted.
3. Combine with exposure
Factor in where the package runs: internet-facing service, internal tool, or build-time-only dependency changes the effective severity.
Expected state: Effective severity reflects context, documented per finding.
4. Route by the combined tier
Critical-plus-reachable in internet-facing code gets an emergency patch window; unreachable items get scheduled upgrades with rationale recorded; unknowns get a reachability task before default scheduling.
Expected state: Every finding has a tier, an SLA, and an owner from the routing decision.
5. Close the loop with compensating controls
Where a fix cannot land in time, document the compensating control (WAF rule, feature flag off, egress block) attached to the finding until the upgrade ships.
Expected state: Overdue findings show either a shipped fix or an active compensating control.
Expected outcome
A vulnerability backlog ordered by real risk with reachability evidence, emergency effort spent on exploitable items, and every deferral carrying rationale or controls.
Verification
Emergency-patched items were all reachable and exposed; a sample of deprioritized findings shows reachability evidence; no overdue item lacks either a fix or a documented control.
CVSS tells you how sharp the knife is, not who holds it
A critical in a code path you never call behind an internal-only endpoint is noise; a medium in your public parser is the emergency. Triage that combines reachability and exposure spends the panic budget where attackers actually can go.
finding: CVE-2026-8841 (cvss 9.8) pkg: xmlparse 2.3.1
context assessment:
reachability: parser feature ENABLED, called in
/api/import (public) -> REACHABLE
exposure: internet-facing, no auth on import
effective tier: EMERGENCY (patch window: 48h)
finding: CVE-2026-7702 (cvss 8.1) pkg: devserver 4.x
reachability: dev-only, not in production build
exposure: build-time only
effective tier: SCHEDULED (next minor, rationale logged)
compensating control (until xmlparse 2.3.2 ships):
WAF rule: block XXE payloads on /api/import
Reachability converts panic into arithmetic
Most critical findings in a large dependency tree are unreachable: the vulnerable function exists but nothing calls it, or the dangerous feature is disabled. Establishing that with a call graph or runtime evidence turns a week of firefighting into a documented deferral.
Compensating controls are the honest bridge
When the fixed version breaks compatibility or lands next sprint, an unmitigated critical sits in production while everyone feels bad. A WAF rule, a disabled feature, or a blocked egress path attached to the finding is an honest, time-boxed bridge — and it shows up in the audit as control, not neglect.