
Building Patch Tuesday Response Process
- 1 installs
- 27.3k repo stars
- Updated August 2, 2026
- mukul975/anthropic-cybersecurity-skills
Establish a structured process to triage, test, and deploy Microsoft Patch Tuesday updates within risk-based remediation SLAs using WSUS/SCCM.
About
Defines an operational process for triaging, testing, and deploying monthly Microsoft Patch Tuesday security updates within risk-based SLAs. A security team uses it to manage Windows vulnerability remediation via WSUS/SCCM and Windows Update.
- Risk-based remediation SLAs for patch triage and deployment
- Maps to NIST CSF and MITRE ATT&CK vulnerability techniques
Building Patch Tuesday Response Process by the numbers
- 1 all-time installs (skills.sh)
- Ranked #1,835 of 2,203 Security skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/mukul975/anthropic-cybersecurity-skills --skill building-patch-tuesday-response-processAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1 |
|---|---|
| repo stars | ★ 27.3k |
| Last updated | August 2, 2026 |
| Repository | mukul975/anthropic-cybersecurity-skills ↗ |
What it does
Establish a structured process to triage, test, and deploy Microsoft Patch Tuesday updates within risk-based remediation SLAs using WSUS/SCCM.
Files
Building Patch Tuesday Response Process
Overview
Microsoft releases security updates on the second Tuesday of each month ("Patch Tuesday"), addressing vulnerabilities across Windows, Office, Exchange, SQL Server, Azure services, and other products. In 2025, Microsoft patched over 1,129 vulnerabilities across the year -- an 11.9% increase from 2024 -- making a structured response process critical. The leading risk types include elevation of privilege (49%), remote code execution (34%), and information disclosure (7%). This skill covers building a repeatable Patch Tuesday response workflow from initial advisory review through testing, deployment, and validation.
When to Use
- When deploying or configuring building patch tuesday response process capabilities in your environment
- When establishing security controls aligned to compliance requirements
- When building or improving security architecture for this domain
- When conducting security assessments that require this implementation
Prerequisites
- Access to Microsoft Security Response Center (MSRC) update guide
- Vulnerability management platform (Qualys VMDR, Rapid7, Tenable)
- Patch deployment infrastructure (WSUS, SCCM/MECM, Intune, or third-party)
- Test environment mirroring production configurations
- Change management process (ITIL-based or equivalent)
- Communication channels for cross-team coordination
Core Concepts
Patch Tuesday Timeline
| Day | Activity | Owner |
|---|---|---|
| T+0 (Tuesday 10 AM PT) | Microsoft releases patches and advisories | Microsoft |
| T+0 (Tuesday afternoon) | Security team reviews advisories and triages | Security Ops |
| T+1 (Wednesday) | Qualys/vendor scan signatures updated | VM Platform |
| T+1-T+2 | Emergency patches deployed for zero-days | IT Operations |
| T+2-T+5 | Test patches in staging environment | QA/IT Ops |
| T+5-T+7 | Deploy to Pilot group (5-10% of fleet) | IT Operations |
| T+7-T+14 | Deploy to Production Ring 1 (servers) | IT Operations |
| T+14-T+21 | Deploy to Production Ring 2 (workstations) | IT Operations |
| T+21-T+30 | Validation scanning and compliance reporting | Security Ops |
Patch Categorization Framework
| Category | Criteria | Response SLA |
|---|---|---|
| Zero-Day / Exploited | Active exploitation confirmed, CISA KEV listed | 24-48 hours |
| Critical RCE | CVSS >= 9.0, remote code execution, no auth required | 3-5 days |
| Critical with Exploit | Public exploit code or EPSS > 0.7 | 7 days |
| High Severity | CVSS 7.0-8.9, privilege escalation | 14 days |
| Medium Severity | CVSS 4.0-6.9 | 30 days |
| Low / Informational | CVSS < 4.0, defense-in-depth | Next maintenance window |
Microsoft Product Categories to Monitor
| Category | Products | Risk Level |
|---|---|---|
| Windows OS | Windows 10, 11, Server 2016-2025 | Critical |
| Exchange Server | Exchange 2016, 2019, Online | Critical |
| SQL Server | SQL 2016-2022 | High |
| Office Suite | Microsoft 365, Office 2019-2024 | High |
| .NET Framework | .NET 4.x, .NET 6-9 | Medium |
| Azure Services | Azure AD, Entra ID, Azure Stack | High |
| Edge/Browser | Edge Chromium, IE mode | Medium |
| Development Tools | Visual Studio, VS Code | Low |
Workflow
Step 1: Pre-Patch Tuesday Preparation (Monday before)
Preparation Checklist:
[ ] Confirm WSUS/SCCM sync schedules are active
[ ] Verify test environment is available and current
[ ] Review outstanding patches from previous month
[ ] Confirm monitoring dashboards are operational
[ ] Pre-stage communication templates
[ ] Ensure rollback procedures are documented
[ ] Verify backup jobs ran successfully on critical serversStep 2: Day-of Triage (Patch Tuesday)
Triage Process:
1. Monitor MSRC Update Guide (https://msrc.microsoft.com/update-guide)
2. Review Microsoft Security Blog for advisory summaries
3. Cross-reference with CISA KEV additions (same day)
4. Check vendor advisories (Qualys, Rapid7, CrowdStrike analysis)
5. Identify zero-day and actively exploited vulnerabilities
6. Classify each CVE by severity and applicability
7. Determine deployment rings and timeline for each patch
8. Submit emergency change request for zero-day patches
9. Communicate triage results to IT Operations and managementStep 3: Scan and Gap Analysis
# Post-Patch-Tuesday scan workflow
def run_patch_tuesday_scan(scanner_api, target_groups):
"""Trigger vulnerability scans after Patch Tuesday updates."""
for group in target_groups:
print(f"[*] Scanning {group['name']}...")
scan_id = scanner_api.launch_scan(
target=group["targets"],
template="patch-tuesday-focused",
credentials=group["creds"]
)
print(f" Scan launched: {scan_id}")
# Wait for scan completion, then generate report
results = scanner_api.get_scan_results(scan_id)
missing_patches = [r for r in results if r["status"] == "missing"]
# Categorize by Patch Tuesday release
current_month = [p for p in missing_patches
if p["vendor_advisory_date"] >= patch_tuesday_date]
return {
"total_missing": len(missing_patches),
"current_month": len(current_month),
"zero_day": [p for p in current_month if p.get("actively_exploited")],
"critical": [p for p in current_month if p["cvss"] >= 9.0],
}Step 4: Ring-Based Deployment Strategy
Ring 0 - Emergency (0-48 hours):
Scope: Zero-day and actively exploited CVEs only
Method: Manual or targeted push (SCCM expedite)
Targets: Internet-facing servers, critical infrastructure
Approval: Emergency change, verbal CISO approval
Rollback: Immediate rollback if service degradation
Ring 1 - Pilot (Day 2-7):
Scope: All critical and high patches
Method: WSUS/SCCM automatic deployment
Targets: IT department machines, test group (5-10%)
Approval: Standard change with CAB notification
Monitoring: 48-hour soak period, check for BSOD, app crashes
Ring 2 - Production Servers (Day 7-14):
Scope: All security patches
Method: SCCM maintenance windows (off-hours)
Targets: Production servers by tier
Approval: Standard change with CAB approval
Monitoring: Application health checks, performance baseline
Ring 3 - Workstations (Day 14-21):
Scope: All security patches + quality updates
Method: Windows Update for Business / Intune
Targets: All managed workstations
Approval: Pre-approved standard change
Monitoring: Help desk ticket monitoring for issues
Ring 4 - Stragglers (Day 21-30):
Scope: Catch remaining unpatched systems
Method: Forced deployment with restart
Targets: Systems that missed prior rings
Approval: Compliance-driven enforcementStep 5: Validation and Reporting
Post-Deployment Validation:
1. Re-scan environment with updated vulnerability signatures
2. Compare pre-patch and post-patch scan results
3. Calculate patch compliance rate per ring and department
4. Identify failed patches and investigate root causes
5. Generate compliance report for management review
6. Update risk register with residual unpatched vulnerabilities
7. Document exceptions and compensating controlsBest Practices
1. Subscribe to MSRC notifications and vendor analysis blogs for early intelligence 2. Maintain a dedicated Patch Tuesday war room or Slack/Teams channel 3. Always patch zero-day vulnerabilities outside the normal ring schedule 4. Test patches against critical business applications before broad deployment 5. Track patch compliance metrics month-over-month for trend analysis 6. Maintain rollback procedures for every deployment ring 7. Coordinate with application owners for compatibility testing 8. Document all exceptions with compensating controls and review dates
Common Pitfalls
- Deploying all patches simultaneously without ring-based testing
- Not scanning after patching to validate remediation
- Treating all patches equally without risk-based prioritization
- Ignoring cumulative update dependencies causing patch failures
- Not accounting for server reboot requirements in maintenance windows
- Failing to communicate patch status to business stakeholders
Related Skills
- implementing-rapid7-insightvm-for-scanning
- performing-cve-prioritization-with-kev-catalog
- implementing-vulnerability-remediation-sla
- implementing-patch-management-workflow
Patch Tuesday Response Report Template
Monthly Patch Summary
| Field | Value |
|---|---|
| Patch Tuesday Date | [YYYY-MM-DD] |
| Total CVEs Released | [N] |
| Zero-Days | [N] |
| Critical | [N] |
| Important | [N] |
| Moderate | [N] |
Deployment Status by Ring
| Ring | Name | SLA | Patches | Deployed | Compliance |
|---|---|---|---|---|---|
| 0 | Emergency | 48h | [N] | [N] | [%] |
| 1 | Pilot | 7 days | [N] | [N] | [%] |
| 2 | Production | 14 days | [N] | [N] | [%] |
| 3 | Workstations | 21 days | [N] | [N] | [%] |
| 4 | Stragglers | 30 days | [N] | [N] | [%] |
Zero-Day / Actively Exploited Patches
| CVE | Product | CVSS | KEV | Status | Deployed |
|---|---|---|---|---|---|
| [CVE-ID] | [Product] | [N.N] | [Y/N] | [Deployed/Pending] | [Date] |
Exceptions and Deferrals
| CVE | Reason | Compensating Control | Review Date | Approver |
|---|---|---|---|---|
| [CVE-ID] | [Reason] | [Control] | [Date] | [Name] |
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to the Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by the Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding any notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. Please do not remove or change
the license header comment from a contributed file except when
necessary.
Copyright 2026 mukul975
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
API Reference: Patch Tuesday Response Process
MSRC Security Update API
GET https://api.msrc.microsoft.com/cvrf/v3.0/Updates('{yyyy-Mon}')
api-key: YOUR_MSRC_KEY
Accept: application/jsonCVRF Vulnerability Fields
| Field | Description |
|---|---|
CVE | CVE identifier |
Title.Value | Vulnerability title |
Threats[].Description.Value | Severity, exploitation status |
CVSSScoreSets[].BaseScore | CVSS v3 base score |
ProductStatuses[].ProductID | Affected product IDs |
Remediations[].URL | KB article / patch URL |
CISA Known Exploited Vulnerabilities (KEV)
GET https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.jsonKEV Entry Fields
| Field | Description |
|---|---|
cveID | CVE identifier |
vendorProject | Vendor name |
product | Product name |
dateAdded | Date added to KEV |
dueDate | Remediation due date |
Patch Priority Matrix
| Priority | Criteria | SLA |
|---|---|---|
| Emergency | Exploited + KEV + CVSS >= 9.0 | 24 hours |
| Critical | Exploited OR KEV + CVSS >= 7.0 | 72 hours |
| Standard | CVSS >= 7.0, no exploitation | 7 days |
| Routine | CVSS < 7.0, no exploitation | 30 days |
NVD API v2
GET https://services.nvd.nist.gov/rest/json/cves/2.0?cveId={CVE-ID}
apiKey: YOUR_NVD_KEYWSUS Deployment API (PowerShell)
$wsus = Get-WsusServer
$update = $wsus.SearchUpdates("KB5034441")
$group = $wsus.GetComputerTargetGroup("Production")
$update.Approve("Install", $group)Deployment Phase Timeline
| Phase | Window | Targets |
|---|---|---|
| Emergency | 0-24h | Critical servers, exploited CVEs |
| Pilot | 24-72h | Test group (5% of fleet) |
| Broad | 3-7d | All production systems |
| Cleanup | 7-30d | Exceptions, rollback monitoring |
Standards and References - Patch Tuesday Response Process
Microsoft Resources
- MSRC Security Update Guide: https://msrc.microsoft.com/update-guide
- Microsoft Security Blog: https://www.microsoft.com/en-us/security/blog/
- Windows Update for Business: https://learn.microsoft.com/en-us/windows/deployment/update/waas-manage-updates-wufb
- SCCM/MECM Patch Management: https://learn.microsoft.com/en-us/mem/configmgr/sum/
Industry Standards
- NIST SP 800-40 Rev 4: Guide to Enterprise Patch Management Planning
- CIS Controls v8.1 Control 7.4: Perform Automated Patch Management
- PCI DSS v4.0 Req 6.3.3: Install security patches within one month of release
- ISO 27001:2022 A.8.8: Management of technical vulnerabilities
Patch Tuesday Statistics (2025)
| Metric | Value |
|---|---|
| Total CVEs patched in 2025 | 1,129 |
| Year-over-year increase | 11.9% |
| Average CVEs per month | ~94 |
| Top category: Elevation of Privilege | ~49% |
| Top category: Remote Code Execution | ~34% |
| Zero-days patched in 2025 | Multiple per quarter |
Vendor Analysis Resources
- Qualys Patch Tuesday Blog: https://blog.qualys.com/tag/patch-tuesday
- Tenable Patch Tuesday Analysis: https://www.tenable.com/blog/tag/patch-tuesday
- CrowdStrike Patch Tuesday: https://www.crowdstrike.com/blog/tag/patch-tuesday
- SANS ISC Patch Tuesday Dashboard: https://isc.sans.edu/patchtuesday/
Workflows - Patch Tuesday Response Process
Workflow 1: Monthly Patch Tuesday Lifecycle
Week 1 (Patch Tuesday):
Mon: Pre-staging, verify infrastructure readiness
Tue: Patch release, triage, zero-day emergency deployment
Wed: Scan environment, update signatures, gap analysis
Thu: Begin pilot deployment (Ring 1)
Fri: Monitor pilot, document issues
Week 2:
Mon-Wed: Production server deployment (Ring 2)
Thu-Fri: Monitor server health, rollback if needed
Week 3:
Mon-Fri: Workstation deployment (Ring 3)
Week 4:
Mon-Wed: Catch stragglers (Ring 4)
Thu: Validation scanning
Fri: Compliance report, close change ticketsWorkflow 2: Zero-Day Emergency Response
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ Zero-Day CVE │────>│ CISO Approves │────>│ Emergency Change │
│ Identified │ │ Emergency Patch │ │ Ticket Created │
└──────────────────┘ └──────────────────┘ └──────────────────┘
│
┌────────────────────────────────────────────────┘
v
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ Quick Smoke Test │────>│ Deploy to Ring 0 │────>│ Monitor for │
│ (1-2 hours) │ │ (Critical Assets)│ │ Issues (4 hours) │
└──────────────────┘ └──────────────────┘ └──────────────────┘
│
v
┌──────────────────┐ ┌──────────────────┐
│ Broader Rollout │────>│ Validation Scan │
│ (All Rings) │ │ & Report │
└──────────────────┘ └──────────────────┘Workflow 3: Patch Compliance Tracking
| Metric | Target | Measurement |
|---|---|---|
| Zero-day patch rate | 100% in 48 hours | SCCM compliance report |
| Critical patch rate | 95% in 7 days | Vulnerability scan delta |
| High patch rate | 90% in 14 days | Vulnerability scan delta |
| Overall compliance | 95% in 30 days | Monthly compliance dashboard |
| Exception documentation | 100% documented | GRC platform audit |
#!/usr/bin/env python3
"""Patch Tuesday Response Agent - Tracks Microsoft patches, assesses risk, and prioritizes deployment."""
import json
import logging
import argparse
from datetime import datetime
import requests
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
logger = logging.getLogger(__name__)
MSRC_API_BASE = "https://api.msrc.microsoft.com/cvrf/v3.0"
def fetch_patch_tuesday_updates(api_key, year_month):
"""Fetch Microsoft Security Update Guide data via MSRC API."""
headers = {"api-key": api_key, "Accept": "application/json"}
resp = requests.get(f"{MSRC_API_BASE}/Updates('{year_month}')", headers=headers, timeout=30)
resp.raise_for_status()
data = resp.json()
logger.info("Fetched MSRC update for %s", year_month)
return data
def parse_vulnerabilities(cvrf_data):
"""Parse CVRF data to extract vulnerability details."""
vulns = []
for vuln in cvrf_data.get("Vulnerability", []):
cve_id = vuln.get("CVE", "")
title = vuln.get("Title", {}).get("Value", "")
severity = "unknown"
cvss_score = 0.0
exploited = False
for threat in vuln.get("Threats", []):
desc = threat.get("Description", {}).get("Value", "")
if "Exploited:Yes" in desc:
exploited = True
if threat.get("Type") == 3:
severity = desc
for score_set in vuln.get("CVSSScoreSets", []):
base = score_set.get("BaseScore", 0.0)
if base > cvss_score:
cvss_score = base
affected_products = []
for product_status in vuln.get("ProductStatuses", []):
for pid in product_status.get("ProductID", []):
affected_products.append(pid)
vulns.append({
"cve": cve_id, "title": title, "severity": severity,
"cvss_score": cvss_score, "exploited_in_wild": exploited,
"affected_product_ids": affected_products[:10],
})
logger.info("Parsed %d vulnerabilities", len(vulns))
return vulns
def check_cisa_kev(cve_list):
"""Check CVEs against CISA Known Exploited Vulnerabilities catalog."""
try:
resp = requests.get("https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json", timeout=15)
resp.raise_for_status()
kev_data = resp.json()
kev_cves = {v["cveID"] for v in kev_data.get("vulnerabilities", [])}
in_kev = [cve for cve in cve_list if cve in kev_cves]
logger.info("Found %d CVEs in CISA KEV", len(in_kev))
return in_kev
except requests.RequestException as e:
logger.warning("Failed to check CISA KEV: %s", e)
return []
def prioritize_patches(vulns, kev_cves):
"""Prioritize patches based on CVSS, exploitation status, and CISA KEV."""
for vuln in vulns:
priority_score = 0
if vuln["exploited_in_wild"]:
priority_score += 40
if vuln["cve"] in kev_cves:
priority_score += 30
if vuln["cvss_score"] >= 9.0:
priority_score += 20
elif vuln["cvss_score"] >= 7.0:
priority_score += 10
if vuln["severity"].lower() == "critical":
priority_score += 10
vuln["priority_score"] = priority_score
if priority_score >= 60:
vuln["deployment_urgency"] = "emergency"
vuln["sla_hours"] = 24
elif priority_score >= 40:
vuln["deployment_urgency"] = "critical"
vuln["sla_hours"] = 72
elif priority_score >= 20:
vuln["deployment_urgency"] = "standard"
vuln["sla_hours"] = 168
else:
vuln["deployment_urgency"] = "routine"
vuln["sla_hours"] = 720
return sorted(vulns, key=lambda v: v["priority_score"], reverse=True)
def generate_deployment_plan(prioritized_vulns):
"""Generate phased deployment plan."""
phases = {"emergency_24h": [], "critical_72h": [], "standard_7d": [], "routine_30d": []}
for vuln in prioritized_vulns:
urgency = vuln.get("deployment_urgency", "routine")
entry = {"cve": vuln["cve"], "title": vuln["title"], "cvss": vuln["cvss_score"],
"exploited": vuln["exploited_in_wild"]}
if urgency == "emergency":
phases["emergency_24h"].append(entry)
elif urgency == "critical":
phases["critical_72h"].append(entry)
elif urgency == "standard":
phases["standard_7d"].append(entry)
else:
phases["routine_30d"].append(entry)
return phases
def generate_report(vulns, kev_cves, deployment_plan, year_month):
"""Generate Patch Tuesday response report."""
report = {
"timestamp": datetime.utcnow().isoformat(),
"patch_tuesday": year_month,
"total_vulnerabilities": len(vulns),
"actively_exploited": sum(1 for v in vulns if v.get("exploited_in_wild")),
"in_cisa_kev": len(kev_cves),
"critical_cvss": sum(1 for v in vulns if v.get("cvss_score", 0) >= 9.0),
"deployment_plan": deployment_plan,
"top_10_priority": [{"cve": v["cve"], "title": v["title"], "cvss": v["cvss_score"],
"exploited": v["exploited_in_wild"], "priority": v["priority_score"]}
for v in vulns[:10]],
}
print(f"PATCH TUESDAY REPORT ({year_month}): {len(vulns)} vulns, "
f"{report['actively_exploited']} exploited, {len(kev_cves)} in KEV")
return report
def main():
parser = argparse.ArgumentParser(description="Patch Tuesday Response Process Agent")
parser.add_argument("--api-key", required=True, help="MSRC API key")
parser.add_argument("--month", required=True, help="Year-Month (e.g., 2024-Jan)")
parser.add_argument("--output", default="patch_tuesday_report.json")
args = parser.parse_args()
cvrf_data = fetch_patch_tuesday_updates(args.api_key, args.month)
vulns = parse_vulnerabilities(cvrf_data)
cve_list = [v["cve"] for v in vulns]
kev_cves = check_cisa_kev(cve_list)
prioritized = prioritize_patches(vulns, set(kev_cves))
deployment_plan = generate_deployment_plan(prioritized)
report = generate_report(prioritized, kev_cves, deployment_plan, args.month)
with open(args.output, "w") as f:
json.dump(report, f, indent=2)
logger.info("Report saved to %s", args.output)
if __name__ == "__main__":
main()
#!/usr/bin/env python3
"""
Patch Tuesday Response Automation Tool
Fetches Microsoft Patch Tuesday advisory data, cross-references with
CISA KEV, and generates a prioritized deployment plan.
Requirements:
pip install requests pandas
Usage:
python process.py fetch --month 2025-12 # Fetch patches for month
python process.py analyze --month 2025-12 # Analyze and prioritize
python process.py plan --month 2025-12 --output deployment_plan.csv
"""
import argparse
import json
import sys
from datetime import datetime
import pandas as pd
import requests
MSRC_API = "https://api.msrc.microsoft.com/cvrf/v3.0/cvrf"
MSRC_UPDATES_API = "https://api.msrc.microsoft.com/cvrf/v3.0/updates"
KEV_URL = "https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json"
EPSS_API = "https://api.first.org/data/v1/epss"
class PatchTuesdayAnalyzer:
"""Analyze and prioritize Patch Tuesday security updates."""
SEVERITY_MAP = {
"Critical": 4,
"Important": 3,
"Moderate": 2,
"Low": 1,
}
RING_ASSIGNMENT = {
"zero_day": {"ring": 0, "name": "Emergency", "sla_hours": 48},
"critical_rce": {"ring": 0, "name": "Emergency", "sla_hours": 72},
"critical": {"ring": 1, "name": "Pilot", "sla_hours": 168},
"important": {"ring": 2, "name": "Production", "sla_hours": 336},
"moderate": {"ring": 3, "name": "Workstations", "sla_hours": 504},
"low": {"ring": 4, "name": "Maintenance", "sla_hours": 720},
}
def __init__(self):
self.session = requests.Session()
self.session.headers.update({
"Accept": "application/json",
"User-Agent": "PatchTuesday-Analyzer/1.0"
})
self.kev_catalog = set()
def load_kev_catalog(self):
"""Load CISA KEV catalog for cross-reference."""
try:
response = self.session.get(KEV_URL, timeout=30)
if response.status_code == 200:
data = response.json()
self.kev_catalog = {
v["cveID"] for v in data.get("vulnerabilities", [])
}
print(f"[+] Loaded {len(self.kev_catalog)} CVEs from CISA KEV")
except Exception as e:
print(f"[!] Failed to load KEV: {e}")
def get_epss_scores(self, cve_list):
"""Fetch EPSS scores for CVEs."""
scores = {}
for i in range(0, len(cve_list), 100):
batch = cve_list[i:i + 100]
try:
response = self.session.get(
EPSS_API,
params={"cve": ",".join(batch)},
timeout=30
)
if response.status_code == 200:
for entry in response.json().get("data", []):
scores[entry["cve"]] = float(entry.get("epss", 0))
except Exception as e:
print(f" [!] EPSS error: {e}")
return scores
def classify_patch(self, cve_data):
"""Classify a patch into deployment ring."""
is_exploited = cve_data.get("actively_exploited", False)
in_kev = cve_data.get("cve_id", "") in self.kev_catalog
severity = cve_data.get("severity", "").lower()
attack_type = cve_data.get("attack_type", "").lower()
cvss = float(cve_data.get("cvss_score", 0))
epss = float(cve_data.get("epss_score", 0))
if is_exploited or in_kev:
return self.RING_ASSIGNMENT["zero_day"]
elif severity == "critical" and "remote code execution" in attack_type:
return self.RING_ASSIGNMENT["critical_rce"]
elif severity == "critical" or cvss >= 9.0 or epss > 0.7:
return self.RING_ASSIGNMENT["critical"]
elif severity == "important" or cvss >= 7.0:
return self.RING_ASSIGNMENT["important"]
elif severity == "moderate" or cvss >= 4.0:
return self.RING_ASSIGNMENT["moderate"]
else:
return self.RING_ASSIGNMENT["low"]
def generate_deployment_plan(self, patches):
"""Generate a ring-based deployment plan."""
self.load_kev_catalog()
cve_list = [p["cve_id"] for p in patches if p.get("cve_id")]
epss_scores = self.get_epss_scores(cve_list)
plan = []
for patch in patches:
cve_id = patch.get("cve_id", "")
patch["epss_score"] = epss_scores.get(cve_id, 0)
patch["in_cisa_kev"] = cve_id in self.kev_catalog
ring = self.classify_patch(patch)
plan.append({
"cve_id": cve_id,
"product": patch.get("product", ""),
"severity": patch.get("severity", ""),
"attack_type": patch.get("attack_type", ""),
"cvss_score": patch.get("cvss_score", 0),
"epss_score": round(patch.get("epss_score", 0), 4),
"in_cisa_kev": patch.get("in_cisa_kev", False),
"actively_exploited": patch.get("actively_exploited", False),
"deployment_ring": ring["ring"],
"ring_name": ring["name"],
"sla_hours": ring["sla_hours"],
"kb_article": patch.get("kb_article", ""),
})
df = pd.DataFrame(plan)
df = df.sort_values(["deployment_ring", "cvss_score"],
ascending=[True, False])
return df
def print_summary(self, df):
"""Print deployment plan summary."""
print(f"\n{'=' * 70}")
print("PATCH TUESDAY DEPLOYMENT PLAN")
print(f"{'=' * 70}")
print(f"Total patches: {len(df)}")
print(f"Zero-day/KEV (Ring 0): {len(df[df['deployment_ring'] == 0])}")
print(f"\nBy Severity:")
print(df["severity"].value_counts().to_string())
print(f"\nBy Deployment Ring:")
for ring in sorted(df["deployment_ring"].unique()):
ring_data = df[df["deployment_ring"] == ring]
ring_name = ring_data.iloc[0]["ring_name"]
sla = ring_data.iloc[0]["sla_hours"]
print(f" Ring {ring} ({ring_name}): {len(ring_data)} patches, "
f"SLA: {sla}h")
print(f"\nBy Attack Type:")
print(df["attack_type"].value_counts().head(5).to_string())
def main():
parser = argparse.ArgumentParser(
description="Patch Tuesday Response Automation"
)
subparsers = parser.add_subparsers(dest="command")
plan_p = subparsers.add_parser("plan", help="Generate deployment plan from CSV")
plan_p.add_argument("--csv", required=True, help="Input CSV of patches")
plan_p.add_argument("--output", default="deployment_plan.csv")
args = parser.parse_args()
analyzer = PatchTuesdayAnalyzer()
if args.command == "plan":
df = pd.read_csv(args.csv)
patches = df.to_dict("records")
plan = analyzer.generate_deployment_plan(patches)
analyzer.print_summary(plan)
plan.to_csv(args.output, index=False)
print(f"\n[+] Deployment plan saved to {args.output}")
else:
parser.print_help()
if __name__ == "__main__":
main()