# Vulnerability Management and Triage — DevSecOps

Source: https://www.skillbyai.com/en/devsecops/dso-vuln-management

> Prioritise findings using severity, exploitability and exposure, and run a fix process with clear deadlines.

## From a pile of findings to a plan

Scanners produce far more findings than any team can fix at once, so **triage** decides the order. **CVSS** scores the technical severity of a vulnerability from 0 to 10, but severity alone is a poor queue: a critical CVE in a library function you never call matters less than a medium one in your internet-facing login service. Add **exploitability**: the **EPSS** score estimates the probability a CVE will be exploited in the wild soon, and the **CISA Known Exploited Vulnerabilities (KEV)** catalogue lists CVEs already exploited. Add **context**: is the component reachable, internet-facing, handling sensitive data? Then set remediation **SLAs** per priority, assign an owner, and track **mean time to remediate** rather than the raw number of open findings. Accepted risks need a written reason, an approver and an expiry date, so 'temporarily ignored' does not quietly become forever.

## The vulnerability management loop

Findings flow from detection to triage, where they are prioritised, then to remediation by the owning team, and finally to verification that the fix is deployed, before the loop repeats.

![Four connected stages: detect, triage, remediate, verify.](assets/figures/devsecops/section-9-map.svg) — Figure 9.1: detect -> triage -> remediate -> verify.

## Ranking findings by real-world risk

Known-exploited first, then exposure and exploit probability, then CVSS. The CVE IDs and scores are illustrative.

```python
findings = [
    {"cve": "CVE-A", "cvss": 9.8, "epss": 0.02, "kev": False, "internet": False},
    {"cve": "CVE-B", "cvss": 7.5, "epss": 0.91, "kev": True,  "internet": True},
    {"cve": "CVE-C", "cvss": 6.1, "epss": 0.40, "kev": False, "internet": True},
    {"cve": "CVE-D", "cvss": 5.3, "epss": 0.01, "kev": False, "internet": False},
]
def priority(f):
    return (f["kev"], f["internet"], f["epss"], f["cvss"])
for rank, f in enumerate(sorted(findings, key=priority, reverse=True), 1):
    print(rank, f["cve"], f"cvss={f['cvss']}", f"epss={f['epss']}", "KEV" if f["kev"] else "")
```

Output:

```
1 CVE-B cvss=7.5 epss=0.91 KEV
2 CVE-C cvss=6.1 epss=0.4 
3 CVE-A cvss=9.8 epss=0.02 
4 CVE-D cvss=5.3 epss=0.01 
```

## Reachability cuts noise

Some SCA tools check whether your code actually calls the vulnerable function. A reachable medium often deserves attention before an unreachable critical.

**Quiz:** Which signal tells you a vulnerability is already being exploited by attackers?

- [ ] A high CVSS base score
- [x] Being listed in the CISA Known Exploited Vulnerabilities catalogue
- [ ] Being found by SAST
- [ ] Having a long description

*Answer:* Being listed in the CISA Known Exploited Vulnerabilities catalogue. KEV lists CVEs with evidence of active exploitation; CVSS measures severity, not whether exploitation is happening.
