Vulnerability Management — Scanning, Prioritisation, Remediation
Build a systematic vulnerability management programme: continuous scanning, risk-based prioritisation using EPSS and CISA KEV, SLA enforcement, and metrics that matter.
What Is Vulnerability Management?
Vulnerability management (VM) is the continuous process of identifying, classifying, prioritising, remediating, and verifying security weaknesses across your entire attack surface. It is not a one-time scan — it is an ongoing programme that runs for the lifetime of the organisation.
The difference between a scanner and a VM programme: a scanner finds vulnerabilities; a programme ensures they get fixed. Most organisations that get breached already knew about the exploited vulnerability — they just lacked a system to drive remediation to completion.
The VM Lifecycle
VM Lifecycle (continuous loop):
1. Asset Discovery → 2. Scanning → 3. Analysis
↑ ↓
6. Verify / Retest ← 5. Remediate ← 4. Prioritise
Asset Discovery: know everything you own (shadow IT kills programmes)
Scanning: authenticated scans at appropriate frequency
Analysis: severity + exploitability + business context
Prioritise: risk-based, not CVSS-only
Remediate: patch, mitigate, or accept with documented rationale
Verify: rescan to confirm fix — never trust without testingKey Stakeholders
VM succeeds when multiple teams own their slice. The security team runs the programme; IT/DevOps patches; engineering remediates code vulnerabilities; management accepts residual risk. Without executive sponsorship to enforce SLAs, VM programmes stall.
| Role | Responsibility | Success Metric |
|---|---|---|
| VM Team / Security | Own the programme, run scans, report metrics | Mean time to remediate (MTTR), coverage % |
| IT / SysOps | Patch OS, middleware, firmware | Critical patch rate within SLA |
| DevOps / Platform | Patch containers, cloud config, IaC | Container image age, misconfig closure rate |
| Application Engineering | Remediate code-level vulns (SAST/DAST findings) | Open critical findings, time to fix |
| Risk / Compliance | Set SLAs, accept residual risk, audit evidence | Compliance report pass rate |
| CISO / Leadership | Enforce SLAs, escalate blockers, fund tools | Programme maturity score |
Asset Discovery and Inventory
You cannot protect what you do not know about. Asset discovery is the foundation — gaps in inventory create blind spots that attackers exploit. Shadow IT (systems deployed without IT approval) is one of the leading causes of breach: developers spin up a cloud VM, forget about it, and it runs unpatched for two years.
Discovery Methods
# Active network scanning — finds live hosts
nmap -sn 10.0.0.0/8 --min-rate 1000 -oG ping_sweep.txt
# Parse live hosts
grep "Up" ping_sweep.txt | awk '{print $2}' > live_hosts.txt
# Cloud asset discovery — AWS (enumerate all regions)
for region in $(aws ec2 describe-regions --query 'Regions[].RegionName' --output text); do
echo "=== $region ==="
aws ec2 describe-instances --region $region --query 'Reservations[].Instances[].[InstanceId,Tags[?Key==Name].Value|[0],State.Name,PublicIpAddress]' --output table
done
# Shadow IT discovery — scan RFC 1918 space
nmap -sn 192.168.0.0/16 172.16.0.0/12 10.0.0.0/8 --exclude known_assets.txt
# Cloud Security Posture Management (CSPM) tools for cloud assets:
# - AWS Security Hub, Azure Defender, Google Security Command Center
# - Wiz, Orca Security, Lacework (commercial, widely used)Asset Inventory Schema
A bare-minimum asset record needs enough context to prioritise and route remediation correctly. Criticality is set by the business, not the security team.
Asset record (minimum viable):
{
"asset_id": "SRV-0042",
"hostname": "payments-api-prod-1",
"ip": "10.5.2.44",
"os": "Ubuntu 22.04 LTS",
"owner": "payments-team@company.com",
"env": "production",
"criticality": "critical", // critical / high / medium / low
"internet_facing": true,
"data_classification": "PCI", // affects SLA tier
"last_scanned": "2026-05-08",
"patch_group": "payments-prod", // maps to change window
"tags": ["pci-in-scope", "tier-1"]
}Vulnerability Scanning
Scanning finds vulnerabilities by comparing observed software versions and configurations against known CVE databases. Authenticated scans (using credentials) find 3–5× more vulnerabilities than unauthenticated scans — always use them for internal assets.
Scanning Cadence by Environment
| Environment | Frequency | Scan Type | Rationale |
|---|---|---|---|
| Internet-facing / DMZ | Daily | Unauthenticated + authenticated | Highest exposure, attackers scan continuously |
| Production internal | Weekly | Authenticated | Balance coverage with change velocity |
| Pre-production / staging | On every deploy (CI/CD) | Authenticated + DAST | Catch before prod promotion |
| Dev / test | Weekly or on-demand | Authenticated | Build security awareness in devs |
| Cloud infrastructure | Continuous (CSPM) | API-based config assessment | Cloud config drifts fast |
| OT / ICS (if applicable) | Monthly (passive) | Passive / agent-based only | Active scanning can crash OT devices |
Nessus — Industry Standard Scanner
Nessus (Tenable) is the most widely deployed commercial scanner. Nessus Essentials is free for up to 16 IPs — sufficient for a home lab. The enterprise product is Tenable.io / Tenable.sc.
Nessus scan configuration checklist: 1. Credentials (for authenticated scan): - SSH: key-based auth preferred (create a dedicated scanner user) - Windows: domain admin or local admin on target (SMB + WMI) - Database: read-only credentials for MSSQL/MySQL/Oracle - Web: authenticated session cookie or credentials 2. Scan policy settings: - Enable "Safe checks" (avoids DoS-risk plugins) - Set scan window to match change freeze schedule - Use "credentialed patch audit" plugin family - Enable "Host enumeration" to catch all open ports 3. Post-scan: - Export: .nessus (XML) for integration, PDF for stakeholders - Import to your VM platform (Tenable.sc, Plextrac, Nucleus Security) - Deduplicate findings across scan cycles # Nessus CLI (nessuscli) for automation: /opt/nessus/sbin/nessuscli scan --id 42 --export /tmp/scan_2026-05-08.nessus
Open-Source Scanners
# OpenVAS / Greenbone (free Nessus alternative) # Install via Docker docker run -d -p 9392:9392 --name openvas greenbone/community-edition # Access web UI at https://localhost:9392 (admin / admin — change immediately) # Nuclei — fast template-based scanner, great for web + cloud nuclei -l targets.txt -t technologies/ -t cves/ -t misconfigurations/ -severity critical,high -o findings.txt -stats # Trivy — container and IaC scanning (used in CI/CD pipelines) trivy image nginx:latest --severity CRITICAL,HIGH trivy fs . --scanners vuln,misconfig,secret trivy k8s cluster --report summary # Grype — alternative container scanner (works offline with local DB) grype nginx:latest grype sbom:/path/to/sbom.json
Container and Cloud-Specific Scanning
# Scan all images in a Kubernetes cluster
kubectl get pods -A -o jsonpath='{range .items[*]}{.spec.containers[*].image}{"
"}{end}' | sort -u | while read img; do trivy image "$img" --severity CRITICAL; done
# AWS — Scan EC2 with AWS Inspector (agentless, uses SSM)
aws inspector2 enable --resource-types EC2 EC2 ECR LAMBDA
# IaC scanning — catch misconfigs before deploy
# Checkov (Terraform, CloudFormation, Kubernetes, Dockerfiles)
checkov -d ./terraform/ --framework terraform --output cli
# tfsec — Terraform security scanner
tfsec ./terraform/ --severity HIGH
# KICS — multi-framework IaC scanner
kics scan -p ./infra/ -o ./results/ --report-formats json,htmlRisk-Based Prioritisation
CVSS score alone is a terrible prioritisation signal. A CVSS 9.8 vulnerability on a dev laptop that holds no sensitive data is less urgent than a CVSS 7.2 vulnerability on a PCI-in-scope database that is actively being exploited in the wild. Risk = Severity × Exploitability × Business Impact.
The Problem with CVSS-Only Prioritisation
Why CVSS fails as a sole prioritisation metric:
Issue 1 — Volume: 60-80% of CVEs score 7.0+ (CVSS "high" or "critical")
Patching everything critical is humanly impossible at scale
Issue 2 — No exploitability context: CVSS scores theoretical maximum impact
Most critical CVEs are never weaponised in actual attacks
Issue 3 — No business context: CVSS doesn't know if the asset holds PCI data
or is an air-gapped test VM
Reality: In a 10,000-asset environment, a weekly scan might surface
2,000+ unique findings. You need a filter more granular than CVSS.EPSS — Exploit Prediction Scoring System
EPSS (maintained by FIRST.org) uses machine learning on 1,000+ features — NVD data, PoC availability, social media mentions, dark web discussion — to predict the probability that a CVE will be exploited in the wild within the next 30 days. EPSS score 0.0–1.0: probability of exploitation.
# EPSS API — get score for a specific CVE
curl -s "https://api.first.org/data/v1/epss?cve=CVE-2021-44228" | python3 -m json.tool
# Response: { "epss": "0.97566", "percentile": "0.99975" }
# CVE-2021-44228 (Log4Shell) — 97.6% probability of exploitation
# Bulk EPSS lookup — query your finding list
curl -s "https://api.first.org/data/v1/epss?cve=CVE-2023-44487,CVE-2024-21762" | jq '.'
# Python: enrich your scanner output with EPSS scores
import requests
def get_epss(cves: list[str]) -> dict:
cve_str = ",".join(cves)
r = requests.get(f"https://api.first.org/data/v1/epss?cve={cve_str}")
return {d["cve"]: float(d["epss"]) for d in r.json()["data"]}
findings = ["CVE-2021-44228", "CVE-2022-22965", "CVE-2023-44487"]
scores = get_epss(findings)
for cve, score in sorted(scores.items(), key=lambda x: -x[1]):
print(f"{cve}: {score:.4f} ({score*100:.1f}% exploit probability)")CISA Known Exploited Vulnerabilities (KEV) Catalogue
The CISA KEV catalogue lists CVEs with confirmed active exploitation in the wild. Federal agencies are mandated to patch KEV entries within 15 days. For any organisation, KEV = patch now. There are no exceptions for business priorities or change freezes — a KEV entry means real attackers are using this today.
# Download CISA KEV catalogue (JSON, updated frequently)
curl -s https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json | jq '.vulnerabilities[] | {cveID, vendorProject, product, dateAdded, dueDate}' | head -40
# Cross-reference your findings against KEV
import json, requests
kev_url = "https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json"
kev = {v["cveID"] for v in requests.get(kev_url).json()["vulnerabilities"]}
my_findings = ["CVE-2021-44228", "CVE-2022-30190", "CVE-2023-99999"]
kev_matches = [cve for cve in my_findings if cve in kev]
print(f"KEV matches requiring immediate action: {kev_matches}")Prioritisation Decision Framework
Prioritisation tiers (apply in order): Tier 0 — PATCH IMMEDIATELY (same business day): ✓ In CISA KEV catalogue (confirmed active exploitation) ✓ Public PoC + EPSS > 0.50 (high weaponisation probability) ✓ CVSSv3 >= 9.0 + internet-facing asset (high exposure) Tier 1 — PATCH WITHIN 7 DAYS: ✓ EPSS > 0.10 + critical/high CVSS ✓ CVSSv3 >= 7.0 + production + PCI/HIPAA/SOC2 in-scope Tier 2 — PATCH WITHIN 30 DAYS: ✓ CVSSv3 >= 7.0 + internal production ✓ Medium CVSS + high-criticality asset Tier 3 — PATCH WITHIN 90 DAYS: ✓ CVSSv3 < 7.0 or low-criticality asset ✓ Informational / best-practice findings Risk Acceptance (document and review quarterly): ✓ Patch breaks functionality (need compensating control) ✓ End-of-life system with replacement in progress ✓ Cost of remediation exceeds risk (rare, requires CISO sign-off)
Combining Signals — Practical Scoring Formula
# Risk score that combines CVSS, EPSS, KEV, and asset criticality
def risk_score(cvss: float, epss: float, kev: bool,
criticality: str, internet_facing: bool) -> float:
criticality_weight = {"critical": 2.0, "high": 1.5, "medium": 1.0, "low": 0.5}
base = cvss / 10.0 # normalise to 0-1
exploit = epss # 0-1 probability
kev_bonus = 0.4 if kev else 0 # known-exploited multiplier
asset_weight = criticality_weight.get(criticality, 1.0)
exposure = 1.3 if internet_facing else 1.0
score = (base * 0.3 + exploit * 0.4 + kev_bonus) * asset_weight * exposure
return min(score, 1.0) # clamp to 1.0
# Examples:
# Log4Shell on internet-facing prod: risk_score(10.0, 0.976, True, "critical", True) = 1.0
# Medium CVE on dev machine: risk_score(5.5, 0.001, False, "low", False) = 0.08SLA Management and Remediation Tracking
SLAs (Service Level Agreements) give remediation deadlines teeth. Without defined, enforced SLAs, "we'll get to it" becomes the de facto policy. SLAs should be set by risk tier, reviewed annually, and enforced through escalation — not shaming.
SLA Tiers by Risk
| Tier | Criteria | SLA | Escalation If Missed |
|---|---|---|---|
| Critical (Tier 0) | KEV + critical asset, or EPSS > 0.5 + internet-facing | 24 hours (emergency change) | CISO notified; emergency change process |
| High (Tier 1) | EPSS > 0.10 + CVSS >= 7 + production | 7 days | VP Engineering escalation |
| High (Tier 2) | CVSS >= 7 + production internal | 30 days | Team manager escalation |
| Medium (Tier 3) | CVSS 4-6.9 + any production | 90 days | Quarterly review meeting |
| Low / Info (Tier 4) | CVSS < 4 or informational | 180 days or accept | Documented risk acceptance |
Remediation Workflow
Ticket lifecycle for a vulnerability finding:
1. IDENTIFIED → scanner detects CVE-2024-XXXX on payments-api-prod-1
- VM platform auto-creates ticket in Jira
- Assigns to asset owner: payments-team
- Sets SLA due date: 2026-05-15 (7 days, Tier 1)
- Links CVE, CVSS, EPSS, remediation guidance
2. ASSIGNED → owner acknowledges within 24 hours
- Confirms understanding of vulnerability
- Assesses feasibility (can we patch without downtime?)
- May request SLA extension with justification
3. IN PROGRESS → work underway
- Patch tested in staging first
- Change request created (CAB approval if required)
- Compensating controls applied if patch delayed
(e.g., WAF rule, network block, disable feature)
4. REMEDIATED → owner marks complete
- VM team rescans asset within 48 hours
- Scanner must not detect the CVE on rescan
- If still detected: ticket reopened, clock resets
5. VERIFIED → VM team confirms clean rescan
- Ticket closed with evidence (scan report link)
- Metrics updated (MTTR recorded)
6. RISK ACCEPTED (alternative path)
- Owner requests acceptance with written justification
- CISO or risk owner signs off
- Review date set (max 90 days for critical, 180 for others)
- Compensating control documentedJira Automation for VM Workflows
# Jira automation rule (pseudo-config) — auto-create VM tickets from scanner API
trigger: webhook from VM platform (Tenable / Qualys)
condition: finding.severity IN ["Critical", "High"] AND finding.asset.env == "production"
actions:
- create issue in project VM
- set priority based on severity
- set due date based on SLA table
- assign to asset.owner (from CMDB lookup)
- add label: "vuln-mgmt", asset.data_classification
- comment: "CVE: {cve_id} | CVSS: {cvss} | EPSS: {epss} | KEV: {in_kev}"
- notify: asset.owner via Slack DM
# Python: Tenable.io → Jira sync example
import tenable, jira
tio = tenable.TenableIO(access_key, secret_key)
jira_client = jira.JIRA(server, auth=(user, token))
for finding in tio.exports.vulns(severity=["critical","high"]):
issue = jira_client.create_issue(
project="VM",
summary=f"{finding['cve_id']} on {finding['asset']['hostname']}",
description=build_description(finding),
priority={"name": map_priority(finding["severity"])},
duedate=calculate_sla(finding),
assignee={"name": lookup_owner(finding["asset"]["fqdn"])}
)Compensating Controls (When You Cannot Patch)
Sometimes patches break applications, require downtime windows months away, or affect EOL systems. Compensating controls buy time while the root fix is scheduled.
Common compensating controls by vulnerability type: Remote Code Execution (unauthenticated): ✓ Block all network access to the service (firewall/security group) ✓ Deploy WAF rule targeting the specific attack pattern ✓ Disable the vulnerable feature/endpoint if possible Authentication bypass: ✓ Restrict access to internal network or VPN only ✓ Add layer-7 authentication in front (reverse proxy + auth) Privilege escalation (local): ✓ Restrict who can log into the host (remove unnecessary accounts) ✓ Increase monitoring (alert on privilege escalation attempts) Default credentials: ✓ Immediate: change credentials (this is never acceptable to defer) SQL injection: ✓ WAF SQL injection protection rules ✓ Restrict DB account permissions to minimum needed IMPORTANT: Compensating controls MUST be documented in the ticket with evidence they are active. "WAF blocks it" is not a patch.
VM Metrics and Reporting
Metrics prove programme effectiveness and identify bottlenecks. Without data, every team claims they are doing fine while vulnerabilities age past SLA. Report metrics weekly to team leads, monthly to management, and quarterly to the board.
Core VM Metrics
| Metric | Definition | Target | Why It Matters |
|---|---|---|---|
| Mean Time to Remediate (MTTR) | Avg days from detection to verified fix | < 7 days critical, < 30 high | Core programme velocity metric |
| SLA Compliance Rate | % of findings closed within SLA | > 90% critical, > 80% high | Reveals teams missing deadlines |
| Scan Coverage | % of assets scanned in last 7/30 days | > 95% internet-facing weekly | Blind spots = breach risk |
| Vulnerability Density | Critical+High per 100 assets | Trending down over time | Programme effectiveness indicator |
| Reopen Rate | % of "fixed" findings that reopen on rescan | < 5% | Measures patch quality |
| KEV Closure Rate | % of CISA KEV findings closed in time | 100% within due date | Regulatory / compliance metric |
| Ageing Vulnerabilities | Criticals open > 30 days, Highs > 90 days | 0 criticals > 30 days | Staleness indicates process failure |
| Risk Score Trend | Weighted risk score across all assets over time | Decreasing quarter over quarter | Lagging outcome metric |
Dashboard Queries — Splunk
# Vulnerability ageing — criticals open longer than SLA
index=vuln_mgmt severity="Critical" status!="Closed"
| eval days_open = (now() - strptime(created_date, "%Y-%m-%d")) / 86400
| where days_open > 7
| stats count by team, hostname, cve_id, days_open
| sort -days_open
# MTTR by team — last 30 days
index=vuln_mgmt status="Closed" severity IN ("Critical","High")
| eval remediation_days = (strptime(closed_date,"%Y-%m-%d") - strptime(created_date,"%Y-%m-%d")) / 86400
| stats avg(remediation_days) as avg_mttr, count as closed_count by team
| sort avg_mttr
# SLA compliance rate per team
index=vuln_mgmt status="Closed" severity="Critical"
| eval sla_days = case(severity=="Critical", 7, severity=="High", 30, true(), 90)
| eval remediation_days = (strptime(closed_date,"%Y-%m-%d") - strptime(created_date,"%Y-%m-%d")) / 86400
| eval within_sla = if(remediation_days <= sla_days, 1, 0)
| stats avg(within_sla)*100 as sla_compliance_pct by team
| sort -sla_compliance_pctExecutive Report Template
Monthly VM Report — May 2026 EXECUTIVE SUMMARY: - Open Critical Vulnerabilities: 12 (down from 23 last month, -48%) - SLA Compliance (Critical): 94% (target: 90%) ✓ - Mean Time to Remediate (Critical): 4.2 days (target: < 7 days) ✓ - Assets scanned (past 7 days): 98.3% of internet-facing (target: 95%) ✓ - CISA KEV findings resolved on time: 8/8 (100%) ✓ CONCERNS REQUIRING ATTENTION: 1. Payments team MTTR: 11.2 days (above 7-day SLA target) - Root cause: change freeze for Q2 release until May 20 - Action: compensating controls applied; patch scheduled May 21 2. Legacy POS systems (15 assets): unauthenticated scan only - Root cause: no credential management for EOL systems - Action: EOL migration project approved, complete by August TOP RISKS THIS MONTH: - CVE-2024-XXXX (KEV entry): Patched within 18 hours of CISA listing - Unpatched Apache on 3 dev servers: Risk accepted, decommission planned
Integrating VM into the SDLC
The most cost-effective place to fix a vulnerability is before it ships. Integrating security scanning into the software development lifecycle (SDLC) — shift-left security — finds issues when they are cheapest to fix: in code, not in production.
The Cost of Late Detection
Relative cost to fix a vulnerability by phase: Design: $1 (architecture review catches it) Development: $6 (SAST flags it in IDE / pre-commit) Integration test: $16 (DAST catches it in CI) Staging: $33 (pentest finds it pre-launch) Production: $80 (VM scanner finds it post-deploy) Post-breach: $640+ (incident response + legal + PR) Source: IBM Systems Sciences Institute (adapted) Principle: Fix left, save right.
Shift-Left Pipeline Integration
# GitHub Actions — complete shift-left security pipeline
name: Security Pipeline
on: [push, pull_request]
jobs:
sast:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Semgrep SAST
uses: semgrep/semgrep-action@v1
with:
config: "p/owasp-top-ten p/python p/javascript"
sca:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Trivy dependency scan
run: |
trivy fs . --scanners vuln --severity CRITICAL,HIGH --exit-code 1 --format sarif --output trivy-sca.sarif
- uses: github/codeql-action/upload-sarif@v3
with: { sarif_file: trivy-sca.sarif }
container-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build image
run: docker build -t app:ci .
- name: Trivy container scan
run: trivy image app:ci --severity CRITICAL,HIGH --exit-code 1
secrets-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 0 }
- name: Gitleaks secret detection
uses: gitleaks/gitleaks-action@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}SBOM — Software Bill of Materials
An SBOM is a machine-readable inventory of all components in a software artefact. Executive Order 14028 mandates SBOMs for US federal software suppliers. SBOMs enable rapid impact assessment when new CVEs drop — instead of asking "do we use Log4j?", you query your SBOM database.
# Generate SBOM with Syft (CycloneDX or SPDX format) syft nginx:latest -o cyclonedx-json > nginx-sbom.json syft dir:./myapp -o spdx-json > myapp-sbom.json # Scan SBOM against vulnerability database with Grype grype sbom:nginx-sbom.json --severity critical,high # Store SBOMs in a central registry (e.g., Dependency-Track) # Query: "which services use log4j 2.x?" curl -X POST https://dtrack.company.com/api/v1/bom -H "X-Api-Key: $DTRACK_API_KEY" -F "autoCreate=true" -F "projectName=payments-api" -F "projectVersion=2.4.1" -F "bom=@payments-api-sbom.json"
Vulnerability Management Tools Landscape
Commercial VM Platforms
| Tool | Category | Best For | Notes |
|---|---|---|---|
| Tenable.io / Nessus | Scanner + VM platform | Enterprise VM, compliance reporting | Market leader; Nessus Essentials free for 16 IPs |
| Qualys VMDR | Scanner + VM platform | Large enterprises, cloud-native | Strong cloud integration, continuous monitoring |
| Rapid7 InsightVM | Scanner + VM platform | Remediation workflow integration | Good Jira/ServiceNow integration, attacker context |
| Microsoft Defender for Endpoint | Agent-based VM | Windows-heavy environments | Built into Defender; no scanner deployment needed |
| Wiz / Orca Security | Cloud VM (CSPM) | Cloud-native organisations | Agentless cloud scanning; excellent for AWS/Azure/GCP |
| Nucleus Security | VM orchestration | Aggregating multiple scanner sources | Normalises Nessus + Qualys + Burp into one view |
| Dependency-Track | SCA / SBOM management | Application component tracking | Open-source; integrates with Syft/Grype/CycloneDX |
| OpenVAS / Greenbone | Open-source scanner | Budget-constrained; home labs | Free; not as comprehensive as Nessus |
Workplace Scenario — Building a VM Programme from Scratch
Context: You join a 500-person SaaS company as their first dedicated
security engineer. They have no formal VM programme. The CEO asks you
to brief the board in 90 days on their vulnerability posture.
Week 1-2: Asset discovery
- Export all AWS/Azure resources via cloud APIs
- Run nmap against all known IP ranges
- Import to spreadsheet / CMDB (buy ServiceNow if budget exists)
- Identify internet-facing assets: these are your first priority
Week 3-4: First scan
- Deploy Nessus (Tenable.io trial or Essentials for labs)
- Run authenticated scan against internet-facing assets
- Expect shock: first scan on a neglected environment often
surfaces dozens of criticals and hundreds of highs
Week 5-8: Prioritise and begin remediation
- Cross-reference with CISA KEV — patch those first, same day
- Assign owners via asset inventory
- Set SLAs: 7 days critical, 30 days high
- Begin tracking in Jira with VM project board
Week 9-12: Metrics and process
- Build MTTR dashboard
- First monthly VM report to leadership
- Integrate Trivy into CI/CD for new findings
- Board presentation: "We found 42 critical vulnerabilities.
28 are closed. 14 remain, all tracked with owners and due dates.
Our MTTR is 8 days for critical. Here is our 6-month roadmap."🎯 Key Takeaways
- ✓VM is a continuous programme, not a point-in-time scan — covering discovery, scanning, prioritisation, remediation, and verification in a repeating loop.
- ✓Authenticated scans find 3-5× more vulnerabilities than unauthenticated scans; always use credentials for internal asset scanning.
- ✓CVSS alone is a poor prioritisation signal — combine it with EPSS (exploit probability), CISA KEV (confirmed exploitation), and asset criticality.
- ✓CISA KEV entries represent vulnerabilities actively exploited in the wild — treat them as emergency patches regardless of CVSS score.
- ✓SLAs give remediation deadlines: Critical/KEV within 24 hours, High within 7-30 days, Medium within 90 days — enforced through escalation.
- ✓Compensating controls (WAF rules, network isolation, feature disable) buy time when immediate patching is not feasible, but must be documented with an expiry date.
- ✓Never close a remediation ticket without rescanning — track reopen rates; high reopens indicate patching quality problems.
- ✓Shift-left scanning (SAST, SCA, container scanning in CI/CD) catches vulnerabilities at 6× lower cost than finding them in production.
- ✓SBOMs enable rapid impact assessment when new CVEs drop — query your component inventory instead of manually hunting through codebases.
- ✓Report VM metrics in business language: breach risk reduction, SLA compliance rates, and MTTR trends — not CVE counts and CVSS averages.
With vulnerabilities identified and managed, you need a plan for when one gets exploited. Module 33 covers the full incident response lifecycle: preparation, detection and identification, containment, eradication, recovery, and lessons learned. You will build IR playbooks, work through a real ransomware scenario, and learn the digital forensics fundamentals that feed post-incident investigations.
Discussion
0Have a better approach? Found something outdated? Share it — your knowledge helps everyone learning here.