I'm the only security and platform person at a small fintech preparing for SOC 2. Patching vulnerabilities with available fixes is manageable, but scanners keep flagging issues where there is no patch, the upgrade would break required functionality, or the vulnerable code is not actually used in our environment. Examples include unused transitive dependencies, unreachable functions, and vulnerabilities that require network access we do not provide.
Our scanners and compliance dashboard keep these findings red, and it seems like every CVE needs a separate risk acceptance. Writing a detailed exception for each one is becoming a huge amount of work. For those who have dealt with audits, what evidence do you provide to show that a CVE is not exploitable in your environment? Is there a practical way to automate reachability analysis and evidence collection, or is this mostly manual documentation?
4 Answers
The auditor usually does not need the CVE to disappear; they need a defensible explanation of why it does or does not apply to your environment. Record whether the vulnerable package is present in production, whether the vulnerable function is reachable, what conditions exploitation requires, and which compensating controls exist. Include the assessor, date, risk owner, and a review or expiration date. A short, repeatable assessment is much better than a permanent exception with no owner or follow-up.
Look into VEX, such as OpenVEX or the CycloneDX format. It lets you mark a finding as not affected and use standardized reasons like the vulnerable code not being in the execution path or the component not being present. Several scanners can consume VEX data, so the same justification can suppress future reports instead of being rewritten every quarter. You still need to perform the reachability analysis, but the evidence becomes machine-readable and easier to audit.
Before documenting hundreds of exceptions, reduce the source of the noise. Remove unused packages, produce slimmer runtime images, replace abandoned dependencies, and check whether your operating-system vendor has backported a fix even if the upstream version number has not changed. For containers, hardened or minimal base images can also reduce the number of irrelevant findings. Automation helps with triage, but it should support a documented decision process rather than simply hiding scanner results.
Keep the exceptions under version control or in a central risk register. A useful workflow is a pull request or approval record for each new exception, with the rationale, affected application or image, compensating controls, named approver, and a scheduled review. Recheck the list regularly for a vendor patch, backported distribution fix, or replacement dependency. This creates an audit trail and prevents old exceptions from becoming permanent by accident.
The review date matters almost as much as the original decision. An accepted risk that is never revisited can look like a broken process, while an accepted risk that is reviewed on schedule shows that the organization is actively managing it.

For the unreachable bucket, dependency and reachability analysis can help a lot. Group findings by dependency rather than handling every CVE independently, then maintain one rationale for a dependency or feature that is never used. The genuinely reachable, unpatched findings should remain in a smaller risk-acceptance queue.