Python · SQL · Web Dev · Java · AI/ML tracks launching soon — your one platform for all of IT

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.

38 min May 2026

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 testing

Key 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.

RoleResponsibilitySuccess Metric
VM Team / SecurityOwn the programme, run scans, report metricsMean time to remediate (MTTR), coverage %
IT / SysOpsPatch OS, middleware, firmwareCritical patch rate within SLA
DevOps / PlatformPatch containers, cloud config, IaCContainer image age, misconfig closure rate
Application EngineeringRemediate code-level vulns (SAST/DAST findings)Open critical findings, time to fix
Risk / ComplianceSet SLAs, accept residual risk, audit evidenceCompliance report pass rate
CISO / LeadershipEnforce SLAs, escalate blockers, fund toolsProgramme 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"]
}
Pro Tip: Integrate asset discovery with your CMDB (ServiceNow, Jira Assets) so that vulnerability findings auto-route to the correct team. Manual routing at scale kills programmes.

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

EnvironmentFrequencyScan TypeRationale
Internet-facing / DMZDailyUnauthenticated + authenticatedHighest exposure, attackers scan continuously
Production internalWeeklyAuthenticatedBalance coverage with change velocity
Pre-production / stagingOn every deploy (CI/CD)Authenticated + DASTCatch before prod promotion
Dev / testWeekly or on-demandAuthenticatedBuild security awareness in devs
Cloud infrastructureContinuous (CSPM)API-based config assessmentCloud config drifts fast
OT / ICS (if applicable)Monthly (passive)Passive / agent-based onlyActive 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,html
Interview Question
What is the difference between an authenticated and an unauthenticated vulnerability scan?
Unauthenticated scans see what an attacker without credentials sees: open ports, service banners, and externally visible vulnerabilities. Authenticated scans log into the target with valid credentials and check installed software versions, patch levels, registry settings, and file permissions — typically finding 3-5x more vulnerabilities. Always prefer authenticated scans for internal assets; unauthenticated scans are appropriate for simulating external attacker perspective.

Risk-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.08
Interview Question
What is EPSS and why is it more useful than CVSS for prioritisation?
EPSS (Exploit Prediction Scoring System) estimates the probability that a CVE will be exploited in the wild within 30 days, using machine learning on threat intelligence signals. CVSS scores theoretical severity (what could happen if exploited), but around 60-80% of CVEs score 7+ in CVSS, making it useless for triage. EPSS adds exploitability context — only about 5-10% of CVEs score above 0.10 in EPSS, dramatically narrowing the must-fix list. The best approach combines CVSS (severity), EPSS (likelihood), CISA KEV (confirmed exploitation), and business context (asset criticality, data classification).
Interview Question
A CISO asks you to explain risk-based prioritisation to a non-technical board. How do you frame it?
Frame it as triage in an emergency room: not every patient gets treated in order of arrival — the most critical go first. We have thousands of vulnerabilities but limited patching capacity. Risk-based prioritisation uses three signals: Is this vulnerability being actively exploited right now? (CISA KEV), How likely is it to be exploited soon? (EPSS probability score), and How valuable is the affected system? (business criticality). This focuses our team on the 5% of vulnerabilities that represent 80% of our actual breach risk, rather than chasing a perfect score on a severity leaderboard.

SLA 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

TierCriteriaSLAEscalation If Missed
Critical (Tier 0)KEV + critical asset, or EPSS > 0.5 + internet-facing24 hours (emergency change)CISO notified; emergency change process
High (Tier 1)EPSS > 0.10 + CVSS >= 7 + production7 daysVP Engineering escalation
High (Tier 2)CVSS >= 7 + production internal30 daysTeam manager escalation
Medium (Tier 3)CVSS 4-6.9 + any production90 daysQuarterly review meeting
Low / Info (Tier 4)CVSS < 4 or informational180 days or acceptDocumented 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 documented

Jira 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.
Interview Question
A critical vulnerability is found on a production server, but the patch breaks a business-critical application and the vendor won't release a fix for 60 days. What do you do?
This is a risk acceptance scenario that requires a documented, time-bound decision. First, implement compensating controls immediately: firewall the vulnerable port, add WAF rules targeting the attack vector, and increase monitoring/alerting around the affected system. Second, document everything: the vulnerability details, why patching is not immediately feasible, which compensating controls are active, and the expected patch date. Third, escalate for formal risk acceptance: CISO or risk owner signs off, sets a hard deadline (no longer than the vendor's promised patch date), and schedules a 30-day review. The risk acceptance expires automatically and must be renewed with fresh justification.
Common Mistake — Marking findings remediated without rescanning
Bad: Close the ticket when the owner says 'I patched it' without verifying with a rescan.
Good: Rescan the specific asset within 48 hours of reported remediation. Only close the ticket when the scanner confirms the CVE is no longer detected. Track reopen rates — high reopen = patching quality problem.

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

MetricDefinitionTargetWhy It Matters
Mean Time to Remediate (MTTR)Avg days from detection to verified fix< 7 days critical, < 30 highCore programme velocity metric
SLA Compliance Rate% of findings closed within SLA> 90% critical, > 80% highReveals teams missing deadlines
Scan Coverage% of assets scanned in last 7/30 days> 95% internet-facing weeklyBlind spots = breach risk
Vulnerability DensityCritical+High per 100 assetsTrending down over timeProgramme effectiveness indicator
Reopen Rate% of "fixed" findings that reopen on rescan< 5%Measures patch quality
KEV Closure Rate% of CISA KEV findings closed in time100% within due dateRegulatory / compliance metric
Ageing VulnerabilitiesCriticals open > 30 days, Highs > 90 days0 criticals > 30 daysStaleness indicates process failure
Risk Score TrendWeighted risk score across all assets over timeDecreasing quarter over quarterLagging 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_pct

Executive 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
Interview Question
How do you report vulnerability management metrics to a board that does not understand CVSS or CVEs?
Translate technical metrics into business risk language. Instead of 'we have 23 critical CVEs', say 'we have 23 vulnerabilities that, if exploited, could result in data breach or system compromise — 18 are patched and we are tracking the remaining 5 to resolution within the week.' Show trends, not snapshots: 'our critical vulnerability count is down 48% from last quarter, and we resolved all 8 actively-exploited vulnerabilities within 18 hours of public disclosure.' Frame SLA performance as operational reliability: 'our teams are closing 94% of critical issues on time, which keeps our breach risk exposure window short.' The board wants to know: are we improving, are we compliant, and what is our residual risk?

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"
Common Mistake — Treating shift-left as a blocker, not a gate
Bad: Fail every CI build on any high-severity finding — developers bypass security checks or add exceptions for everything to keep shipping.
Good: Block only on verified, actionable findings with no exceptions. Low-signal findings (false positives, accepted risks) go to a dashboard, not a build gate. Build developer trust by fixing false positives quickly — a gate with 80% accuracy is worse than no gate.
Common Mistake — No authenticated scanning
Bad: Run unauthenticated Nessus scans on internal servers and report low finding counts as a sign of good security posture.
Good: Always use authenticated scans for internal assets. Unauthenticated scans miss 70-80% of vulnerabilities because they cannot read installed software versions or config files. Create a dedicated scanner service account with least-privilege read access.
Common Mistake — CVSS-only prioritisation
Bad: Sort findings by CVSS score descending and work top-down — treat a 9.8 on a dev laptop the same as a 9.8 on a payment processor.
Good: Combine CVSS with EPSS (exploitability probability), CISA KEV (confirmed exploitation), and asset criticality/exposure. A 7.2 in CISA KEV on a production server outranks a 9.8 with 0.001 EPSS on an isolated test environment.
Common Mistake — No verification step
Bad: Close tickets when owners report patching complete, without rescanning.
Good: Rescan affected assets within 48 hours of reported remediation. Track reopen rates — high reopen rates mean patching quality is poor or patches are being applied incorrectly. Never trust without verifying.
Common Mistake — Ignoring EOL systems
Bad: Accept that legacy EOL systems cannot be patched and stop scanning them — 'we know they are vulnerable.'
Good: EOL systems are often the most critical to track: they cannot receive patches, so risk acceptance must be formally documented, compensating controls must be applied (network isolation, enhanced monitoring), and migration timelines must be tracked. Never let EOL status be an excuse to stop monitoring.

Vulnerability Management Tools Landscape

Commercial VM Platforms

ToolCategoryBest ForNotes
Tenable.io / NessusScanner + VM platformEnterprise VM, compliance reportingMarket leader; Nessus Essentials free for 16 IPs
Qualys VMDRScanner + VM platformLarge enterprises, cloud-nativeStrong cloud integration, continuous monitoring
Rapid7 InsightVMScanner + VM platformRemediation workflow integrationGood Jira/ServiceNow integration, attacker context
Microsoft Defender for EndpointAgent-based VMWindows-heavy environmentsBuilt into Defender; no scanner deployment needed
Wiz / Orca SecurityCloud VM (CSPM)Cloud-native organisationsAgentless cloud scanning; excellent for AWS/Azure/GCP
Nucleus SecurityVM orchestrationAggregating multiple scanner sourcesNormalises Nessus + Qualys + Burp into one view
Dependency-TrackSCA / SBOM managementApplication component trackingOpen-source; integrates with Syft/Grype/CycloneDX
OpenVAS / GreenboneOpen-source scannerBudget-constrained; home labsFree; 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."
Pro Tip: Before your first board presentation on a new VM programme, make sure you can answer: "What is our most critical unpatched vulnerability right now, who owns it, and when will it be fixed?" If you cannot answer those three questions with confidence, the programme is not yet working.

🎯 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.
💡 Note
Up Next — Module 33: Incident Response
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.
Share

Discussion

0

Have a better approach? Found something outdated? Share it — your knowledge helps everyone learning here.

Continue with GitHub
Loading...