# how to triage a new CVE for your stack

## TL;DR

Dont panic and dont patch blindly. Read the advisory, map the affected product and versions to your actual inventory, check whether the vulnerable code path is reachable in your stack, then decide: patch now, schedule, mitigate, or accept. Most CVEs never touch you; the ones that do get handled in order of real risk, not headline severity.

```text
how to triage a new CVE for your stack
```

## Use this when

- A new CVE is in the news and someone asks "are we affected"
- Your scanner or Dependabot flags a CVE and you need to decide how urgent it is
- A vendor publishes a security advisory for something you run
- You need a repeatable triage process instead of ad-hoc panic

## Not for this skill when

- You want the theory of severity vs exploitability scoring (thats a separate skill)
- You need to write a CVE summary for leadership (different skill, different audience)
- You are doing a full audit of every dependency (use a scanner workflow instead)
- The CVE is about your own shipped code, not a third-party component

## Steps

### 1. Capture the advisory facts

Get the CVE ID and pull the canonical details: affected product, affected version range, fixed version, and attack vector. The NVD entry or the vendor advisory is the source of truth, not the news article.

```bash
curl -s "https://services.nvd.nist.gov/rest/json/cves/2.0?cveId=CVE-2026-12345" | python3 -c "import json,sys; d=json.load(sys.stdin); print(d['vulnerabilities'][0]['cve']['descriptions'][0]['value'][:600])"
```

Expected: a short description naming the product, the vulnerable versions, and what an attacker can do. If the CVE ID has no NVD entry yet, use the vendor advisory; brand-new CVEs can lag by hours.

### 2. Check whether you run the affected product and version

Match the advisory against your real inventory, not your memory of it. Query the lockfile or package manager directly.

```bash
npx osv-scanner --lockfile=package-lock.json
```

Expected: osv-scanner lists known-vulnerable packages in that lockfile, or reports no issues. Per-ecosystem spot checks work too: `npm ls [package-name]`, `pip show [package-name]`, `go list -m all | grep [module-name]`. If nothing in your inventory matches the affected product, you are done; record "not affected" and move on.

### 3. Determine reachability

Affected does not mean exploitable. Check whether the vulnerable function, endpoint, or config is actually reachable in your deployment. Search for imports and call sites, and check whether the vulnerable feature is enabled in your config.

```bash
grep -rn "[vulnerable-function-or-import]" src/ --include="*.py"
```

Expected: either concrete call sites (reachable, keep going) or zero hits (probably not reachable, downgrade urgency). A CVE in an admin panel you never expose, or a parser for a format you never accept, is a schedule-it fix, not a drop-everything fix.

### 4. Check exploitation signals

Look for real-world exploitation: the CISA known-exploited list and the EPSS score. A CVE with a public exploit and a high EPSS score jumps the queue regardless of its CVSS number.

```bash
curl -s "https://api.first.org/data/v1/epss?cve=CVE-2026-12345"
```

Expected: a JSON response with an EPSS probability. Cross-check the CVE ID against the CISA known-exploited-vulnerabilities catalog; anything on that list is patch-now.

### 5. Make the call and record it

Decide: patch now, schedule, mitigate, or accept with a note. Log the CVE ID, decision, and date so nobody re-triages it from scratch.

```bash
echo "CVE-2026-12345 | affected, not reachable | scheduled for next sprint | $(date -u +%F)" | tee -a security-triage-log.txt
```

Expected: one line appended to your triage log. No log, no memory; triage you cant find later didnt happen.

### Variant: does this CVE affect my project

Same workflow, narrower scope: one repo, one CVE. Skip the org-wide inventory and go straight to the lockfile scan plus a reachability grep. If the scanner flags it and the code path is reachable, patch; if the scanner is clean, note the CVE ID and move on.

### Variant: new vulnerability triage process for a team

Turn the steps above into a runbook: who watches the feeds, who runs step 2 within 4 hours, where decisions get logged, and what "patch now" means for your deploy pipeline. The process matters more than any single CVE; teams without one re-litigate urgency every time.

### Variant: how to respond to a vendor security advisory

Vendor advisories sometimes understate version ranges. Verify against NVD and the release tags, and apply any workaround config first, patch second.

## Why this happens

Advisories describe the worst case for every possible deployment, so they read scarier than your reality. Most stacks dont run the affected version, dont enable the vulnerable feature, or dont expose the attack surface. Triage exists to close the gap between "vulnerable in theory" and "exploitable in your stack" without burning a sprint on every headline.

## Edge cases and pitfalls

- Transitive dependencies: the vulnerable package may be three levels deep; osv-scanner catches these, eyeballing package.json does not.
- Vendored code: scanners miss copied source; the reachability grep is your backstop.
- Container base images: the CVE may be in the OS layer, not your app deps; scan the image too.
- Dev-only dependencies: flagged by scanners but never shipped; confirm with your lockfile groups before panicking.
- Duplicate triage: without a log, three people triage the same CVE; the log in step 5 prevents this.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_2STtsKdhE04r3Wx5aqBeYg
