A scanner can tell you that a repository contains 47 known vulnerabilities. It cannot decide which engineer should stop what they are doing, which dependency should move first, or whether a finding is reachable in the deployed application.
That gap is where security programs become noisy. A flat list of CVEs looks objective, but it quietly treats every vulnerable package as equally urgent. Teams either interrupt too much work or, more commonly, learn to ignore the list.
A useful triage process produces a queue, not an inbox.
Start With Exposure, Not the Score
CVSS is valuable, but it describes the general technical severity of a vulnerability. It does not describe the specific risk to your application.
Before assigning priority, ask four questions:
- Is the affected package present in a deployed artifact? Test-only tools and abandoned sample projects should not compete with production services.
- Is the vulnerable behavior reachable? A flaw in an image parser matters differently when your application never processes untrusted images.
- Is exploitation plausible now? Public exploit activity and EPSS can distinguish a theoretical issue from one attackers are likely to use.
- What is exposed if exploitation succeeds? Internet-facing identity services deserve a different response than isolated internal utilities.
The answers do not erase severity. They add the application context that severity scores cannot contain.
Rank Findings With a Small Decision Model
Complex scoring formulas tend to create false precision. A small set of priority bands is easier to explain and operate:
| Priority | Typical evidence | Expected response | | --- | --- | --- | | P0 | Exploitable, exposed, and high-impact | Interrupt normal work and remediate now | | P1 | Reachable production path with credible exploitation | Assign an owner in the current sprint | | P2 | Present in production but exposure is limited or uncertain | Investigate and schedule | | P3 | Development-only, unreachable, or strongly mitigated | Document and monitor |
Use the highest band only when the evidence supports it. If every critical CVE becomes a P0, the label stops communicating anything.
Uncertainty should be visible too. “Reachability unknown” is a reason to investigate, not a reason to silently place a finding at the bottom of the queue.
Follow the Dependency Path
In .NET, the vulnerable package in a report is often not the package declared in the project file. It may have arrived through several transitive relationships:
Checkout.Api
└── Contoso.Payments
└── Contoso.Transport
└── Vulnerable.PackageThat path changes the remediation choice. The cleanest fix may be to upgrade Contoso.Payments, replace it, or ask its maintainer to release a version with a corrected dependency. Adding a direct reference to force a transitive version can be a useful short-term measure, but it also creates an override the team must remember to remove.
Record the introducing dependency with the finding. “Upgrade Vulnerable.Package” is not an actionable ticket when the application does not own that reference.
Make Every Accepted Risk Expire
Sometimes the correct decision is not to patch immediately. A vendor may not have released a fix, the affected code path may be disabled, or the upgrade may require a larger migration.
An exception should capture:
- the reason the risk is acceptable;
- the evidence behind that conclusion;
- the compensating control, if any;
- the owner;
- an expiration date or review trigger.
Permanent suppressions turn yesterday's context into tomorrow's blind spot. Time-bound exceptions force the decision to be revisited when the application, dependency graph, or threat changes.
Separate Discovery From Enforcement
Do not make a new scanner block every existing finding on day one. First establish the baseline, remove obvious false positives, and assign the serious work. Then enforce a policy on new or regressed risk.
A sensible first gate might block critical findings and suspected typosquats:
version: 1
policies:
max-severity: critical
fail-on-typosquat: trueTighten the policy as the backlog becomes manageable. This makes the build signal credible: a failed check means the pull request introduced something the team has explicitly agreed not to accept.
See the policy reference for the controls available in .rorix.yml.
The Deliverable Is a Decision
For each finding, a developer should be able to see the affected application, the dependency path, the relevant exposure, the proposed fix, and the deadline. If the output still requires an engineer to reconstruct all of that from a CVE identifier, triage has not happened yet.
Better vulnerability management is not a larger alert feed. It is a shorter distance between evidence and an owned decision.
