Lab 30: Vulnerability Triage & Virtual Patching¶
Chapter: 29 — Vulnerability Management | 53 — Zero-Day Response | 24 — Supply Chain Security Difficulty: ⭐⭐⭐⭐☆ Advanced Estimated Time: 4–5 hours Prerequisites: Chapter 29, Chapter 53, Chapter 24, vulnerability scanning fundamentals, web application firewall basics, CVSS scoring concepts
Overview¶
In this lab you will:
- Intake and classify 50 vulnerability scan results using combined CVSS base scores and EPSS exploitation probability — building a risk-prioritized remediation queue that accounts for both severity and real-world exploitability
- Calculate CVSS v4.0 Base and Environmental scores manually for five synthetic vulnerabilities — demonstrating mastery of the new v4.0 metric groups including Attack Requirements, Automatable, and Recovery
- Compare CVSS-only vs EPSS+CVSS prioritization strategies — identifying vulnerabilities where rankings diverge significantly and articulating the operational impact of each approach on patch scheduling
- Develop virtual patching rules using ModSecurity WAF rules, Snort/Suricata IPS signatures, and EDR detection rules for a synthetic zero-day vulnerability — providing immediate protection while awaiting vendor patches
- Design an emergency patch deployment strategy with canary groups, staged rollout percentages, rollback criteria, and verification queries — balancing speed of remediation against operational stability
Synthetic Data Only
All data in this lab is 100% synthetic and fictional. All IP addresses use RFC 5737 (192.0.2.x, 198.51.100.x, 203.0.113.x) or RFC 1918 (10.x, 172.16.x, 192.168.x) reserved ranges. All domains use *.example or *.example.com. All credentials are testuser/REDACTED. All CVE identifiers use the CVE-SYNTH- prefix and are entirely fictitious. This lab is for defensive education only — never use these techniques against systems you do not own or without explicit written authorization.
Scenario¶
Engagement Brief — Meridian Healthcare Systems
Organization: Meridian Healthcare Systems (fictional) Domain: meridian.example.com (SYNTHETIC) Vulnerability Scanner: scanner.meridian.example.com — 10.20.1.10 (SYNTHETIC) SIEM: siem.meridian.example.com — 10.20.1.20 (SYNTHETIC) WAF Cluster: waf.meridian.example.com — 192.0.2.50, 192.0.2.51 (SYNTHETIC) IPS Sensors: ips01.meridian.example.com — 10.20.0.5 (SYNTHETIC) Patch Management Server: wsus.meridian.example.com — 10.20.1.30 (SYNTHETIC) Patient Portal (Web App): portal.meridian.example.com — 198.51.100.10 (SYNTHETIC) EHR API Server: ehr-api.meridian.example.com — 10.20.10.50 (SYNTHETIC) Database Cluster: db01.meridian.example.com — 10.20.20.10 (SYNTHETIC) Database Cluster: db02.meridian.example.com — 10.20.20.11 (SYNTHETIC) EDR Console: edr.meridian.example.com — 10.20.1.40 (SYNTHETIC) Emergency Contact: soc@meridian.example.com (SYNTHETIC)
Summary: Meridian Healthcare Systems operates a hybrid environment with on-premises EHR systems and a cloud-hosted patient portal. A quarterly vulnerability scan has returned 50 findings across production systems, including a critical zero-day in the patient portal's authentication library. The CISO has declared an emergency response and tasked you — the senior vulnerability analyst — with triaging all findings, implementing virtual patches for immediate threats, and managing the emergency patch deployment once the vendor releases a fix.
Regulatory Context: HIPAA requires timely remediation of known vulnerabilities. Critical findings affecting systems with PHI (Protected Health Information) must have compensating controls within 48 hours or risk a reportable incident.
Certification Relevance¶
Certification Mapping
This lab maps to objectives in the following certifications:
| Certification | Relevant Domains |
|---|---|
| CompTIA Security+ (SY0-701) | Domain 1: General Security Concepts (12%), Domain 4: Security Operations (28%) |
| CompTIA CySA+ (CS0-003) | Domain 2: Vulnerability Management (22%), Domain 1: Security Operations (33%) |
| CompTIA CASP+ (CAS-004) | Domain 1: Security Architecture (29%), Domain 2: Security Operations (30%) |
| SC-200 (Microsoft Security Operations Analyst) | KQL Detection, Vulnerability Assessment, Threat Mitigation |
| CISSP | Domain 6: Security Assessment and Testing, Domain 7: Security Operations |
| CEH (Certified Ethical Hacker) | Module 5: Vulnerability Analysis, Module 18: IoT & OT Hacking |
| GIAC GEVA (Enterprise Vulnerability Assessor) | Vulnerability Scoring, Prioritization, Remediation Strategy |
Prerequisites¶
Required Tools¶
| Tool | Purpose | Version |
|---|---|---|
| Python 3 + pandas | Vulnerability data analysis and scoring | 3.10+ |
| ModSecurity / CRS | WAF rule development | 3.x / CRS 4.x |
| Snort or Suricata | IPS signature writing | 3.x / 7.x |
| curl / httpie | HTTP request testing | Latest |
| jq | JSON parsing | 1.7+ |
| PowerShell | Patch deployment scripting | 7.4+ |
| KQL environment (Azure Sentinel or demo) | Detection query development | N/A |
| Splunk (free tier or sandbox) | SPL detection query development | 9.x |
Required Knowledge¶
- Chapter 29: Vulnerability Management
- Chapter 53: Zero-Day Response
- Chapter 24: Supply Chain Security
- Chapter 5: Detection Engineering at Scale
- Lab 18: Threat Hunting with KQL & SPL
Lab Environment Setup¶
# Clone the lab environment repository
git clone https://github.com/nexus-secops/lab30-vuln-triage.example.git
cd lab30-vuln-triage
# Install Python dependencies
pip install pandas numpy tabulate jinja2
# Verify ModSecurity test harness
modsec-test --version 2>/dev/null || echo "ModSecurity optional — rule syntax exercises work without runtime"
# Verify Snort/Suricata test harness
snort --version 2>/dev/null || suricata --build-info 2>/dev/null || echo "IPS optional — signature syntax exercises work without runtime"
# Load synthetic vulnerability dataset
python load_vulns.py --dataset synthetic_50.json
Lab Environment Options
This lab can be completed using:
- Full lab environment — with ModSecurity, Snort/Suricata, and SIEM access for end-to-end testing
- Syntax-only mode — all WAF/IPS exercises include expected output so you can validate rule syntax without a running engine
- Paper-based mode — scoring worksheets and deployment templates can be completed as written exercises
Objectives¶
- Classify 50 vulnerabilities into Critical/High/Medium/Low categories using a combined CVSS+EPSS scoring methodology and produce a prioritized remediation queue
- Calculate CVSS v4.0 scores manually for five vulnerabilities, demonstrating understanding of Base, Threat, and Environmental metric groups
- Quantify the impact of EPSS on vulnerability prioritization by comparing CVSS-only rankings against EPSS+CVSS combined rankings and identifying the top 5 rank-change outliers
- Write virtual patching rules (WAF, IPS, EDR) for a synthetic zero-day vulnerability that block exploitation without disrupting legitimate application functionality
- Design a staged patch deployment with canary validation, progressive rollout, automated rollback triggers, and post-patch verification queries in both KQL and SPL
Phase 1: Vulnerability Discovery & Intake (45 minutes)¶
1.1 Understanding the Vulnerability Intake Pipeline¶
When a vulnerability scanner completes a quarterly scan, the raw output must be ingested, normalized, enriched, and prioritized before remediation can begin. This phase simulates the full intake pipeline.
┌─────────────────────────────────────────────────────────────────────┐
│ VULNERABILITY INTAKE PIPELINE │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ Scanner Output ──► Normalize ──► Enrich ──► Score ──► Prioritize │
│ │ │ │ │ │ │
│ Raw CVEs Deduplicate Add EPSS CVSS+EPSS Assign to │
│ CVSS Base Map to Add Asset Combined remediation │
│ Affected assets context risk score queues │
│ components Remove FP Add threat Rank order Set SLAs │
│ intel │
└─────────────────────────────────────────────────────────────────────┘
1.2 Synthetic Vulnerability Scan Results¶
Below are the 50 vulnerability findings from the quarterly scan. All CVE identifiers, CVSS scores, and EPSS probabilities are synthetic and fictional.
Vulnerability Dataset — Meridian Healthcare Systems Quarterly Scan¶
| # | CVE ID | CVSS 3.1 Base | EPSS (30-day) | Asset | Component | Description |
|---|---|---|---|---|---|---|
| 1 | CVE-SYNTH-2026-0042 | 9.8 | 0.971 | portal.meridian.example.com | AuthLib 2.4.1 | Authentication bypass via crafted JWT — unauthenticated RCE |
| 2 | CVE-SYNTH-2026-0108 | 9.1 | 0.892 | ehr-api.meridian.example.com | Spring Framework 5.3.18 | Remote code execution via SpEL injection |
| 3 | CVE-SYNTH-2026-0215 | 9.0 | 0.034 | db01.meridian.example.com | PostgreSQL 14.2 | Privilege escalation via crafted SQL function — requires auth |
| 4 | CVE-SYNTH-2026-0301 | 8.8 | 0.756 | portal.meridian.example.com | jQuery 3.5.1 | Stored XSS via DOM manipulation in patient messaging |
| 5 | CVE-SYNTH-2026-0044 | 8.6 | 0.912 | waf.meridian.example.com | OpenSSL 3.0.7 | Buffer overflow in TLS handshake — DoS or potential RCE |
| 6 | CVE-SYNTH-2026-0519 | 8.4 | 0.003 | db02.meridian.example.com | PostgreSQL 14.2 | Information disclosure via timing side-channel — requires local access |
| 7 | CVE-SYNTH-2026-0623 | 8.2 | 0.445 | ehr-api.meridian.example.com | Jackson Databind 2.13.1 | Deserialization RCE via polymorphic type handling |
| 8 | CVE-SYNTH-2026-0087 | 8.1 | 0.823 | portal.meridian.example.com | Apache Tomcat 9.0.56 | Request smuggling via malformed Transfer-Encoding |
| 9 | CVE-SYNTH-2026-0734 | 8.0 | 0.067 | wsus.meridian.example.com | WSUS Service 10.0.19041 | Privilege escalation via WSUS update interception — MITM required |
| 10 | CVE-SYNTH-2026-0156 | 7.8 | 0.534 | edr.meridian.example.com | EDR Agent 4.2.1 | Local privilege escalation via symlink race condition |
| 11 | CVE-SYNTH-2026-0845 | 7.5 | 0.891 | portal.meridian.example.com | Node.js 16.14.0 | Prototype pollution via recursive merge — DoS |
| 12 | CVE-SYNTH-2026-0267 | 7.5 | 0.012 | db01.meridian.example.com | pgAdmin 6.8 | CSRF in admin panel — requires authenticated session |
| 13 | CVE-SYNTH-2026-0390 | 7.4 | 0.678 | ehr-api.meridian.example.com | Log4j 2.17.0 | Information disclosure via crafted log pattern — limited impact |
| 14 | CVE-SYNTH-2026-0912 | 7.2 | 0.445 | portal.meridian.example.com | PHP 8.1.3 | Type confusion in filter_var — authentication bypass under specific config |
| 15 | CVE-SYNTH-2026-0478 | 7.1 | 0.023 | wsus.meridian.example.com | .NET Runtime 6.0.3 | Denial of service via crafted XML — requires local network access |
| 16 | CVE-SYNTH-2026-0553 | 7.0 | 0.834 | portal.meridian.example.com | Nginx 1.20.2 | HTTP/2 rapid reset DoS (variant) |
| 17 | CVE-SYNTH-2026-0661 | 7.0 | 0.002 | db02.meridian.example.com | OpenSSH 8.8p1 | Double-free in ssh-agent forwarding — requires agent forwarding enabled |
| 18 | CVE-SYNTH-2026-0189 | 6.8 | 0.567 | ehr-api.meridian.example.com | Bouncy Castle 1.70 | Weak key generation under specific entropy conditions |
| 19 | CVE-SYNTH-2026-0742 | 6.7 | 0.091 | edr.meridian.example.com | Windows Defender 4.18.2203 | FP bypass via DLL sideloading in trusted directory |
| 20 | CVE-SYNTH-2026-0334 | 6.5 | 0.445 | portal.meridian.example.com | Express.js 4.17.3 | Path traversal via URL-encoded double-dots in static file handler |
| 21 | CVE-SYNTH-2026-0856 | 6.5 | 0.823 | ehr-api.meridian.example.com | Apache Commons Text 1.9 | String interpolation injection — data exfiltration via error messages |
| 22 | CVE-SYNTH-2026-0123 | 6.4 | 0.034 | db01.meridian.example.com | Redis 6.2.6 | Lua sandbox escape — requires authenticated access to Redis CLI |
| 23 | CVE-SYNTH-2026-0967 | 6.3 | 0.156 | wsus.meridian.example.com | IIS 10.0 | HTTP response splitting via crafted header — limited exploitability |
| 24 | CVE-SYNTH-2026-0445 | 6.1 | 0.712 | portal.meridian.example.com | React 17.0.2 | Reflected XSS via dangerouslySetInnerHTML misuse in search results |
| 25 | CVE-SYNTH-2026-0578 | 6.1 | 0.003 | edr.meridian.example.com | .NET Framework 4.8 | XML external entity injection in configuration parser |
| 26 | CVE-SYNTH-2026-0201 | 6.0 | 0.289 | ehr-api.meridian.example.com | Hibernate ORM 5.6.7 | SQL injection via HQL parameter binding bypass |
| 27 | CVE-SYNTH-2026-0839 | 5.9 | 0.456 | portal.meridian.example.com | TLS 1.2 Config | POODLE variant — CBC cipher suite weakness |
| 28 | CVE-SYNTH-2026-0714 | 5.8 | 0.012 | db02.meridian.example.com | MySQL Connector/J 8.0.28 | SSRF via autoDeserialize connection property |
| 29 | CVE-SYNTH-2026-0356 | 5.5 | 0.678 | edr.meridian.example.com | Sysmon 14.0 | Log evasion via event ID truncation — attacker can suppress telemetry |
| 30 | CVE-SYNTH-2026-0492 | 5.4 | 0.034 | portal.meridian.example.com | Bootstrap 4.6.1 | DOM-based XSS in tooltip/popover via data attributes |
| 31 | CVE-SYNTH-2026-0618 | 5.3 | 0.567 | ehr-api.meridian.example.com | Guava 31.0.1 | Temporary file creation race condition — information disclosure |
| 32 | CVE-SYNTH-2026-0783 | 5.3 | 0.002 | wsus.meridian.example.com | PowerShell 7.2.1 | Command injection via crafted module manifest |
| 33 | CVE-SYNTH-2026-0145 | 5.0 | 0.345 | portal.meridian.example.com | Cookie Config | Secure flag missing on session cookie — MitM session hijack |
| 34 | CVE-SYNTH-2026-0901 | 5.0 | 0.001 | db01.meridian.example.com | pg_stat_statements | Information disclosure of query patterns — requires pg_monitor role |
| 35 | CVE-SYNTH-2026-0267b | 4.8 | 0.234 | ehr-api.meridian.example.com | Swagger UI 4.1.3 | Reflected XSS via crafted API spec URL |
| 36 | CVE-SYNTH-2026-0534 | 4.7 | 0.089 | edr.meridian.example.com | WinRM Service | Information disclosure via error response verbosity |
| 37 | CVE-SYNTH-2026-0678 | 4.6 | 0.012 | portal.meridian.example.com | CSP Config | Missing frame-ancestors directive — clickjacking potential |
| 38 | CVE-SYNTH-2026-0812 | 4.3 | 0.567 | ehr-api.meridian.example.com | Spring Security 5.6.2 | CSRF token fixation under specific session config |
| 39 | CVE-SYNTH-2026-0234 | 4.3 | 0.001 | db02.meridian.example.com | PostgreSQL 14.2 | Verbose error messages leak table schema — requires valid credentials |
| 40 | CVE-SYNTH-2026-0956 | 4.0 | 0.123 | wsus.meridian.example.com | WSUS Service 10.0.19041 | Information disclosure via unauthenticated metadata endpoint |
| 41 | CVE-SYNTH-2026-0389 | 3.7 | 0.456 | portal.meridian.example.com | HTTP Headers | Missing X-Content-Type-Options header — MIME sniffing |
| 42 | CVE-SYNTH-2026-0567 | 3.5 | 0.023 | edr.meridian.example.com | EDR Agent 4.2.1 | Excessive log verbosity exposes internal paths |
| 43 | CVE-SYNTH-2026-0723 | 3.3 | 0.189 | ehr-api.meridian.example.com | API Config | Rate limiting not enforced on /api/v1/auth endpoint |
| 44 | CVE-SYNTH-2026-0891 | 3.1 | 0.001 | db01.meridian.example.com | PostgreSQL 14.2 | Minor info leak via timing differences in auth response |
| 45 | CVE-SYNTH-2026-0134 | 2.7 | 0.045 | portal.meridian.example.com | TLS Config | TLS 1.0 enabled (deprecated) — compliance finding |
| 46 | CVE-SYNTH-2026-0456 | 2.4 | 0.001 | wsus.meridian.example.com | WSUS Service 10.0.19041 | Self-signed certificate on internal management interface |
| 47 | CVE-SYNTH-2026-0612 | 2.1 | 0.012 | edr.meridian.example.com | EDR Agent 4.2.1 | Unencrypted local IPC channel — requires local admin |
| 48 | CVE-SYNTH-2026-0789 | 1.9 | 0.001 | db02.meridian.example.com | PostgreSQL 14.2 | Minor memory leak under specific query pattern — DoS unlikely |
| 49 | CVE-SYNTH-2026-0345 | 1.6 | 0.001 | portal.meridian.example.com | HTTP Config | Server version disclosed in HTTP response header |
| 50 | CVE-SYNTH-2026-0501 | 1.2 | 0.001 | ehr-api.meridian.example.com | API Config | OPTIONS method responds with verbose Allow header |
1.3 Combined Risk Scoring Methodology¶
CVSS alone does not capture real-world exploitation likelihood. EPSS (Exploit Prediction Scoring System) provides a probability estimate that a vulnerability will be exploited in the wild within the next 30 days. Combining both yields a more operationally useful risk score.
Combined Risk Score Formula¶
Combined_Risk = (CVSS_Normalized * W_cvss) + (EPSS * W_epss) + Asset_Criticality_Modifier
Where:
CVSS_Normalized = CVSS_Base / 10.0 (normalize to 0–1 range)
W_cvss = 0.4 (severity weight)
W_epss = 0.4 (exploitation probability weight)
Asset_Criticality_Modifier:
PHI-bearing system = +0.20
Internet-facing = +0.15
Internal-only = +0.00
Development/staging = -0.05
Asset Criticality Classification¶
| Asset | Internet-Facing | Contains PHI | Criticality |
|---|---|---|---|
| portal.meridian.example.com | Yes | Yes | PHI + Internet (+0.35) |
| ehr-api.meridian.example.com | No (API gateway) | Yes | PHI (+0.20) |
| db01.meridian.example.com | No | Yes | PHI (+0.20) |
| db02.meridian.example.com | No | Yes | PHI (+0.20) |
| waf.meridian.example.com | Yes | No | Internet (+0.15) |
| wsus.meridian.example.com | No | No | Internal (+0.00) |
| edr.meridian.example.com | No | No | Internal (+0.00) |
1.4 Exercise: Calculate Combined Risk Scores¶
Task: For each of the 50 vulnerabilities, calculate the Combined Risk Score using the formula above. Then classify each into remediation tiers:
| Tier | Combined Risk Score | Remediation SLA |
|---|---|---|
| Critical | ≥ 0.80 | 24 hours (virtual patch immediately) |
| High | 0.60–0.79 | 7 days |
| Medium | 0.40–0.59 | 30 days |
| Low | < 0.40 | 90 days (next quarterly cycle) |
Python helper script (calculate all 50):
#!/usr/bin/env python3
"""
Lab 30 — Combined Risk Score Calculator
Meridian Healthcare Systems — Vulnerability Triage
ALL DATA IS SYNTHETIC
"""
import pandas as pd
# Vulnerability dataset (synthetic)
vulns = [
{"id": 1, "cve": "CVE-SYNTH-2026-0042", "cvss": 9.8, "epss": 0.971, "asset": "portal.meridian.example.com", "modifier": 0.35},
{"id": 2, "cve": "CVE-SYNTH-2026-0108", "cvss": 9.1, "epss": 0.892, "asset": "ehr-api.meridian.example.com", "modifier": 0.20},
{"id": 3, "cve": "CVE-SYNTH-2026-0215", "cvss": 9.0, "epss": 0.034, "asset": "db01.meridian.example.com", "modifier": 0.20},
{"id": 4, "cve": "CVE-SYNTH-2026-0301", "cvss": 8.8, "epss": 0.756, "asset": "portal.meridian.example.com", "modifier": 0.35},
{"id": 5, "cve": "CVE-SYNTH-2026-0044", "cvss": 8.6, "epss": 0.912, "asset": "waf.meridian.example.com", "modifier": 0.15},
{"id": 6, "cve": "CVE-SYNTH-2026-0519", "cvss": 8.4, "epss": 0.003, "asset": "db02.meridian.example.com", "modifier": 0.20},
{"id": 7, "cve": "CVE-SYNTH-2026-0623", "cvss": 8.2, "epss": 0.445, "asset": "ehr-api.meridian.example.com", "modifier": 0.20},
{"id": 8, "cve": "CVE-SYNTH-2026-0087", "cvss": 8.1, "epss": 0.823, "asset": "portal.meridian.example.com", "modifier": 0.35},
{"id": 9, "cve": "CVE-SYNTH-2026-0734", "cvss": 8.0, "epss": 0.067, "asset": "wsus.meridian.example.com", "modifier": 0.00},
{"id": 10, "cve": "CVE-SYNTH-2026-0156", "cvss": 7.8, "epss": 0.534, "asset": "edr.meridian.example.com", "modifier": 0.00},
{"id": 11, "cve": "CVE-SYNTH-2026-0845", "cvss": 7.5, "epss": 0.891, "asset": "portal.meridian.example.com", "modifier": 0.35},
{"id": 12, "cve": "CVE-SYNTH-2026-0267", "cvss": 7.5, "epss": 0.012, "asset": "db01.meridian.example.com", "modifier": 0.20},
{"id": 13, "cve": "CVE-SYNTH-2026-0390", "cvss": 7.4, "epss": 0.678, "asset": "ehr-api.meridian.example.com", "modifier": 0.20},
{"id": 14, "cve": "CVE-SYNTH-2026-0912", "cvss": 7.2, "epss": 0.445, "asset": "portal.meridian.example.com", "modifier": 0.35},
{"id": 15, "cve": "CVE-SYNTH-2026-0478", "cvss": 7.1, "epss": 0.023, "asset": "wsus.meridian.example.com", "modifier": 0.00},
{"id": 16, "cve": "CVE-SYNTH-2026-0553", "cvss": 7.0, "epss": 0.834, "asset": "portal.meridian.example.com", "modifier": 0.35},
{"id": 17, "cve": "CVE-SYNTH-2026-0661", "cvss": 7.0, "epss": 0.002, "asset": "db02.meridian.example.com", "modifier": 0.20},
{"id": 18, "cve": "CVE-SYNTH-2026-0189", "cvss": 6.8, "epss": 0.567, "asset": "ehr-api.meridian.example.com", "modifier": 0.20},
{"id": 19, "cve": "CVE-SYNTH-2026-0742", "cvss": 6.7, "epss": 0.091, "asset": "edr.meridian.example.com", "modifier": 0.00},
{"id": 20, "cve": "CVE-SYNTH-2026-0334", "cvss": 6.5, "epss": 0.445, "asset": "portal.meridian.example.com", "modifier": 0.35},
{"id": 21, "cve": "CVE-SYNTH-2026-0856", "cvss": 6.5, "epss": 0.823, "asset": "ehr-api.meridian.example.com", "modifier": 0.20},
{"id": 22, "cve": "CVE-SYNTH-2026-0123", "cvss": 6.4, "epss": 0.034, "asset": "db01.meridian.example.com", "modifier": 0.20},
{"id": 23, "cve": "CVE-SYNTH-2026-0967", "cvss": 6.3, "epss": 0.156, "asset": "wsus.meridian.example.com", "modifier": 0.00},
{"id": 24, "cve": "CVE-SYNTH-2026-0445", "cvss": 6.1, "epss": 0.712, "asset": "portal.meridian.example.com", "modifier": 0.35},
{"id": 25, "cve": "CVE-SYNTH-2026-0578", "cvss": 6.1, "epss": 0.003, "asset": "edr.meridian.example.com", "modifier": 0.00},
{"id": 26, "cve": "CVE-SYNTH-2026-0201", "cvss": 6.0, "epss": 0.289, "asset": "ehr-api.meridian.example.com", "modifier": 0.20},
{"id": 27, "cve": "CVE-SYNTH-2026-0839", "cvss": 5.9, "epss": 0.456, "asset": "portal.meridian.example.com", "modifier": 0.35},
{"id": 28, "cve": "CVE-SYNTH-2026-0714", "cvss": 5.8, "epss": 0.012, "asset": "db02.meridian.example.com", "modifier": 0.20},
{"id": 29, "cve": "CVE-SYNTH-2026-0356", "cvss": 5.5, "epss": 0.678, "asset": "edr.meridian.example.com", "modifier": 0.00},
{"id": 30, "cve": "CVE-SYNTH-2026-0492", "cvss": 5.4, "epss": 0.034, "asset": "portal.meridian.example.com", "modifier": 0.35},
{"id": 31, "cve": "CVE-SYNTH-2026-0618", "cvss": 5.3, "epss": 0.567, "asset": "ehr-api.meridian.example.com", "modifier": 0.20},
{"id": 32, "cve": "CVE-SYNTH-2026-0783", "cvss": 5.3, "epss": 0.002, "asset": "wsus.meridian.example.com", "modifier": 0.00},
{"id": 33, "cve": "CVE-SYNTH-2026-0145", "cvss": 5.0, "epss": 0.345, "asset": "portal.meridian.example.com", "modifier": 0.35},
{"id": 34, "cve": "CVE-SYNTH-2026-0901", "cvss": 5.0, "epss": 0.001, "asset": "db01.meridian.example.com", "modifier": 0.20},
{"id": 35, "cve": "CVE-SYNTH-2026-0267b", "cvss": 4.8, "epss": 0.234, "asset": "ehr-api.meridian.example.com", "modifier": 0.20},
{"id": 36, "cve": "CVE-SYNTH-2026-0534", "cvss": 4.7, "epss": 0.089, "asset": "edr.meridian.example.com", "modifier": 0.00},
{"id": 37, "cve": "CVE-SYNTH-2026-0678", "cvss": 4.6, "epss": 0.012, "asset": "portal.meridian.example.com", "modifier": 0.35},
{"id": 38, "cve": "CVE-SYNTH-2026-0812", "cvss": 4.3, "epss": 0.567, "asset": "ehr-api.meridian.example.com", "modifier": 0.20},
{"id": 39, "cve": "CVE-SYNTH-2026-0234", "cvss": 4.3, "epss": 0.001, "asset": "db02.meridian.example.com", "modifier": 0.20},
{"id": 40, "cve": "CVE-SYNTH-2026-0956", "cvss": 4.0, "epss": 0.123, "asset": "wsus.meridian.example.com", "modifier": 0.00},
{"id": 41, "cve": "CVE-SYNTH-2026-0389", "cvss": 3.7, "epss": 0.456, "asset": "portal.meridian.example.com", "modifier": 0.35},
{"id": 42, "cve": "CVE-SYNTH-2026-0567", "cvss": 3.5, "epss": 0.023, "asset": "edr.meridian.example.com", "modifier": 0.00},
{"id": 43, "cve": "CVE-SYNTH-2026-0723", "cvss": 3.3, "epss": 0.189, "asset": "ehr-api.meridian.example.com", "modifier": 0.20},
{"id": 44, "cve": "CVE-SYNTH-2026-0891", "cvss": 3.1, "epss": 0.001, "asset": "db01.meridian.example.com", "modifier": 0.20},
{"id": 45, "cve": "CVE-SYNTH-2026-0134", "cvss": 2.7, "epss": 0.045, "asset": "portal.meridian.example.com", "modifier": 0.35},
{"id": 46, "cve": "CVE-SYNTH-2026-0456", "cvss": 2.4, "epss": 0.001, "asset": "wsus.meridian.example.com", "modifier": 0.00},
{"id": 47, "cve": "CVE-SYNTH-2026-0612", "cvss": 2.1, "epss": 0.012, "asset": "edr.meridian.example.com", "modifier": 0.00},
{"id": 48, "cve": "CVE-SYNTH-2026-0789", "cvss": 1.9, "epss": 0.001, "asset": "db02.meridian.example.com", "modifier": 0.20},
{"id": 49, "cve": "CVE-SYNTH-2026-0345", "cvss": 1.6, "epss": 0.001, "asset": "portal.meridian.example.com", "modifier": 0.35},
{"id": 50, "cve": "CVE-SYNTH-2026-0501", "cvss": 1.2, "epss": 0.001, "asset": "ehr-api.meridian.example.com", "modifier": 0.20},
]
# Calculate combined risk scores
df = pd.DataFrame(vulns)
df["cvss_norm"] = df["cvss"] / 10.0
df["combined_risk"] = (df["cvss_norm"] * 0.4) + (df["epss"] * 0.4) + df["modifier"]
# Classify into tiers
def classify_tier(score):
if score >= 0.80:
return "Critical"
elif score >= 0.60:
return "High"
elif score >= 0.40:
return "Medium"
else:
return "Low"
df["tier"] = df["combined_risk"].apply(classify_tier)
# Sort by combined risk descending
df_sorted = df.sort_values("combined_risk", ascending=False)
# Display results
print("=" * 90)
print("MERIDIAN HEALTHCARE SYSTEMS — VULNERABILITY TRIAGE REPORT")
print("=" * 90)
print(f"\n{'#':<4} {'CVE':<24} {'CVSS':<6} {'EPSS':<7} {'Combined':<10} {'Tier':<10} {'Asset'}")
print("-" * 90)
for _, row in df_sorted.iterrows():
print(f"{row['id']:<4} {row['cve']:<24} {row['cvss']:<6.1f} {row['epss']:<7.3f} "
f"{row['combined_risk']:<10.3f} {row['tier']:<10} {row['asset']}")
# Summary
print(f"\n{'=' * 90}")
print("TIER SUMMARY")
print(f"{'=' * 90}")
for tier in ["Critical", "High", "Medium", "Low"]:
count = len(df[df["tier"] == tier])
print(f" {tier:<10}: {count:>3} vulnerabilities")
print(f" {'Total':<10}: {len(df):>3} vulnerabilities")
1.5 Deliverables — Phase 1¶
Phase 1 Deliverables
- [ ] Completed combined risk score calculation for all 50 vulnerabilities
- [ ] Tier classification (Critical/High/Medium/Low) for each vulnerability
- [ ] Sorted remediation queue — highest combined risk first
- [ ] Written justification for at least 3 vulnerabilities where you disagree with the automated classification (e.g., a High CVSS that you would downgrade due to asset context, or a Medium you would upgrade due to threat intelligence)
- [ ] Identification of the top 5 vulnerabilities requiring immediate action
Phase 2: CVSS v4.0 Scoring Exercise (45 minutes)¶
2.1 CVSS v4.0 Overview¶
CVSS v4.0 introduced significant changes from v3.1, including new metric groups and refined definitions. Understanding these changes is essential for accurate manual scoring.
┌─────────────────────────────────────────────────────────────────────┐
│ CVSS v4.0 METRIC GROUPS │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ BASE METRICS (Exploitability + Impact) │
│ ├── Attack Vector (AV): Network/Adjacent/Local/Physical │
│ ├── Attack Complexity (AC): Low/High │
│ ├── Attack Requirements (AT): None/Present [NEW in v4.0] │
│ ├── Privileges Required (PR): None/Low/High │
│ ├── User Interaction (UI): None/Passive/Active [refined v4.0] │
│ ├── Vulnerable System Impact (VC/VI/VA): None/Low/High │
│ └── Subsequent System Impact (SC/SI/SA): None/Low/High [NEW] │
│ │
│ THREAT METRICS │
│ └── Exploit Maturity (E): Unreported/PoC/Attacked [replaces RL] │
│ │
│ ENVIRONMENTAL METRICS │
│ ├── Modified Base Metrics (MAV, MAC, MAT, MPR, MUI, etc.) │
│ ├── Confidentiality/Integrity/Availability Requirements │
│ └── (CR/IR/AR): Low/Medium/High │
│ │
│ SUPPLEMENTAL METRICS [NEW — informational only, no score impact] │
│ ├── Safety (S): Negligible/Present │
│ ├── Automatable (AU): No/Yes │
│ ├── Recovery (R): Automatic/User/Irrecoverable │
│ ├── Value Density (V): Diffuse/Concentrated │
│ ├── Vulnerability Response Effort (RE): Low/Moderate/High │
│ └── Provider Urgency (U): Clear/Green/Amber/Red │
└─────────────────────────────────────────────────────────────────────┘
2.2 Vulnerability Descriptions for Manual Scoring¶
Score each of the following five synthetic vulnerabilities using CVSS v4.0. For each, provide the full vector string and calculated score.
Vulnerability A: CVE-SYNTH-2026-0042 — Authentication Bypass via Crafted JWT¶
Description: The AuthLib library version 2.4.1 used in the Meridian patient portal (portal.meridian.example.com) contains a critical flaw in JWT signature verification. When an RS256-signed JWT is presented with the algorithm header changed to "none", the library accepts the token without verifying the signature. An unauthenticated attacker can craft a JWT with arbitrary claims (including admin role) and send it to any authenticated endpoint. No user interaction is required. The vulnerable component is the authentication gateway, and successful exploitation grants full access to the patient portal and all patient health records accessible through it. The vulnerability is being actively exploited in the wild. The patient portal is internet-facing and processes PHI.
Scoring Worksheet A:
CVSS v4.0 Base Metrics:
Attack Vector (AV): ___ (Network / Adjacent / Local / Physical)
Attack Complexity (AC): ___ (Low / High)
Attack Requirements (AT): ___ (None / Present)
Privileges Required (PR): ___ (None / Low / High)
User Interaction (UI): ___ (None / Passive / Active)
Vulnerable System Impact:
Confidentiality (VC): ___ (None / Low / High)
Integrity (VI): ___ (None / Low / High)
Availability (VA): ___ (None / Low / High)
Subsequent System Impact:
Confidentiality (SC): ___ (None / Low / High)
Integrity (SI): ___ (None / Low / High)
Availability (SA): ___ (None / Low / High)
Threat Metrics:
Exploit Maturity (E): ___ (Unreported / PoC / Attacked)
Environmental Metrics:
Confidentiality Req (CR): ___ (Low / Medium / High)
Integrity Req (IR): ___ (Low / Medium / High)
Availability Req (AR): ___ (Low / Medium / High)
Supplemental Metrics:
Safety (S): ___ (Negligible / Present)
Automatable (AU): ___ (No / Yes)
Recovery (R): ___ (Automatic / User / Irrecoverable)
Value Density (V): ___ (Diffuse / Concentrated)
CVSS v4.0 Vector String: CVSS:4.0/AV:___/AC:___/AT:___/PR:___/UI:___/VC:___/VI:___/VA:___/SC:___/SI:___/SA:___
Base Score: ___
Base + Threat Score: ___
Base + Threat + Environmental Score (Overall): ___
Vulnerability B: CVE-SYNTH-2026-0623 — Deserialization RCE via Polymorphic Type Handling¶
Description: Jackson Databind version 2.13.1 in the EHR API server (ehr-api.meridian.example.com) enables default typing, allowing polymorphic deserialization of untrusted input. An attacker with a valid API key (Low privileges) can send a crafted JSON payload containing a malicious gadget chain that achieves remote code execution on the API server. The attack requires the presence of specific gadget libraries on the classpath (Attack Requirements: Present). No user interaction is needed. Successful exploitation gives full control of the EHR API server, which has direct access to the database tier containing patient records. A proof-of-concept exploit exists in public repositories but active exploitation has not been confirmed.
Scoring Worksheet B:
CVSS v4.0 Base Metrics:
Attack Vector (AV): ___
Attack Complexity (AC): ___
Attack Requirements (AT): ___
Privileges Required (PR): ___
User Interaction (UI): ___
Vulnerable System Impact:
Confidentiality (VC): ___
Integrity (VI): ___
Availability (VA): ___
Subsequent System Impact:
Confidentiality (SC): ___
Integrity (SI): ___
Availability (SA): ___
Threat Metrics:
Exploit Maturity (E): ___
Environmental Metrics:
Confidentiality Req (CR): ___
Integrity Req (IR): ___
Availability Req (AR): ___
CVSS v4.0 Vector String: CVSS:4.0/AV:___/AC:___/AT:___/PR:___/UI:___/VC:___/VI:___/VA:___/SC:___/SI:___/SA:___
Base Score: ___
Base + Threat Score: ___
Base + Threat + Environmental Score (Overall): ___
Vulnerability C: CVE-SYNTH-2026-0156 — Local Privilege Escalation via Symlink Race Condition¶
Description: The EDR agent version 4.2.1 on endpoint edr.meridian.example.com contains a time-of-check-time-of-use (TOCTOU) vulnerability in its update mechanism. A local user with low-level access can create a symbolic link from the EDR agent's temporary update directory to a system directory. During the update process, the agent writes files with SYSTEM privileges to the symlink target. Exploitation requires precise timing (Attack Complexity: High) and the update process must be triggered (Attack Requirements: Present). Successful exploitation grants SYSTEM-level access on the local endpoint. No other systems are directly impacted. No public exploit is known.
Scoring Worksheet C:
CVSS v4.0 Base Metrics:
Attack Vector (AV): ___
Attack Complexity (AC): ___
Attack Requirements (AT): ___
Privileges Required (PR): ___
User Interaction (UI): ___
Vulnerable System Impact:
Confidentiality (VC): ___
Integrity (VI): ___
Availability (VA): ___
Subsequent System Impact:
Confidentiality (SC): ___
Integrity (SI): ___
Availability (SA): ___
Threat Metrics:
Exploit Maturity (E): ___
Environmental Metrics:
Confidentiality Req (CR): ___
Integrity Req (IR): ___
Availability Req (AR): ___
CVSS v4.0 Vector String: CVSS:4.0/AV:___/AC:___/AT:___/PR:___/UI:___/VC:___/VI:___/VA:___/SC:___/SI:___/SA:___
Base Score: ___
Base + Threat Score: ___
Base + Threat + Environmental Score (Overall): ___
Vulnerability D: CVE-SYNTH-2026-0445 — Reflected XSS via dangerouslySetInnerHTML¶
Description: The Meridian patient portal (portal.meridian.example.com) uses React 17.0.2 with dangerouslySetInnerHTML in the search results component. User-supplied search terms are reflected into the page without proper sanitization, enabling reflected cross-site scripting. The attack requires a user to click a malicious link (User Interaction: Active). Successful exploitation allows session hijacking and PHI exfiltration from the victim's browser session. The vulnerable system itself has low confidentiality and integrity impact (client-side only), but the subsequent system impact is high because stolen session tokens can access PHI through the portal API. Active exploitation has been observed in phishing campaigns.
Scoring Worksheet D:
CVSS v4.0 Base Metrics:
Attack Vector (AV): ___
Attack Complexity (AC): ___
Attack Requirements (AT): ___
Privileges Required (PR): ___
User Interaction (UI): ___
Vulnerable System Impact:
Confidentiality (VC): ___
Integrity (VI): ___
Availability (VA): ___
Subsequent System Impact:
Confidentiality (SC): ___
Integrity (SI): ___
Availability (SA): ___
Threat Metrics:
Exploit Maturity (E): ___
Environmental Metrics:
Confidentiality Req (CR): ___
Integrity Req (IR): ___
Availability Req (AR): ___
CVSS v4.0 Vector String: CVSS:4.0/AV:___/AC:___/AT:___/PR:___/UI:___/VC:___/VI:___/VA:___/SC:___/SI:___/SA:___
Base Score: ___
Base + Threat Score: ___
Base + Threat + Environmental Score (Overall): ___
Vulnerability E: CVE-SYNTH-2026-0356 — Log Evasion via Event ID Truncation¶
Description: Sysmon version 14.0 on the EDR console (edr.meridian.example.com) contains a flaw where event IDs exceeding a certain length are silently truncated, causing events to be misclassified or dropped. An attacker with local access and low privileges on any monitored endpoint can craft process creation commands that exploit this truncation to evade Sysmon logging. The attack is low complexity and requires no special conditions. The direct impact to the vulnerable system is low — only integrity is affected (log tampering). However, subsequent systems (the entire SIEM monitoring pipeline) lose visibility, creating a high subsequent integrity impact. No public exploit exists, but the technique is straightforward.
Scoring Worksheet E:
CVSS v4.0 Base Metrics:
Attack Vector (AV): ___
Attack Complexity (AC): ___
Attack Requirements (AT): ___
Privileges Required (PR): ___
User Interaction (UI): ___
Vulnerable System Impact:
Confidentiality (VC): ___
Integrity (VI): ___
Availability (VA): ___
Subsequent System Impact:
Confidentiality (SC): ___
Integrity (SI): ___
Availability (SA): ___
Threat Metrics:
Exploit Maturity (E): ___
Environmental Metrics:
Confidentiality Req (CR): ___
Integrity Req (IR): ___
Availability Req (AR): ___
CVSS v4.0 Vector String: CVSS:4.0/AV:___/AC:___/AT:___/PR:___/UI:___/VC:___/VI:___/VA:___/SC:___/SI:___/SA:___
Base Score: ___
Base + Threat Score: ___
Base + Threat + Environmental Score (Overall): ___
2.3 Deliverables — Phase 2¶
Phase 2 Deliverables
- [ ] Completed CVSS v4.0 scoring worksheets for all 5 vulnerabilities
- [ ] Full vector strings with all applicable metric groups
- [ ] Written explanation for each metric choice (minimum 1 sentence per metric)
- [ ] Comparison: How do your v4.0 scores compare to the v3.1 scores in the scan results? Identify any significant differences and explain why v4.0 produces a different score.
Phase 3: EPSS-Based Prioritization (30 minutes)¶
3.1 EPSS Fundamentals¶
The Exploit Prediction Scoring System (EPSS) uses machine learning to estimate the probability that a vulnerability will be exploited in the wild within the next 30 days. Unlike CVSS (which measures severity), EPSS measures likelihood of exploitation.
Key properties:
- Range: 0.0 (0%) to 1.0 (100%) probability
- Percentile: Relative ranking compared to all scored CVEs
- Updated daily — scores change as threat landscape evolves
- Based on: vulnerability age, CVSS metrics, public exploit availability, mentions on social media/dark web, vendor, CWE type, and more
3.2 Exercise: CVSS-Only vs EPSS+CVSS Ranking Comparison¶
Task: Create two ranked lists of the 50 vulnerabilities and compare them.
Ranking Method 1 — CVSS Only: Sort all 50 vulnerabilities by CVSS 3.1 Base Score (descending). Break ties by CVE ID.
Ranking Method 2 — EPSS+CVSS Combined: Use the Combined Risk Score from Phase 1 (which incorporates EPSS, CVSS, and asset criticality).
Python comparison script:
#!/usr/bin/env python3
"""
Lab 30 — CVSS vs EPSS+CVSS Ranking Comparison
ALL DATA IS SYNTHETIC
"""
import pandas as pd
# (Reuse vulns list from Phase 1)
# ... assume vulns list is loaded ...
df = pd.DataFrame(vulns)
df["cvss_norm"] = df["cvss"] / 10.0
df["combined_risk"] = (df["cvss_norm"] * 0.4) + (df["epss"] * 0.4) + df["modifier"]
# CVSS-only ranking
df["rank_cvss"] = df["cvss"].rank(ascending=False, method="min").astype(int)
# Combined risk ranking
df["rank_combined"] = df["combined_risk"].rank(ascending=False, method="min").astype(int)
# Calculate rank change
df["rank_change"] = df["rank_cvss"] - df["rank_combined"]
# Find biggest movers
biggest_movers = df.reindex(df["rank_change"].abs().sort_values(ascending=False).index).head(10)
print("=" * 100)
print("TOP 10 RANK-CHANGE OUTLIERS (CVSS-only rank vs EPSS+CVSS combined rank)")
print("=" * 100)
print(f"\n{'CVE':<24} {'CVSS':<6} {'EPSS':<7} {'Combined':<10} {'CVSS Rank':<11} {'Combined Rank':<15} {'Change'}")
print("-" * 100)
for _, row in biggest_movers.iterrows():
direction = "UP" if row["rank_change"] > 0 else "DOWN"
print(f"{row['cve']:<24} {row['cvss']:<6.1f} {row['epss']:<7.3f} "
f"{row['combined_risk']:<10.3f} {row['rank_cvss']:<11} {row['rank_combined']:<15} "
f"{'+' if row['rank_change'] > 0 else ''}{int(row['rank_change'])} ({direction})")
print("\n" + "=" * 100)
print("ANALYSIS QUESTIONS")
print("=" * 100)
print("""
1. Which vulnerabilities moved UP significantly in priority when EPSS was included?
→ These are lower-CVSS vulns that are actively being exploited in the wild.
→ They represent the biggest blind spot in CVSS-only approaches.
2. Which vulnerabilities moved DOWN significantly?
→ These are high-CVSS vulns with very low exploitation probability.
→ They are theoretically severe but practically unlikely to be exploited.
3. What operational impact does this have on your patch schedule?
→ Consider: developer time, change windows, risk tolerance.
""")
3.3 Key Outlier Analysis¶
Identify and analyze the following specific outlier patterns:
Pattern 1: High CVSS, Low EPSS (Over-prioritized by CVSS alone)¶
| CVE | CVSS | EPSS | CVSS Rank | Combined Rank | Analysis |
|---|---|---|---|---|---|
| CVE-SYNTH-2026-0215 | 9.0 | 0.034 | 3 | ? | PostgreSQL priv-esc requires auth — low real-world exploitation |
| CVE-SYNTH-2026-0519 | 8.4 | 0.003 | 6 | ? | Timing side-channel requires local access — extremely hard to exploit |
| CVE-SYNTH-2026-0734 | 8.0 | 0.067 | 9 | ? | WSUS interception requires MITM position — high barrier |
| CVE-SYNTH-2026-0661 | 7.0 | 0.002 | 16 | ? | OpenSSH double-free requires agent forwarding — rare config |
Exercise Question: For each of these, would you override the automated ranking? Under what circumstances would a high-CVSS, low-EPSS vulnerability still warrant emergency treatment?
Pattern 2: Lower CVSS, High EPSS (Under-prioritized by CVSS alone)¶
| CVE | CVSS | EPSS | CVSS Rank | Combined Rank | Analysis |
|---|---|---|---|---|---|
| CVE-SYNTH-2026-0845 | 7.5 | 0.891 | 11 | ? | Node.js prototype pollution — trivial to exploit, widely targeted |
| CVE-SYNTH-2026-0553 | 7.0 | 0.834 | 16 | ? | Nginx HTTP/2 rapid reset — mass scanning observed |
| CVE-SYNTH-2026-0856 | 6.5 | 0.823 | 20 | ? | Commons Text interpolation — active campaign targeting Java apps |
| CVE-SYNTH-2026-0356 | 5.5 | 0.678 | 29 | ? | Sysmon log evasion — actively used by APT groups |
Exercise Question: How would you explain to a CISO why a CVSS 5.5 vulnerability should be patched before a CVSS 9.0 vulnerability?
3.4 Deliverables — Phase 3¶
Phase 3 Deliverables
- [ ] Complete dual-ranked list (CVSS-only and EPSS+CVSS combined) for all 50 vulnerabilities
- [ ] Top 5 rank-change outliers identified and analyzed (both UP and DOWN movers)
- [ ] Written one-paragraph executive summary explaining why EPSS+CVSS produces better outcomes than CVSS alone
- [ ] Decision matrix: Under what specific conditions would you override EPSS-based prioritization? (List at least 3 conditions)
Phase 4: Virtual Patching (60 minutes)¶
4.1 Zero-Day Scenario: CVE-SYNTH-2026-0042¶
ZERO-DAY ALERT — CVE-SYNTH-2026-0042
Vulnerability: Authentication bypass via crafted JWT in AuthLib 2.4.1 Affected System: portal.meridian.example.com — 198.51.100.10 (SYNTHETIC) CVSS 3.1: 9.8 (Critical) | EPSS: 0.971 | Combined Risk: 1.19 (Critical) Vendor Patch: NOT AVAILABLE — zero-day Active Exploitation: Confirmed — threat intel reports active campaigns HIPAA Impact: PHI system — compensating controls required within 48 hours Status: Virtual patching is the ONLY option until vendor releases a fix
Exploitation Details (Synthetic — Educational Only)¶
Vulnerable Code Path:
POST /api/v1/auth/token HTTP/1.1
Host: portal.meridian.example.com
Content-Type: application/json
{
"token": "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJzdWIiOiJhZG1pbiIsInJvbGUiOiJzdXBlcmFkbWluIiwiaWF0IjoxNzEzNTIwMDAwfQ."
}
Decoded JWT Header:
Decoded JWT Payload:
Attack Pattern:
- Attacker crafts JWT with
"alg": "none"— bypasses signature verification - Attacker sets arbitrary claims (
role: superadmin) - Token is sent to any authenticated API endpoint
- AuthLib accepts the token without verifying the (absent) signature
- Attacker gains full administrative access to the patient portal
Indicators of Compromise (Synthetic):
- JWT tokens with
"alg": "none"or"alg": "None"or"alg": "NONE"in the header - JWT tokens with empty or missing signature segment (trailing dot with no data)
- Unusual admin-level API calls from external IP addresses
- Access to PHI endpoints from accounts that don't normally access them
- HTTP requests with
Authorization: Bearer eyJhbGciOiJub25lI...where the base64-decoded header contains algorithm "none"
4.2 Exercise: WAF Rules (ModSecurity)¶
Write ModSecurity rules to block exploitation of CVE-SYNTH-2026-0042. Your rules must:
- Detect and block JWTs with
alg: none(case-insensitive) - Detect and block JWTs with missing or empty signature segments
- Log blocked attempts with sufficient detail for forensic analysis
- NOT block legitimate RS256-signed JWTs
Template — ModSecurity Rules:
# ============================================================
# Virtual Patch: CVE-SYNTH-2026-0042
# AuthLib JWT Algorithm None Authentication Bypass
# Meridian Healthcare Systems — portal.meridian.example.com
# ALL DATA IS SYNTHETIC — EDUCATIONAL ONLY
#
# Deploy to: /etc/modsecurity/rules/virtual-patches/
# Effective: Immediately upon deployment
# Expiry: Remove after vendor patch applied and verified
# ============================================================
# Rule 1: Block JWT with "alg":"none" in Authorization header
# The JWT header is base64url-encoded. "alg":"none" variants encode to:
# eyJhbGciOiJub25lIi (alg: none)
# eyJhbGciOiJOb25lIi (alg: None)
# eyJhbGciOiJOT05FIi (alg: NONE)
# eyJhbGciOiJuT25FIi (alg: nOnE) — and other case variants
SecRule REQUEST_HEADERS:Authorization "@rx (?i)bearer\s+eyJhbGciOi(?:Jub25lIi|JOb25lIi|JOT05FIi|[A-Za-z0-9+/=]*bm9uZ[A-Za-z0-9+/=]*)" \
"id:930001,\
phase:1,\
deny,\
status:403,\
log,\
msg:'CVE-SYNTH-2026-0042: JWT alg:none detected in Authorization header',\
tag:'virtual-patch/CVE-SYNTH-2026-0042',\
tag:'attack-authentication',\
tag:'OWASP_CRS/WEB_ATTACK/JWT_BYPASS',\
severity:'CRITICAL',\
logdata:'Matched Data: %{MATCHED_VAR} found within %{MATCHED_VAR_NAME}'"
# Rule 2: Block JWT with missing signature segment in Authorization header
# Valid JWT: header.payload.signature (3 segments separated by dots)
# Attack JWT: header.payload. (empty signature) or header.payload (no third segment)
SecRule REQUEST_HEADERS:Authorization "@rx (?i)bearer\s+[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.?\s*$" \
"id:930002,\
phase:1,\
deny,\
status:403,\
log,\
msg:'CVE-SYNTH-2026-0042: JWT with empty/missing signature detected',\
tag:'virtual-patch/CVE-SYNTH-2026-0042',\
tag:'attack-authentication',\
severity:'CRITICAL',\
chain"
SecRule REQUEST_HEADERS:Authorization "!@rx \.[A-Za-z0-9_-]{10,}\s*$" \
"logdata:'Matched Data: JWT signature segment missing or too short'"
# Rule 3: Block JWT alg:none in request body (for POST /api/v1/auth/token)
# Some implementations accept the token in the request body
SecRule REQUEST_BODY "@rx (?i)eyJhbGciOi(?:Jub25lIi|JOb25lIi|JOT05FIi)" \
"id:930003,\
phase:2,\
deny,\
status:403,\
log,\
msg:'CVE-SYNTH-2026-0042: JWT alg:none detected in request body',\
tag:'virtual-patch/CVE-SYNTH-2026-0042',\
tag:'attack-authentication',\
severity:'CRITICAL',\
logdata:'Matched Data: %{MATCHED_VAR} found within request body'"
# Rule 4: Rate-limit authentication endpoints to slow brute-force JWT fuzzing
# Allow max 10 auth requests per minute per IP
SecRule REQUEST_URI "@rx ^/api/v1/auth/" \
"id:930004,\
phase:1,\
pass,\
nolog,\
setvar:'ip.auth_counter=+1',\
expirevar:'ip.auth_counter=60'"
SecRule IP:AUTH_COUNTER "@gt 10" \
"id:930005,\
phase:1,\
deny,\
status:429,\
log,\
msg:'CVE-SYNTH-2026-0042: Auth endpoint rate limit exceeded (>10/min)',\
tag:'virtual-patch/CVE-SYNTH-2026-0042',\
tag:'rate-limiting',\
severity:'WARNING'"
Student Task: Review the rules above, then:
- Identify gaps: What attack variants could bypass these rules? (Hint: consider URL-encoding, chunked transfer encoding, case variations in base64)
- Write Rule 6: A rule that inspects the decoded JWT header (if your WAF supports Lua/transforms) to catch ALL case variants of
"alg":"none" - Write Rule 7: A rule that blocks requests to PHI endpoints (
/api/v1/patients/*,/api/v1/records/*) when the JWT was issued more than 24 hours ago (to limit the blast radius of stolen tokens) - Test plan: Document how you would test these rules without disrupting production traffic
4.3 Exercise: IPS Signatures (Snort/Suricata)¶
Write network-level IPS signatures to detect exploitation of CVE-SYNTH-2026-0042.
Template — Snort/Suricata Rules:
# ============================================================
# Virtual Patch: CVE-SYNTH-2026-0042 — IPS Signatures
# AuthLib JWT Algorithm None Authentication Bypass
# Meridian Healthcare Systems
# ALL DATA IS SYNTHETIC — EDUCATIONAL ONLY
# ============================================================
# Signature 1: Detect JWT alg:none in HTTP Authorization header
alert http $EXTERNAL_NET any -> 198.51.100.10 any (
msg:"CVE-SYNTH-2026-0042 - JWT alg:none in Authorization header";
flow:established,to_server;
http.header;
content:"Authorization";
content:"Bearer ";
content:"eyJhbGciOiJub25lIi"; # base64("{"alg":"none"")
sid:2026004201;
rev:1;
classtype:web-application-attack;
metadata:cve CVE-SYNTH-2026-0042, severity critical, deployment perimeter;
reference:url,advisory.meridian.example.com/CVE-SYNTH-2026-0042;
)
# Signature 2: Detect JWT alg:None variant (capitalized)
alert http $EXTERNAL_NET any -> 198.51.100.10 any (
msg:"CVE-SYNTH-2026-0042 - JWT alg:None variant in Authorization header";
flow:established,to_server;
http.header;
content:"Authorization";
content:"Bearer ";
content:"eyJhbGciOiJOb25lIi"; # base64("{"alg":"None"")
sid:2026004202;
rev:1;
classtype:web-application-attack;
metadata:cve CVE-SYNTH-2026-0042, severity critical, deployment perimeter;
)
# Signature 3: Detect JWT alg:NONE variant (all caps)
alert http $EXTERNAL_NET any -> 198.51.100.10 any (
msg:"CVE-SYNTH-2026-0042 - JWT alg:NONE variant in Authorization header";
flow:established,to_server;
http.header;
content:"Authorization";
content:"Bearer ";
content:"eyJhbGciOiJOT05FIi"; # base64("{"alg":"NONE"")
sid:2026004203;
rev:1;
classtype:web-application-attack;
metadata:cve CVE-SYNTH-2026-0042, severity critical, deployment perimeter;
)
# Signature 4: Detect JWT with empty signature (generic — catches all alg:none bypasses)
# Pattern: two base64url segments followed by a trailing dot with no/minimal signature
alert http $EXTERNAL_NET any -> 198.51.100.10 any (
msg:"CVE-SYNTH-2026-0042 - JWT with empty/missing signature";
flow:established,to_server;
http.header;
content:"Authorization";
content:"Bearer ";
pcre:"/Bearer\s+[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.?\s*$/";
sid:2026004204;
rev:1;
classtype:web-application-attack;
metadata:cve CVE-SYNTH-2026-0042, severity critical, deployment perimeter;
)
# Signature 5: Detect rapid authentication attempts (possible JWT fuzzing)
alert http $EXTERNAL_NET any -> 198.51.100.10 any (
msg:"CVE-SYNTH-2026-0042 - Rapid auth attempts (possible JWT fuzzing)";
flow:established,to_server;
http.uri;
content:"/api/v1/auth/";
threshold:type both, track by_src, count 20, seconds 60;
sid:2026004205;
rev:1;
classtype:attempted-recon;
metadata:cve CVE-SYNTH-2026-0042, severity high, deployment perimeter;
)
Student Task:
- Write Signature 6: Detect POST requests to
/api/v1/auth/tokenwith a JSON body containing a JWT that has"alg"set to"none"(inspect the request body, not just headers) - Write Signature 7: Detect successful authentication responses (HTTP 200) to external IPs that were preceded by a blocked JWT attempt from the same source IP within 5 minutes (correlation signature — this indicates the attacker found a bypass)
- Write Signature 8: Detect access to PHI endpoints (
/api/v1/patients/,/api/v1/records/) from source IPs that are NOT in the known-good IP list (geographic anomaly detection)
4.4 Exercise: EDR Detection Rules¶
Write endpoint detection rules that identify post-exploitation activity related to CVE-SYNTH-2026-0042.
EDR Detection Rules:
# ============================================================
# EDR Detection: CVE-SYNTH-2026-0042 Post-Exploitation
# Meridian Healthcare Systems
# ALL DATA IS SYNTHETIC — EDUCATIONAL ONLY
# ============================================================
# Rule 1: Detect unusual process spawned by web application server
- name: "CVE-SYNTH-2026-0042 - Web Server Child Process Anomaly"
description: "Detects unusual child processes spawned by the Tomcat/Node.js process on the patient portal server, indicating possible post-exploitation RCE"
platform: windows
severity: critical
condition:
parent_process_name:
- "java.exe" # Tomcat
- "node.exe" # Node.js
process_name:
- "cmd.exe"
- "powershell.exe"
- "pwsh.exe"
- "wscript.exe"
- "cscript.exe"
- "certutil.exe"
- "bitsadmin.exe"
- "mshta.exe"
host: "portal-srv01.meridian.example.com" # SYNTHETIC
action: alert_and_isolate
mitre_attack:
- T1059.001 # PowerShell
- T1059.003 # Windows Command Shell
# Rule 2: Detect mass PHI data access after authentication bypass
- name: "CVE-SYNTH-2026-0042 - Mass PHI Record Access"
description: "Detects a single session accessing an abnormally high number of patient records, indicating possible data exfiltration after auth bypass"
platform: application
severity: critical
condition:
endpoint: "/api/v1/patients/*"
method: "GET"
unique_record_count_per_session: "> 50"
time_window: "5m"
action: alert_and_block_session
mitre_attack:
- T1530 # Data from Cloud Storage
- T1005 # Data from Local System
# Rule 3: Detect token reuse from multiple geographic locations
- name: "CVE-SYNTH-2026-0042 - JWT Token Geographic Anomaly"
description: "Detects the same JWT token being used from multiple distinct source IP ranges within a short time window, indicating token theft and reuse"
platform: application
severity: high
condition:
same_jwt_hash: true
distinct_source_ip_count: "> 2"
time_window: "15m"
action: alert_and_revoke_token
mitre_attack:
- T1550.001 # Application Access Token
Student Task:
- Write Rule 4: Detect file system changes in web application directories that could indicate webshell deployment after RCE
- Write Rule 5: Detect outbound network connections from the portal server to known-bad IP ranges or unusual ports (data exfiltration)
- Write Rule 6: Detect credential dumping attempts on the portal server (post-exploitation lateral movement preparation)
4.5 Deliverables — Phase 4¶
Phase 4 Deliverables
- [ ] Complete ModSecurity ruleset (Rules 1-7) for CVE-SYNTH-2026-0042
- [ ] Complete Snort/Suricata signature set (Signatures 1-8)
- [ ] Complete EDR detection rules (Rules 1-6)
- [ ] Gap analysis: What exploitation paths are NOT covered by your virtual patching rules?
- [ ] Testing plan: How would you validate these rules without impacting production?
- [ ] Bypass analysis: Document at least 3 ways an attacker might bypass your virtual patches and how you would detect those bypasses
Phase 5: Emergency Patch Deployment (45 minutes)¶
5.1 Scenario: Vendor Patch Released¶
VENDOR ADVISORY — AuthLib 2.4.2 Released
Date: 2026-04-12 (SYNTHETIC) Advisory: SYNTH-SA-2026-042 Affected Version: AuthLib 2.4.1 and earlier Fixed Version: AuthLib 2.4.2 Fix: Strict algorithm validation — rejects "none" algorithm entirely; enforces allowlist of acceptable algorithms (RS256, RS384, RS512, ES256, ES384, ES512) Breaking Changes: Applications that intentionally used "none" algorithm for local/test tokens will break. All JWTs must now have valid signatures. Deployment Notes: Library update only — no database migration, no configuration changes required beyond updating the dependency version.
5.2 Deployment Strategy Design¶
Template — Emergency Patch Deployment Plan:
╔══════════════════════════════════════════════════════════════════════╗
║ EMERGENCY PATCH DEPLOYMENT PLAN ║
║ CVE-SYNTH-2026-0042 — AuthLib 2.4.2 ║
║ Meridian Healthcare Systems (SYNTHETIC) ║
╠══════════════════════════════════════════════════════════════════════╣
║ ║
║ DEPLOYMENT PHASES ║
║ ║
║ Phase A: Pre-Deployment Validation (30 min) ║
║ ├── [ ] Download AuthLib 2.4.2 from vendor repository ║
║ ├── [ ] Verify package hash: sha256:abc123... (SYNTHETIC) ║
║ ├── [ ] Verify GPG signature from vendor signing key ║
║ ├── [ ] Run automated test suite against updated library ║
║ ├── [ ] Test JWT authentication flow in staging environment ║
║ ├── [ ] Verify no regression in legitimate RS256 token handling ║
║ └── [ ] Obtain emergency change approval (CAB fast-track) ║
║ ║
║ Phase B: Canary Deployment (30 min) ║
║ ├── Target: 1 portal server (portal-canary01.meridian.example.com) ║
║ ├── Traffic: 5% of production load via load balancer weight ║
║ ├── [ ] Deploy updated AuthLib 2.4.2 to canary server ║
║ ├── [ ] Monitor: HTTP 5xx rate (threshold: < 0.1%) ║
║ ├── [ ] Monitor: Authentication success rate (threshold: > 99.5%) ║
║ ├── [ ] Monitor: Response latency p99 (threshold: < 500ms) ║
║ ├── [ ] Monitor: Error logs for JWT rejection false positives ║
║ └── [ ] Hold window: 30 minutes of clean metrics before proceeding ║
║ ║
║ Phase C: Staged Rollout (60 min) ║
║ ├── Stage 1: 25% of production servers (15 min hold) ║
║ ├── Stage 2: 50% of production servers (15 min hold) ║
║ ├── Stage 3: 75% of production servers (15 min hold) ║
║ └── Stage 4: 100% of production servers (30 min monitoring) ║
║ ║
║ Phase D: Post-Deployment Verification (30 min) ║
║ ├── [ ] Confirm AuthLib version 2.4.2 on ALL portal servers ║
║ ├── [ ] Run exploit verification — confirm alg:none rejected ║
║ ├── [ ] Run legitimate auth flow — confirm no regression ║
║ ├── [ ] Remove virtual patch WAF rules (staged removal) ║
║ ├── [ ] Remove virtual patch IPS signatures (after 48hr soak) ║
║ └── [ ] Update vulnerability scanner — mark CVE as remediated ║
║ ║
║ ROLLBACK CRITERIA (automatic rollback if ANY trigger hit) ║
║ ├── HTTP 5xx rate > 1% for 5 consecutive minutes ║
║ ├── Authentication success rate < 98% ║
║ ├── Response latency p99 > 2000ms for 5 minutes ║
║ ├── Any critical error in application logs ║
║ └── Manual trigger by deployment lead ║
║ ║
║ ROLLBACK PROCEDURE ║
║ ├── 1. Revert AuthLib to 2.4.1 on affected servers ║
║ ├── 2. Re-enable virtual patch WAF/IPS rules ║
║ ├── 3. Notify SOC team — virtual patching resumes ║
║ ├── 4. Investigate failure root cause ║
║ └── 5. Schedule retry with fix within 24 hours ║
║ ║
╚══════════════════════════════════════════════════════════════════════╝
5.3 Exercise: Deployment Automation Scripts¶
Task: Write the deployment automation scripts for each phase.
Canary deployment script:
#!/bin/bash
# ============================================================
# Emergency Patch Deployment — Canary Phase
# CVE-SYNTH-2026-0042 — AuthLib 2.4.2
# ALL DATA IS SYNTHETIC — EDUCATIONAL ONLY
# ============================================================
set -euo pipefail
# Configuration (SYNTHETIC)
CANARY_HOST="portal-canary01.meridian.example.com" # SYNTHETIC
PACKAGE_URL="https://packages.meridian.example.com/authlib/2.4.2/authlib-2.4.2.tar.gz" # SYNTHETIC
EXPECTED_SHA256="a1b2c3d4e5f6..." # SYNTHETIC — replace with real hash
ROLLBACK_VERSION="2.4.1"
MONITORING_DURATION=1800 # 30 minutes in seconds
METRICS_ENDPOINT="https://metrics.meridian.example.com/api/v1/query" # SYNTHETIC
echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] Starting canary deployment for AuthLib 2.4.2"
# Step 1: Download and verify package
echo "[STEP 1] Downloading package..."
curl -sL "$PACKAGE_URL" -o /tmp/authlib-2.4.2.tar.gz
ACTUAL_SHA256=$(sha256sum /tmp/authlib-2.4.2.tar.gz | awk '{print $1}')
if [ "$ACTUAL_SHA256" != "$EXPECTED_SHA256" ]; then
echo "[CRITICAL] Package hash mismatch! Expected: $EXPECTED_SHA256, Got: $ACTUAL_SHA256"
echo "[CRITICAL] Aborting deployment — possible supply chain compromise"
exit 1
fi
echo "[STEP 1] Package hash verified: $ACTUAL_SHA256"
# Step 2: Deploy to canary server
echo "[STEP 2] Deploying to canary: $CANARY_HOST"
ssh deployer@"$CANARY_HOST" << 'DEPLOY_EOF'
# Backup current version
cp -r /opt/portal/lib/authlib /opt/portal/lib/authlib.bak
# Extract new version
tar xzf /tmp/authlib-2.4.2.tar.gz -C /opt/portal/lib/
# Verify installed version
VERSION=$(/opt/portal/lib/authlib/version.sh)
if [ "$VERSION" != "2.4.2" ]; then
echo "[ERROR] Version mismatch after install: $VERSION"
# Rollback
rm -rf /opt/portal/lib/authlib
mv /opt/portal/lib/authlib.bak /opt/portal/lib/authlib
exit 1
fi
# Restart application (graceful — drain existing connections)
systemctl reload portal-app
echo "[DEPLOY] AuthLib 2.4.2 deployed to canary"
DEPLOY_EOF
# Step 3: Monitor canary metrics
echo "[STEP 3] Monitoring canary for $((MONITORING_DURATION / 60)) minutes..."
MONITOR_START=$(date +%s)
MONITOR_END=$((MONITOR_START + MONITORING_DURATION))
while [ "$(date +%s)" -lt "$MONITOR_END" ]; do
ELAPSED=$(( ($(date +%s) - MONITOR_START) / 60 ))
echo "[MONITOR] Elapsed: ${ELAPSED}m / $((MONITORING_DURATION / 60))m"
# Check HTTP 5xx rate
ERROR_RATE=$(curl -s "$METRICS_ENDPOINT" \
--data-urlencode "query=rate(http_responses_total{host=\"$CANARY_HOST\",status=~\"5..\"}[5m])" \
| jq -r '.data.result[0].value[1] // "0"')
if (( $(echo "$ERROR_RATE > 0.001" | bc -l) )); then
echo "[ROLLBACK] Error rate exceeded threshold: $ERROR_RATE > 0.1%"
ssh deployer@"$CANARY_HOST" "rm -rf /opt/portal/lib/authlib && mv /opt/portal/lib/authlib.bak /opt/portal/lib/authlib && systemctl reload portal-app"
echo "[ROLLBACK] Canary rolled back to AuthLib $ROLLBACK_VERSION"
exit 1
fi
# Check auth success rate
AUTH_RATE=$(curl -s "$METRICS_ENDPOINT" \
--data-urlencode "query=rate(auth_success_total{host=\"$CANARY_HOST\"}[5m]) / rate(auth_attempts_total{host=\"$CANARY_HOST\"}[5m])" \
| jq -r '.data.result[0].value[1] // "1"')
if (( $(echo "$AUTH_RATE < 0.995" | bc -l) )); then
echo "[ROLLBACK] Auth success rate below threshold: $AUTH_RATE < 99.5%"
ssh deployer@"$CANARY_HOST" "rm -rf /opt/portal/lib/authlib && mv /opt/portal/lib/authlib.bak /opt/portal/lib/authlib && systemctl reload portal-app"
echo "[ROLLBACK] Canary rolled back to AuthLib $ROLLBACK_VERSION"
exit 1
fi
echo "[MONITOR] Error rate: ${ERROR_RATE} | Auth rate: ${AUTH_RATE} — within thresholds"
sleep 60
done
echo "[SUCCESS] Canary monitoring complete — all metrics within thresholds"
echo "[NEXT] Proceed to staged rollout (Phase C)"
Staged rollout script:
#!/bin/bash
# ============================================================
# Emergency Patch Deployment — Staged Rollout
# CVE-SYNTH-2026-0042 — AuthLib 2.4.2
# ALL DATA IS SYNTHETIC — EDUCATIONAL ONLY
# ============================================================
set -euo pipefail
# Server groups (SYNTHETIC)
declare -a STAGE_1=(
"portal-web01.meridian.example.com"
"portal-web02.meridian.example.com"
)
declare -a STAGE_2=(
"portal-web03.meridian.example.com"
"portal-web04.meridian.example.com"
)
declare -a STAGE_3=(
"portal-web05.meridian.example.com"
"portal-web06.meridian.example.com"
)
declare -a STAGE_4=(
"portal-web07.meridian.example.com"
"portal-web08.meridian.example.com"
)
HOLD_DURATION=900 # 15 minutes per stage
deploy_stage() {
local STAGE_NAME=$1
shift
local SERVERS=("$@")
echo "========================================"
echo "[STAGE] Deploying $STAGE_NAME: ${SERVERS[*]}"
echo "========================================"
for SERVER in "${SERVERS[@]}"; do
echo "[DEPLOY] Updating $SERVER..."
ssh deployer@"$SERVER" << 'EOF'
cp -r /opt/portal/lib/authlib /opt/portal/lib/authlib.bak
tar xzf /tmp/authlib-2.4.2.tar.gz -C /opt/portal/lib/
systemctl reload portal-app
EOF
echo "[DEPLOY] $SERVER updated"
done
echo "[HOLD] Monitoring for $((HOLD_DURATION / 60)) minutes..."
sleep "$HOLD_DURATION"
# Check aggregate metrics before proceeding
echo "[CHECK] Verifying stage metrics..."
# (monitoring logic similar to canary phase)
}
deploy_stage "Stage 1 (25%)" "${STAGE_1[@]}"
deploy_stage "Stage 2 (50%)" "${STAGE_2[@]}"
deploy_stage "Stage 3 (75%)" "${STAGE_3[@]}"
deploy_stage "Stage 4 (100%)" "${STAGE_4[@]}"
echo "========================================"
echo "[COMPLETE] All servers updated to AuthLib 2.4.2"
echo "[NEXT] Proceed to post-deployment verification (Phase D)"
echo "========================================"
5.4 Exercise: Rollback Verification Queries¶
Write queries to verify rollback state if deployment fails.
KQL — Verify Rollback Success:
// Verify AuthLib version across all portal servers after rollback
// ALL DATA IS SYNTHETIC
DeviceFileEvents
| where Timestamp > ago(1h)
| where DeviceName startswith "portal-"
and DeviceName endswith ".meridian.example.com"
| where FolderPath has "authlib"
| where ActionType == "FileModified" or ActionType == "FileCreated"
| summarize LatestEvent = max(Timestamp),
FileCount = count()
by DeviceName, FolderPath
| extend LibraryVersion = extract(@"authlib[/\\](\d+\.\d+\.\d+)", 1, FolderPath)
| project DeviceName, LibraryVersion, LatestEvent, FileCount
| order by DeviceName asc
SPL — Verify Rollback Success:
index=endpoint sourcetype=file_monitor
host="portal-*.meridian.example.com"
file_path="*authlib*"
action IN ("modified", "created")
earliest=-1h
| stats latest(_time) as latest_event count as file_count by host file_path
| rex field=file_path "authlib[/\\\\](?<library_version>\d+\.\d+\.\d+)"
| table host library_version latest_event file_count
| sort host
5.5 Deliverables — Phase 5¶
Phase 5 Deliverables
- [ ] Complete deployment plan document with all four phases (A-D)
- [ ] Canary deployment script with metric monitoring and auto-rollback
- [ ] Staged rollout script with hold windows and verification
- [ ] Rollback procedure and verification queries (KQL and SPL)
- [ ] Communication template: draft the stakeholder notification for each deployment phase (1 paragraph each)
- [ ] Risk assessment: What could go wrong during emergency patching? List 5 risks and mitigations.
Phase 6: Patch Verification & Validation (30 minutes)¶
6.1 Post-Patch Verification Queries¶
After the patch is deployed, you must verify three things:
- Patch applied: Every portal server is running AuthLib 2.4.2
- No systems missed: Identify any servers still running the vulnerable version
- No exploitation during patch window: Detect any successful exploitation that occurred between vulnerability disclosure and patch completion
6.2 KQL Detection Queries¶
// ============================================================
// Query 1: Verify patch deployment — all servers on AuthLib 2.4.2
// Meridian Healthcare Systems — ALL DATA IS SYNTHETIC
// ============================================================
let ExpectedVersion = "2.4.2";
let PortalServers = dynamic([
"portal-canary01.meridian.example.com",
"portal-web01.meridian.example.com",
"portal-web02.meridian.example.com",
"portal-web03.meridian.example.com",
"portal-web04.meridian.example.com",
"portal-web05.meridian.example.com",
"portal-web06.meridian.example.com",
"portal-web07.meridian.example.com",
"portal-web08.meridian.example.com"
]);
SoftwareInventory
| where Timestamp > ago(24h)
| where DeviceName in (PortalServers)
| where SoftwareName =~ "authlib"
| summarize LatestVersion = arg_max(Timestamp, SoftwareVersion)
by DeviceName
| extend PatchStatus = iff(SoftwareVersion == ExpectedVersion, "PATCHED", "VULNERABLE")
| project DeviceName, SoftwareVersion, PatchStatus, Timestamp
| order by PatchStatus desc, DeviceName asc
// ============================================================
// Query 2: Find servers that missed the patch
// ALL DATA IS SYNTHETIC
// ============================================================
let ExpectedVersion = "2.4.2";
SoftwareInventory
| where Timestamp > ago(24h)
| where SoftwareName =~ "authlib"
| where DeviceName startswith "portal-"
and DeviceName endswith ".meridian.example.com"
| summarize arg_max(Timestamp, SoftwareVersion) by DeviceName
| where SoftwareVersion != ExpectedVersion
| project DeviceName,
CurrentVersion = SoftwareVersion,
ExpectedVersion = ExpectedVersion,
LastScanTime = Timestamp,
DaysVulnerable = datetime_diff('day', now(), Timestamp)
| extend Urgency = case(
DaysVulnerable > 7, "CRITICAL — Overdue",
DaysVulnerable > 3, "HIGH — Approaching SLA",
DaysVulnerable > 1, "MEDIUM — Within SLA",
"LOW — Recently scanned"
)
| order by DaysVulnerable desc
// ============================================================
// Query 3: Detect exploitation attempts during patch window
// Looks for JWT alg:none attacks between disclosure and full patch
// ALL DATA IS SYNTHETIC
// ============================================================
let DisclosureTime = datetime(2026-04-10T08:00:00Z); // SYNTHETIC
let PatchCompleteTime = datetime(2026-04-12T16:00:00Z); // SYNTHETIC
//
// Look for indicators of compromise during the patch window
//
union
(
// Indicator 1: WAF blocks of JWT alg:none (from virtual patches)
CommonSecurityLog
| where TimeGenerated between (DisclosureTime .. PatchCompleteTime)
| where DeviceVendor == "ModSecurity" or DeviceVendor == "WAF"
| where Message has "CVE-SYNTH-2026-0042"
| where Activity == "BLOCK"
| summarize BlockedAttempts = count(),
UniqueSourceIPs = dcount(SourceIP),
FirstAttempt = min(TimeGenerated),
LastAttempt = max(TimeGenerated)
by SourceIP
| extend EventType = "WAF_BLOCK"
),
(
// Indicator 2: Successful authentications with suspicious JWT patterns
SigninLogs
| where TimeGenerated between (DisclosureTime .. PatchCompleteTime)
| where AppDisplayName =~ "Meridian Patient Portal"
| where ResultType == 0 // Successful auth
| where AuthenticationDetails has "none" or AuthenticationDetails has "alg"
| summarize SuccessfulAuths = count(),
UniqueUsers = dcount(UserPrincipalName)
by SourceIP = IPAddress, UserPrincipalName
| extend EventType = "SUSPICIOUS_AUTH"
),
(
// Indicator 3: Unusual PHI access patterns during patch window
AuditLogs
| where TimeGenerated between (DisclosureTime .. PatchCompleteTime)
| where OperationName has_any ("PatientRecordAccess", "PHIExport", "BulkQuery")
| summarize RecordsAccessed = count(),
UniquePatients = dcount(TargetResources)
by InitiatedBy = tostring(InitiatedBy.user.userPrincipalName),
SourceIP = tostring(InitiatedBy.user.ipAddress)
| where RecordsAccessed > 50 // Threshold: normal max is ~20/session
| extend EventType = "MASS_PHI_ACCESS"
),
(
// Indicator 4: IPS alerts for CVE-SYNTH-2026-0042
CommonSecurityLog
| where TimeGenerated between (DisclosureTime .. PatchCompleteTime)
| where DeviceVendor in ("Snort", "Suricata")
| where Message has "CVE-SYNTH-2026-0042" or Message has "2026004"
| summarize AlertCount = count(),
UniqueSourceIPs = dcount(SourceIP)
by SourceIP, Message
| extend EventType = "IPS_ALERT"
)
| project EventType, SourceIP, details = pack_all()
| order by EventType asc
// ============================================================
// Query 4: Post-patch validation — confirm exploit is blocked
// Send test alg:none JWT and verify it is rejected
// ALL DATA IS SYNTHETIC
// ============================================================
// After patching, look for HTTP 401/403 responses to JWT alg:none test
WebLogs
| where Timestamp > ago(1h)
| where ServerHost startswith "portal-"
and ServerHost endswith ".meridian.example.com"
| where UrlPath has "/api/v1/auth/"
| where RequestHeaders has "eyJhbGciOiJub25lIi" // base64 of alg:none
| project Timestamp, ServerHost, SourceIP, HttpStatusCode, UrlPath
| summarize TestResults = count() by ServerHost, HttpStatusCode
| extend ValidationResult = case(
HttpStatusCode == 401, "PASS — Exploit correctly rejected",
HttpStatusCode == 403, "PASS — Exploit correctly blocked by WAF",
HttpStatusCode == 200, "FAIL — Exploit still works! CRITICAL!",
strcat("REVIEW — Unexpected status: ", tostring(HttpStatusCode))
)
6.3 SPL Detection Queries¶
`comment("============================================================")`
`comment("Query 1: Verify patch deployment — all servers on AuthLib 2.4.2")`
`comment("Meridian Healthcare Systems — ALL DATA IS SYNTHETIC")`
`comment("============================================================")`
index=endpoint sourcetype=software_inventory
host="portal-*.meridian.example.com"
software_name="authlib"
earliest=-24h
| stats latest(_time) as last_scan latest(software_version) as current_version by host
| eval expected_version="2.4.2"
| eval patch_status=if(current_version==expected_version, "PATCHED", "VULNERABLE")
| table host current_version expected_version patch_status last_scan
| sort - patch_status host
`comment("============================================================")`
`comment("Query 2: Find servers that missed the patch")`
`comment("ALL DATA IS SYNTHETIC")`
`comment("============================================================")`
index=endpoint sourcetype=software_inventory
host="portal-*.meridian.example.com"
software_name="authlib"
earliest=-24h
| stats latest(_time) as last_scan latest(software_version) as current_version by host
| where current_version!="2.4.2"
| eval days_vulnerable=round((now()-last_scan)/86400, 1)
| eval urgency=case(
days_vulnerable>7, "CRITICAL - Overdue",
days_vulnerable>3, "HIGH - Approaching SLA",
days_vulnerable>1, "MEDIUM - Within SLA",
1==1, "LOW - Recently scanned")
| table host current_version days_vulnerable urgency last_scan
| sort - days_vulnerable
`comment("============================================================")`
`comment("Query 3: Detect exploitation attempts during patch window")`
`comment("ALL DATA IS SYNTHETIC")`
`comment("============================================================")`
index=waf OR index=proxy OR index=ids
sourcetype IN ("modsecurity", "snort", "suricata", "web_access")
earliest="04/10/2026:08:00:00" latest="04/12/2026:16:00:00"
("CVE-SYNTH-2026-0042" OR "eyJhbGciOiJub25lIi" OR "alg.*none" OR sid=2026004*)
| eval event_type=case(
sourcetype=="modsecurity", "WAF_BLOCK",
sourcetype IN ("snort","suricata"), "IPS_ALERT",
sourcetype=="web_access" AND status==200, "SUSPICIOUS_AUTH",
1==1, "OTHER")
| stats count as attempts dc(src_ip) as unique_source_ips
earliest(_time) as first_seen latest(_time) as last_seen
values(src_ip) as source_ips
by event_type
| sort - attempts
`comment("============================================================")`
`comment("Query 4: Detect mass PHI access during patch window")`
`comment("ALL DATA IS SYNTHETIC")`
`comment("============================================================")`
index=web sourcetype=access_combined
host="portal-*.meridian.example.com"
uri_path IN ("/api/v1/patients/*", "/api/v1/records/*")
status=200
earliest="04/10/2026:08:00:00" latest="04/12/2026:16:00:00"
| stats count as records_accessed dc(uri_path) as unique_endpoints
earliest(_time) as first_access latest(_time) as last_access
by src_ip useragent
| where records_accessed > 50
| eval risk=case(
records_accessed>500, "CRITICAL - Possible mass exfiltration",
records_accessed>200, "HIGH - Abnormal access volume",
records_accessed>50, "MEDIUM - Elevated access",
1==1, "LOW")
| table src_ip records_accessed unique_endpoints risk first_access last_access useragent
| sort - records_accessed
`comment("============================================================")`
`comment("Query 5: Post-patch validation — confirm exploit is blocked")`
`comment("ALL DATA IS SYNTHETIC")`
`comment("============================================================")`
index=web sourcetype=access_combined
host="portal-*.meridian.example.com"
uri_path="/api/v1/auth/*"
earliest=-1h
| search "eyJhbGciOiJub25lIi"
| stats count by host status
| eval validation_result=case(
status==401, "PASS - Exploit correctly rejected",
status==403, "PASS - Exploit correctly blocked by WAF",
status==200, "FAIL - Exploit still works! CRITICAL!",
1==1, "REVIEW - Unexpected status: ".status)
| table host status validation_result count
6.4 Patch Compliance Dashboard Specification¶
Task: Design a dashboard that shows real-time patch compliance status. Define the following panels:
┌──────────────────────────────────────────────────────────────────────┐
│ PATCH COMPLIANCE DASHBOARD │
│ CVE-SYNTH-2026-0042 — AuthLib 2.4.2 │
├─────────────────────────┬────────────────────────────────────────────┤
│ │ │
│ PATCH STATUS │ DEPLOYMENT TIMELINE │
│ ┌─────────────────┐ │ ┌────────────────────────────────────┐ │
│ │ Patched: 7/9 │ │ │ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓░░░ 78% │ │
│ │ Pending: 2/9 │ │ │ Canary → 25% → 50% → 75% → 100% │ │
│ │ Failed: 0/9 │ │ └────────────────────────────────────┘ │
│ └─────────────────┘ │ │
│ │ │
├─────────────────────────┼────────────────────────────────────────────┤
│ │ │
│ EXPLOITATION ATTEMPTS │ VIRTUAL PATCH EFFECTIVENESS │
│ During Patch Window │ ┌────────────────────────────────────┐ │
│ ┌─────────────────┐ │ │ WAF Blocks: 1,247 │ │
│ │ Blocked: 1,302 │ │ │ IPS Alerts: 55 │ │
│ │ Suspicious: 3 │ │ │ False Positives: 2 │ │
│ │ Confirmed: 0 │ │ │ Bypass Attempts: 0 │ │
│ └─────────────────┘ │ └────────────────────────────────────┘ │
│ │ │
├─────────────────────────┴────────────────────────────────────────────┤
│ │
│ SERVER-LEVEL DETAIL │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ Server │ Version │ Status │ Patched │ │
│ │ portal-canary01.meridian.ex... │ 2.4.2 │ ✓ │ 14:00 │ │
│ │ portal-web01.meridian.ex... │ 2.4.2 │ ✓ │ 14:35 │ │
│ │ portal-web02.meridian.ex... │ 2.4.2 │ ✓ │ 14:35 │ │
│ │ portal-web03.meridian.ex... │ 2.4.2 │ ✓ │ 14:50 │ │
│ │ portal-web04.meridian.ex... │ 2.4.2 │ ✓ │ 14:50 │ │
│ │ portal-web05.meridian.ex... │ 2.4.2 │ ✓ │ 15:05 │ │
│ │ portal-web06.meridian.ex... │ 2.4.2 │ ✓ │ 15:05 │ │
│ │ portal-web07.meridian.ex... │ 2.4.1 │ ✗ │ — │ │
│ │ portal-web08.meridian.ex... │ 2.4.1 │ ✗ │ — │ │
│ └──────────────────────────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────────┘
6.5 Deliverables — Phase 6¶
Phase 6 Deliverables
- [ ] KQL queries for patch verification (4 queries — tested and producing expected output)
- [ ] SPL queries for patch verification (5 queries — tested and producing expected output)
- [ ] Dashboard specification with panel definitions, data sources, and refresh intervals
- [ ] Written report: "Patch Window Exposure Analysis" — documenting any exploitation that occurred during the vulnerability window (use synthetic data)
- [ ] Lessons learned document: What would you do differently to reduce the patch window next time?
Challenge Questions¶
Challenge Questions (Advanced)
Challenge 1: EPSS Threshold Decision
Your organization has a limited patch window of 4 hours per month. You have 200 vulnerabilities in the queue. Using EPSS data, you determine that only 15 vulnerabilities have EPSS > 0.5. Your CISO asks: "Should we patch only the EPSS > 0.5 vulnerabilities and defer the rest?" Write a 2-paragraph response that addresses the statistical and operational considerations. Include the concepts of false negative risk, regulatory exposure, and the base rate problem.
Challenge 2: Virtual Patch Lifecycle
A virtual patch (WAF rule) for CVE-SYNTH-2026-0042 has been in production for 90 days. The vendor patch was applied 60 days ago. The security team wants to remove the virtual patch rules to reduce WAF complexity. Design a decision framework for virtual patch retirement that accounts for: (a) patch verification confidence, (b) the possibility of patch regression during future updates, (c) defense-in-depth value, and (d) WAF performance impact.
Challenge 3: Supply Chain Vulnerability
During your analysis, you discover that AuthLib 2.4.2 (the "fix") was compiled with a version of GCC that has a known code generation bug (CVE-SYNTH-2026-9999). This bug could theoretically cause the JWT validation to be optimized away under specific compiler flags. How would you verify that the compiled library actually enforces the algorithm check? What additional supply chain controls would you recommend?
Challenge 4: CVSS v4.0 Disagreement
Your vulnerability scanner reports CVE-SYNTH-2026-0042 as CVSS 9.8 (v3.1). Your manual CVSS v4.0 analysis produces a score of 10.0 when accounting for Supplemental metrics (Automatable: Yes, Safety: Present in healthcare context). However, the NVD publishes it as v4.0 8.7 because they did not consider the Environmental metrics. Which score should your organization use for SLA purposes, and why? Design a policy that handles CVSS score disagreements.
Challenge 5: Zero-Day Dilemma
At hour 12 of the zero-day response, your threat intel team reports that the exploit for CVE-SYNTH-2026-0042 is being sold on dark web forums for $50,000. The virtual patch is in place but an attacker could theoretically bypass the WAF by fragmenting the JWT across multiple HTTP/2 frames. You have two options: (a) take the patient portal offline until the vendor patch is ready (estimated 36 hours), or (b) keep it running with virtual patches and enhanced monitoring. The portal handles 10,000 patient appointment bookings per day. Write a risk-based decision memo (1 page) recommending one option, with quantified risk analysis.
Scoring Rubric¶
Scoring Rubric — 250 Points Total
Phase 1: Vulnerability Discovery & Intake (40 points)¶
| Criteria | Points | Description |
|---|---|---|
| Correct combined risk scores (all 50) | 15 | All calculations accurate within ±0.01 |
| Correct tier classification | 10 | All 50 vulns assigned to correct tier |
| Sorted remediation queue | 5 | Correctly ordered by combined risk score |
| Written justifications (3+) | 5 | Thoughtful analysis of classification overrides |
| Top 5 identification | 5 | Correct identification with supporting rationale |
Phase 2: CVSS v4.0 Scoring Exercise (45 points)¶
| Criteria | Points | Description |
|---|---|---|
| Vuln A scoring (all metrics) | 9 | Correct metric selections with justification |
| Vuln B scoring (all metrics) | 9 | Correct metric selections with justification |
| Vuln C scoring (all metrics) | 9 | Correct metric selections with justification |
| Vuln D scoring (all metrics) | 9 | Correct metric selections with justification |
| Vuln E scoring (all metrics) | 9 | Correct metric selections with justification |
Phase 3: EPSS-Based Prioritization (30 points)¶
| Criteria | Points | Description |
|---|---|---|
| Dual-ranked list (complete) | 10 | Both CVSS-only and combined rankings for all 50 |
| Top 5 outlier analysis | 10 | Correctly identified outliers with insightful analysis |
| Executive summary | 5 | Clear, persuasive, technically accurate |
| Decision matrix | 5 | At least 3 valid override conditions documented |
Phase 4: Virtual Patching (60 points)¶
| Criteria | Points | Description |
|---|---|---|
| ModSecurity rules (7 rules) | 20 | Syntactically correct, operationally effective |
| Snort/Suricata signatures (8 sigs) | 15 | Syntactically correct, proper flow/content |
| EDR detection rules (6 rules) | 10 | Logical, covers post-exploitation indicators |
| Gap analysis | 5 | Identifies at least 2 uncovered attack paths |
| Testing plan | 5 | Realistic, non-disruptive testing methodology |
| Bypass analysis | 5 | At least 3 bypass vectors with detection strategies |
Phase 5: Emergency Patch Deployment (40 points)¶
| Criteria | Points | Description |
|---|---|---|
| Deployment plan (all phases A-D) | 15 | Complete, realistic, operationally sound |
| Automation scripts | 10 | Functional scripts with error handling |
| Rollback procedure + queries | 5 | Complete rollback with verification |
| Communication templates | 5 | Professional, complete, appropriate audience |
| Risk assessment (5 risks) | 5 | Realistic risks with practical mitigations |
Phase 6: Patch Verification & Validation (35 points)¶
| Criteria | Points | Description |
|---|---|---|
| KQL queries (4 queries) | 10 | Syntactically correct, operationally useful |
| SPL queries (5 queries) | 10 | Syntactically correct, operationally useful |
| Dashboard specification | 5 | Complete panel definitions with data sources |
| Patch window exposure analysis | 5 | Thorough analysis using synthetic data |
| Lessons learned | 5 | Actionable, specific, demonstrates learning |
Scoring Thresholds¶
| Score | Grade | Assessment |
|---|---|---|
| 225–250 | Expert | Ready for senior vulnerability management roles |
| 200–224 | Proficient | Solid understanding — ready for independent work |
| 175–199 | Competent | Good foundation — needs mentored practice |
| 150–174 | Developing | Understands concepts — needs more hands-on experience |
| < 150 | Foundational | Review prerequisite materials and retry |
Answer Key¶
Phase 1 Answer Key — Top 10 Combined Risk Scores (click to expand)
Combined Risk Score Calculation Examples:
| # | CVE | CVSS | EPSS | CVSS Norm | Asset Modifier | Combined Risk | Tier |
|---|---|---|---|---|---|---|---|
| 1 | CVE-SYNTH-2026-0042 | 9.8 | 0.971 | 0.98 | +0.35 | (0.98×0.4)+(0.971×0.4)+0.35 = 1.130 | Critical |
| 2 | CVE-SYNTH-2026-0108 | 9.1 | 0.892 | 0.91 | +0.20 | (0.91×0.4)+(0.892×0.4)+0.20 = 0.921 | Critical |
| 5 | CVE-SYNTH-2026-0044 | 8.6 | 0.912 | 0.86 | +0.15 | (0.86×0.4)+(0.912×0.4)+0.15 = 0.859 | Critical |
| 4 | CVE-SYNTH-2026-0301 | 8.8 | 0.756 | 0.88 | +0.35 | (0.88×0.4)+(0.756×0.4)+0.35 = 1.004 | Critical |
| 8 | CVE-SYNTH-2026-0087 | 8.1 | 0.823 | 0.81 | +0.35 | (0.81×0.4)+(0.823×0.4)+0.35 = 1.003 | Critical |
| 11 | CVE-SYNTH-2026-0845 | 7.5 | 0.891 | 0.75 | +0.35 | (0.75×0.4)+(0.891×0.4)+0.35 = 1.006 | Critical |
| 16 | CVE-SYNTH-2026-0553 | 7.0 | 0.834 | 0.70 | +0.35 | (0.70×0.4)+(0.834×0.4)+0.35 = 0.964 | Critical |
| 13 | CVE-SYNTH-2026-0390 | 7.4 | 0.678 | 0.74 | +0.20 | (0.74×0.4)+(0.678×0.4)+0.20 = 0.767 | High |
| 14 | CVE-SYNTH-2026-0912 | 7.2 | 0.445 | 0.72 | +0.35 | (0.72×0.4)+(0.445×0.4)+0.35 = 0.816 | Critical |
| 7 | CVE-SYNTH-2026-0623 | 8.2 | 0.445 | 0.82 | +0.20 | (0.82×0.4)+(0.445×0.4)+0.20 = 0.706 | High |
Key Insight: CVE-SYNTH-2026-0845 (CVSS 7.5) ranks higher than CVE-SYNTH-2026-0215 (CVSS 9.0) because its EPSS of 0.891 indicates active exploitation, while the PostgreSQL vulnerability (EPSS 0.034) is rarely exploited in practice despite its high severity score.
Key Insight: CVE-SYNTH-2026-0519 (CVSS 8.4) drops dramatically in combined ranking because its EPSS of 0.003 indicates virtually zero real-world exploitation — the timing side-channel attack requires local access and is extremely difficult to execute reliably.
Phase 2 Answer Key — CVSS v4.0 Scoring (click to expand)
Vulnerability A: CVE-SYNTH-2026-0042
Attack Vector (AV): Network — exploitable remotely over the internet
Attack Complexity (AC): Low — no special conditions or race windows
Attack Requirements (AT): None — no prerequisite configuration required
Privileges Required (PR): None — unauthenticated attack
User Interaction (UI): None — no user action required
Vulnerable System Impact:
Confidentiality (VC): High — full access to portal data
Integrity (VI): High — can modify any portal data
Availability (VA): High — can disrupt portal operations
Subsequent System Impact:
Confidentiality (SC): High — access to backend PHI via portal API
Integrity (SI): High — can modify patient records via API
Availability (SA): Low — backend systems have independent availability
Threat Metrics:
Exploit Maturity (E): Attacked — confirmed active exploitation
Environmental Metrics:
Confidentiality Req (CR): High — PHI data requires maximum confidentiality
Integrity Req (IR): High — patient record integrity is critical
Availability Req (AR): High — patient portal availability affects care delivery
Supplemental Metrics:
Safety (S): Present — healthcare context, patient safety implications
Automatable (AU): Yes — trivially scriptable, no human interaction needed
Recovery (R): User — requires manual incident response and token revocation
Value Density (V): Concentrated — high-value PHI data in one place
Vector: CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:L/E:A/CR:H/IR:H/AR:H/S:P/AU:Y/R:U/V:C
Base Score: 10.0
Base + Threat Score: 10.0
Overall Score: 10.0
Vulnerability B: CVE-SYNTH-2026-0623
AV: Network | AC: Low | AT: Present (requires gadget libs on classpath)
PR: Low (valid API key required) | UI: None
VC: High | VI: High | VA: High
SC: High (direct DB access) | SI: High | SA: Low
E: PoC (public PoC exists but no confirmed active exploitation)
CR: High | IR: High | AR: Medium
Vector: CVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:L/E:P/CR:H/IR:H/AR:M
Base Score: 8.7
Base + Threat Score: 8.4
Overall Score: 8.6
Vulnerability C: CVE-SYNTH-2026-0156
AV: Local | AC: High (precise timing required) | AT: Present (update must be triggered)
PR: Low (local user access) | UI: None
VC: High | VI: High | VA: High (SYSTEM access)
SC: None (local endpoint only) | SI: None | SA: None
E: Unreported (no public exploit)
CR: Medium | IR: Medium | AR: Medium
Vector: CVSS:4.0/AV:L/AC:H/AT:P/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:U/CR:M/IR:M/AR:M
Base Score: 5.9
Base + Threat Score: 5.2
Overall Score: 5.2
Note: CVSS v3.1 scored this 7.8 — v4.0 is significantly lower due to AT:Present
and AC:High, which v3.1 did not fully account for.
Vulnerability D: CVE-SYNTH-2026-0445
AV: Network | AC: Low | AT: None
PR: None | UI: Active (user must click malicious link)
VC: Low (client-side XSS — limited direct impact) | VI: Low | VA: None
SC: High (session hijacking → PHI access) | SI: Low | SA: None
E: Attacked (observed in phishing campaigns)
CR: High (PHI) | IR: Medium | AR: Low
Vector: CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:A/VC:L/VI:L/VA:N/SC:H/SI:L/SA:N/E:A/CR:H/IR:M/AR:L
Base Score: 6.9
Base + Threat Score: 6.9
Overall Score: 7.1
Note: CVSS v3.1 scored this 6.1. v4.0 is higher because the Subsequent System
impact (SC:High) captures the session hijacking → PHI access chain that v3.1
did not model well.
Vulnerability E: CVE-SYNTH-2026-0356
AV: Local | AC: Low | AT: None
PR: Low | UI: None
VC: None | VI: Low (log tampering) | VA: None
SC: None | SI: High (SIEM pipeline loses visibility) | SA: None
E: Unreported (no public exploit, but technique is simple)
CR: Low | IR: High (log integrity is critical for detection) | AR: Low
Vector: CVSS:4.0/AV:L/AC:L/AT:N/PR:L/UI:N/VC:N/VI:L/VA:N/SC:N/SI:H/SA:N/E:U/CR:L/IR:H/AR:L
Base Score: 5.3
Base + Threat Score: 4.8
Overall Score: 5.1
Note: The high Environmental score for IR captures the critical importance
of log integrity in a healthcare monitoring environment.
Phase 3 Answer Key — EPSS Outlier Analysis (click to expand)
Top 5 Rank-Change Outliers (UP movers — underestimated by CVSS alone):
| CVE | CVSS Rank | Combined Rank | Change | Analysis |
|---|---|---|---|---|
| CVE-SYNTH-2026-0845 (Node.js) | ~11 | ~6 | +5 UP | EPSS 0.891 — mass scanning; CVSS 7.5 underestimates real risk |
| CVE-SYNTH-2026-0553 (Nginx) | ~16 | ~7 | +9 UP | EPSS 0.834 — active DDoS campaigns; CVSS 7.0 underestimates |
| CVE-SYNTH-2026-0856 (Commons Text) | ~20 | ~12 | +8 UP | EPSS 0.823 on a CVSS 6.5 — campaign targeting Java apps |
| CVE-SYNTH-2026-0356 (Sysmon) | ~29 | ~18 | +11 UP | EPSS 0.678 on a CVSS 5.5 — used by APT groups for evasion |
| CVE-SYNTH-2026-0445 (React XSS) | ~24 | ~15 | +9 UP | EPSS 0.712 on CVSS 6.1 — active phishing campaigns |
Top 5 Rank-Change Outliers (DOWN movers — overestimated by CVSS alone):
| CVE | CVSS Rank | Combined Rank | Change | Analysis |
|---|---|---|---|---|
| CVE-SYNTH-2026-0215 (PostgreSQL) | ~3 | ~17 | -14 DOWN | CVSS 9.0 but EPSS only 0.034 — requires auth, rarely exploited |
| CVE-SYNTH-2026-0519 (PostgreSQL) | ~6 | ~30 | -24 DOWN | CVSS 8.4 but EPSS 0.003 — timing side-channel, local only |
| CVE-SYNTH-2026-0734 (WSUS) | ~9 | ~28 | -19 DOWN | CVSS 8.0 but EPSS 0.067 — MITM requirement, rare attack |
| CVE-SYNTH-2026-0661 (OpenSSH) | ~16 | ~33 | -17 DOWN | CVSS 7.0 but EPSS 0.002 — requires agent forwarding, rare |
| CVE-SYNTH-2026-0267 (pgAdmin) | ~11 | ~31 | -20 DOWN | CVSS 7.5 but EPSS 0.012 — CSRF in admin, requires auth session |
Executive Summary (model answer):
CVSS-only prioritization would have Meridian Healthcare patching CVE-SYNTH-2026-0215 (PostgreSQL privilege escalation, CVSS 9.0) before CVE-SYNTH-2026-0845 (Node.js prototype pollution, CVSS 7.5). However, the Node.js vulnerability has an EPSS of 0.891 — meaning there is an 89.1% probability it will be exploited within 30 days — compared to only 3.4% for the PostgreSQL issue. In operational terms, patching by CVSS alone would leave a highly-targeted, easily-exploitable internet-facing vulnerability open while resources are spent on a rarely-exploited internal database issue.
The combined EPSS+CVSS approach, weighted with asset criticality modifiers, produces a prioritization that aligns remediation effort with actual risk. This does not mean ignoring high-CVSS, low-EPSS vulnerabilities — they remain in the remediation queue — but it ensures that limited patching windows are used to maximum risk-reduction effect. For a healthcare organization bound by HIPAA, this data-driven approach is both defensible to auditors and operationally superior.
Phase 4 Answer Key — Virtual Patching Gaps (click to expand)
Gap Analysis — Uncovered Attack Paths:
-
HTTP/2 frame fragmentation: The ModSecurity rules inspect the assembled HTTP request, but an attacker could fragment the JWT across multiple HTTP/2 frames. If the WAF does not reassemble frames before inspection, the
alg:nonepattern may not match. Mitigation: Ensure WAF performs full HTTP/2 frame reassembly; add a rule that inspects reassembled content. -
JWT in non-standard locations: The rules cover
Authorizationheader and request body, but the application might accept JWTs in query parameters (?token=...), cookies, or custom headers (X-Auth-Token). Mitigation: Add rules covering all JWT input vectors used by the application. -
Base64 padding variants: Standard base64 and base64url encoding produce different outputs for the same input. The rules match specific base64url patterns, but an attacker might use standard base64 with padding characters (
=). Mitigation: Add rule variants covering both base64 and base64url encodings. -
Chunked Transfer-Encoding evasion: If the request body is sent with chunked encoding, the WAF may inspect each chunk individually rather than the reassembled body, missing the pattern. Mitigation: Configure WAF to reassemble chunked requests before rule evaluation.
-
Algorithm confusion (RS256 → HS256): Beyond
alg:none, an attacker might changealgfrom RS256 to HS256 and use the public key as the HMAC secret. This is a different attack (CVE-2015-2951 pattern) not covered by thealg:nonerules. Mitigation: Add rules that block any JWT where the algorithm does not match the expected RS256/ES256 allowlist.
ATT&CK Techniques Mapped¶
| Technique ID | Technique Name | Lab Phase | Context |
|---|---|---|---|
| T1190 | Exploit Public-Facing Application | Phase 4 | JWT alg:none exploitation of patient portal |
| T1078.004 | Valid Accounts: Cloud Accounts | Phase 4 | Forged JWT grants admin access |
| T1550.001 | Use Alternate Authentication Material: Application Access Token | Phase 4, 6 | Crafted JWT used for authentication bypass |
| T1059.001 | Command and Scripting Interpreter: PowerShell | Phase 4 | Post-exploitation command execution |
| T1059.003 | Command and Scripting Interpreter: Windows Command Shell | Phase 4 | Post-exploitation command execution |
| T1005 | Data from Local System | Phase 4, 6 | PHI data exfiltration after auth bypass |
| T1530 | Data from Cloud Storage | Phase 6 | Mass access to patient records |
| T1562.001 | Impair Defenses: Disable or Modify Tools | Phase 2, 3 | Sysmon log evasion (CVE-SYNTH-2026-0356) |
| T1070.003 | Indicator Removal: Clear Command History | Phase 4 | Post-exploitation evidence cleanup |
| T1210 | Exploitation of Remote Services | Phase 2 | Deserialization RCE (CVE-SYNTH-2026-0623) |
| T1068 | Exploitation for Privilege Escalation | Phase 2 | Local priv-esc (CVE-SYNTH-2026-0156) |
| T1195.002 | Supply Chain Compromise: Compromise Software Supply Chain | Challenge 3 | Compiler-level supply chain concern |
| T1189 | Drive-by Compromise | Phase 2 | Reflected XSS exploitation (CVE-SYNTH-2026-0445) |
| T1499.003 | Endpoint DoS: Application Exhaustion Flood | Phase 1 | HTTP/2 rapid reset DoS (CVE-SYNTH-2026-0553) |
| T1110.001 | Brute Force: Password Guessing | Phase 4 | Rate limiting on auth endpoints |
Cross-References¶
Related Chapters¶
| Chapter | Relevance |
|---|---|
| Chapter 29: Vulnerability Management | Core vulnerability management lifecycle — scanning, assessment, remediation |
| Chapter 53: Zero-Day Response | Zero-day incident response procedures — virtual patching, emergency remediation |
| Chapter 24: Supply Chain Security | Third-party library vulnerabilities — dependency management, SBOM |
| Chapter 5: Detection Engineering at Scale | KQL/SPL detection query development methodology |
| Chapter 6: SIEM Architecture & Optimization | SIEM query optimization for vulnerability monitoring |
| Chapter 10: Incident Response Engineering | Emergency response procedures for critical vulnerabilities |
Related Labs¶
| Lab | Relevance |
|---|---|
| Lab 18: Threat Hunting with KQL & SPL | KQL/SPL query development fundamentals |
| Lab 28: API Security Testing | API vulnerability assessment — JWT testing |
| Lab 29: Zero Trust Architecture | Authentication and access control validation |
| Lab 3: IR Simulation | Incident response procedures |
Related Scenarios¶
| Scenario | Relevance |
|---|---|
| SC-009 through SC-096 | Attack scenarios involving vulnerability exploitation |
Related Tools¶
| Tool | Relevance |
|---|---|
| Detection Query Browser | Pre-built KQL/SPL detection queries for common vulnerabilities |
| ATT&CK Gap Analysis | Map coverage gaps for vulnerability exploitation techniques |
Lab Revision History¶
| Version | Date | Changes |
|---|---|---|
| 1.0 | 2026-04-12 | Initial release — 6 phases, 50 synthetic vulnerabilities, CVSS v4.0 scoring, virtual patching, deployment automation |