Your Scanner Found 200 CVEs. You Have Time to Fix Maybe Five.
Dependency vulnerability scanners report every known CVE in every package, including dev dependencies, transitive dependencies of unused features, and CVEs that require local access. Treating all 200 as equal priority means you fix none effectively. Triage by actual risk.
Start with OpsCheck Package Vulnerability Check to scan your composer.json or package.json directly. Then use OpsCheck SBOM Vulnerability Scanner for a full dependency tree analysis.
The Triage Framework
# Export your dependency list
composer show --format=json > composer-packages.json
npm list --json > npm-packages.json
# For each CVE, ask in order:
# 1. Is this package actually deployed in production? (not dev-only)
# 2. Is the vulnerable function actually reachable from untrusted input?
# 3. What is the attack vector? (Network > Adjacent > Local > Physical)
# 4. Is there a known public exploit? (CVSS "exploitability" subscore)
# 5. Can we patch without breaking the application?
Prioritization Matrix
# Tier 1 — Fix immediately (today)
# - CVSS >= 9.0, Network attack vector, known public exploit
# - Remote code execution (RCE) in a network-facing component
# - Authentication bypass in your framework or auth library
# Tier 2 — Fix this sprint
# - CVSS 7.0-8.9, Network vector, no public exploit yet
# - Information disclosure in logging or error handling libraries
# - Denial of service in request parsing
# Tier 3 — Schedule for next maintenance window
# - CVSS 4.0-6.9, Local or Adjacent vector
# - Vulnerabilities in CLI tools not exposed to web traffic
# - Issues in dev dependencies that never run in production
# Tier 4 — Accept the risk
# - CVSS < 4.0, Physical access required, theoretical exploits
# - Vulnerabilities in optional features you do not use
# - Issues already mitigated by your deployment architecture
Real-World Scenario
A Laravel application's composer audit showed 47 CVEs. 38 of them were in dev dependencies (phpunit, mockery, etc.) — zero runtime risk. 7 were in production dependencies. Of those, 4 required local filesystem access already restricted by containerization. 2 were in a mail library used only for queue workers, not exposed to user input. The remaining 1 — a Guzzle CVE with CVSS 8.2 — was the only one that mattered. Patching it took 5 minutes. The team had previously spent an entire sprint trying to fix all 47.
The OpsCheck Hash Generator was used to verify the patched library file matched the expected checksum before deployment.
# Quick triage: separate production from dev dependencies
composer show --no-dev --format=json | python3 -c "
import json, sys
deps = json.load(sys.stdin)
for pkg in deps.get('installed', []):
print(f'{pkg[\"name\"]}@{pkg[\"version\"]}')
"
Triage Checklist
- Run OpsCheck Package Vulnerability Check for your manifest
- Separate dev vs production dependencies — dev CVEs rarely matter
- Assess reachability: is the vulnerable code path actually exercised?
- Check the attack vector: Network > Adjacent > Local > Physical
- Look for public exploits — CVSS score without an exploit is less urgent
- Document accepted risks with a justification for auditors