What Happened
Your .NET development team might spend weeks triaging vulnerability alerts from your software composition analysis (SCA) tool. Imagine your application pulls in 4,200 NuGet packages across microservices, and the SCA scanner flags 847 CVEs in your dependency tree. Security blocks production releases while developers investigate high-severity findings.
After implementing reachability analysis, you might find that only 12 of those 847 vulnerabilities exist in code paths your application actually executes. The other 835 alerts point to vulnerable methods in dependencies that your codebase never calls. Weeks of engineering time could be wasted chasing ghosts.
This isn't a failure of your SCA tool. It's a failure of your vulnerability management process to answer the most basic question: "Can an attacker reach this code from our application?"
Timeline
Week 1: SCA scan returns 847 vulnerabilities. Security creates tickets for all CVSS 7.0+ findings (412 issues). Development grinds to a halt.
Week 2-3: Developers manually trace code paths for critical findings. Most can't definitively prove whether vulnerable methods are reachable. Security maintains deployment freeze.
Week 4: Team escalates to CISO. External consultant recommends reachability analysis tooling.
Week 5: Deploy reachability analysis integration. Initial scan completes in 4 hours.
Week 6: Results show 12 exploitable vulnerabilities out of 847 total findings. Team remediates actual risks in 3 days. Deployment freeze lifts.
Which Controls Failed or Were Missing
The breakdown wasn't technical—it was procedural. Your team might face similar control failures:
Missing context in vulnerability assessment: Your SCA tool inventories every CVE in every dependency but provides no analysis of whether vulnerable code is reachable from your application's execution paths. Treating all findings as equally urgent based solely on CVSS scores is ineffective.
No risk-based prioritization framework: CVSS severity becomes the de facto priority queue. A CVSS 9.8 vulnerability in a logging library's XML parser means nothing if your application only uses that library's JSON methods—but you need a mechanism to make that distinction.
Inadequate verification procedures: Developers spend hours manually tracing call graphs through dependency chains, often without definitive answers. They can't prove a negative (that code isn't reachable), so they assume every finding is exploitable.
Broken feedback loop between security and development: Security flags everything. Development pushes back on false positives. Neither side has data to resolve disputes. Trust erodes with each blocked deployment.
What the Standards Require
OWASP ASVS v4.0.3 Requirement 14.2.1 states: "All components should be up to date with proper security configuration(s) and version(s)." But "up to date" doesn't mean "patch every CVE regardless of exploitability." The standard expects risk-based decisions.
PCI DSS v4.0.1 Requirement 6.3.2 requires organizations to "manage all vulnerabilities by using a formal risk assessment process." The key phrase is "risk assessment process"—not "severity score automation." You must evaluate whether a vulnerability represents actual risk in your environment.
NIST 800-53 Rev 5 Control RA-5 mandates vulnerability scanning and remediation but explicitly allows for risk-based prioritization: "Organizations determine the required vulnerability remediation actions...based on risk assessments." Scanning everything and fixing nothing isn't compliance.
ISO/IEC 27001:2022 Control 8.8 (Management of technical vulnerabilities) requires that "information about technical vulnerabilities of information systems in use shall be obtained, the organization's exposure to such vulnerabilities shall be evaluated and appropriate measures shall be taken." The critical word is "exposure"—which means understanding whether your application actually exposes the vulnerable code path.
None of these standards require you to remediate every CVE in every dependency. They require you to understand your actual risk exposure and act accordingly.
Lessons and Action Items for Your Team
1. Implement reachability analysis in your SCA workflow
Reachability analysis determines whether vulnerable code in a dependency is actually called from your application's code. For .NET teams using NuGet packages, this means analyzing your call graph to see if execution paths exist from your code to vulnerable methods.
Action: If you're using Sonatype Lifecycle or similar tooling, enable reachability analysis for your .NET repositories. If your current SCA tool doesn't support it, evaluate tools that do. The ROI is immediate—you'll cut alert volume by 70-90% in most codebases.
2. Rebuild your vulnerability triage process around exploitability
Stop using CVSS scores as your primary sort key. Your queue should prioritize:
- Reachable vulnerabilities with known exploits
- Reachable vulnerabilities in internet-facing code paths
- Reachable vulnerabilities with high CVSS scores
- Unreachable vulnerabilities (deprioritized, but tracked)
Action: Document your new triage criteria. Train your security and development teams on the difference between "vulnerable dependency present" and "vulnerable code path exposed."
3. Use reachability data to rebuild trust with development
Developers ignore security alerts when they're overwhelmed with false positives. Reachability analysis gives you credibility—you're bringing them 12 real problems instead of 847 maybes.
Action: In your next sprint planning, show the before/after on vulnerability counts. Demonstrate that you're filtering noise, not just generating tickets. Make it clear that remaining alerts represent actual exploitable paths.
4. Document your risk acceptance for unreachable vulnerabilities
You'll still have hundreds of CVEs in your dependency tree that aren't reachable. That's fine—but document why you're not remediating them.
Action: Create a "risk accepted - unreachable" category in your vulnerability tracking system. Include the reachability analysis output. When auditors ask about unpatched CVEs, you have evidence that they don't represent actual risk in your environment.
5. Automate reachability checks in CI/CD
Manual analysis doesn't scale. Build reachability analysis into your pipeline so every pull request includes exploitability context.
Action: Add reachability scanning to your CI/CD pipeline. Configure it to block merges only when reachable vulnerabilities are introduced—not when someone updates a dependency that happens to contain unreachable vulnerable code.
Your dependency tree will always contain vulnerabilities. The question is whether attackers can reach them from your code. Answer that question first, then start patching.



