mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-06-15 23:44:56 +03:00
c47eed6a64
- Fix 25 shell=True subprocess calls with list-based commands - Fix 49 verify=False in defensive skills (env-var override) - Add timeout to 231 HTTP/subprocess/socket calls - Fix 6 SQL injection patterns with whitelist validation - Replace 8 __import__() with standard imports - Remove 701 unused imports across 442 files - Add authorized-testing disclaimers to all offensive skills - Complete 11 incomplete skill directories - Expand 10 stub SKILL.md files with full content - Fix 2 YAML parse errors in frontmatter - Fix 5 pre-existing syntax errors - Convert 22 hardcoded paths/ports to environment variables - Back up 21 redundant skill pairs to .bak - Fix 2 global declaration errors - 724/724 skills with full folder anatomy (SKILL.md + agent.py + api-reference.md + LICENSE) - 0 compile errors across all 724 agent.py files
240 lines
8.7 KiB
Python
240 lines
8.7 KiB
Python
#!/usr/bin/env python3
|
|
"""CISA KEV CVE prioritization agent.
|
|
|
|
Downloads the CISA Known Exploited Vulnerabilities (KEV) catalog and
|
|
cross-references it against a list of CVEs from vulnerability scans to
|
|
prioritize remediation based on active exploitation status, due dates,
|
|
and vendor/product impact.
|
|
"""
|
|
import argparse
|
|
import csv
|
|
import io
|
|
import json
|
|
import os
|
|
import sys
|
|
from datetime import datetime, timezone
|
|
|
|
try:
|
|
import requests
|
|
except ImportError:
|
|
print("[!] 'requests' library required: pip install requests", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
KEV_JSON_URL = "https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json"
|
|
|
|
|
|
def download_kev_catalog():
|
|
"""Download the latest CISA KEV catalog as JSON."""
|
|
print(f"[*] Downloading CISA KEV catalog from {KEV_JSON_URL}")
|
|
resp = requests.get(KEV_JSON_URL, timeout=30)
|
|
resp.raise_for_status()
|
|
data = resp.json()
|
|
vulns = data.get("vulnerabilities", [])
|
|
catalog_version = data.get("catalogVersion", "unknown")
|
|
count = data.get("count", len(vulns))
|
|
date_released = data.get("dateReleased", "unknown")
|
|
print(f"[+] KEV catalog v{catalog_version}: {count} vulnerabilities "
|
|
f"(released: {date_released})")
|
|
return vulns, {
|
|
"catalog_version": catalog_version,
|
|
"count": count,
|
|
"date_released": date_released,
|
|
}
|
|
|
|
|
|
def build_kev_index(kev_vulns):
|
|
"""Build a lookup dict keyed by CVE ID for fast matching."""
|
|
index = {}
|
|
for vuln in kev_vulns:
|
|
cve_id = vuln.get("cveID", "")
|
|
if cve_id:
|
|
index[cve_id.upper()] = {
|
|
"cve_id": cve_id,
|
|
"vendor": vuln.get("vendorProject", ""),
|
|
"product": vuln.get("product", ""),
|
|
"vulnerability_name": vuln.get("vulnerabilityName", ""),
|
|
"date_added": vuln.get("dateAdded", ""),
|
|
"short_description": vuln.get("shortDescription", ""),
|
|
"required_action": vuln.get("requiredAction", ""),
|
|
"due_date": vuln.get("dueDate", ""),
|
|
"known_ransomware_campaign": vuln.get("knownRansomwareCampaignUse", "Unknown"),
|
|
"notes": vuln.get("notes", ""),
|
|
}
|
|
return index
|
|
|
|
|
|
def load_cve_list(source):
|
|
"""Load CVE list from file (one CVE per line or CSV) or comma-separated string."""
|
|
cves = []
|
|
if os.path.isfile(source):
|
|
with open(source, "r") as f:
|
|
content = f.read()
|
|
for line in content.strip().splitlines():
|
|
line = line.strip().strip(",").strip('"')
|
|
if line.upper().startswith("CVE-"):
|
|
cves.append(line.upper())
|
|
elif "," in line:
|
|
parts = line.split(",")
|
|
for part in parts:
|
|
part = part.strip().strip('"')
|
|
if part.upper().startswith("CVE-"):
|
|
cves.append(part.upper())
|
|
else:
|
|
for part in source.split(","):
|
|
part = part.strip()
|
|
if part.upper().startswith("CVE-"):
|
|
cves.append(part.upper())
|
|
return list(set(cves))
|
|
|
|
|
|
def prioritize_cves(cve_list, kev_index):
|
|
"""Cross-reference CVEs against KEV catalog and prioritize."""
|
|
in_kev = []
|
|
not_in_kev = []
|
|
|
|
for cve_id in cve_list:
|
|
kev_entry = kev_index.get(cve_id)
|
|
if kev_entry:
|
|
entry = dict(kev_entry)
|
|
entry["in_kev"] = True
|
|
entry["priority"] = "CRITICAL"
|
|
if entry.get("known_ransomware_campaign", "").lower() == "known":
|
|
entry["priority"] = "CRITICAL-RANSOMWARE"
|
|
try:
|
|
due = datetime.strptime(entry["due_date"], "%Y-%m-%d")
|
|
if due < datetime.now():
|
|
entry["overdue"] = True
|
|
entry["priority"] = "CRITICAL-OVERDUE"
|
|
else:
|
|
entry["overdue"] = False
|
|
except (ValueError, KeyError):
|
|
entry["overdue"] = False
|
|
in_kev.append(entry)
|
|
else:
|
|
not_in_kev.append({
|
|
"cve_id": cve_id,
|
|
"in_kev": False,
|
|
"priority": "STANDARD",
|
|
})
|
|
|
|
# Sort: overdue first, then ransomware, then by due date
|
|
priority_order = {"CRITICAL-OVERDUE": 0, "CRITICAL-RANSOMWARE": 1, "CRITICAL": 2}
|
|
in_kev.sort(key=lambda x: (priority_order.get(x["priority"], 9), x.get("due_date", "")))
|
|
|
|
return in_kev, not_in_kev
|
|
|
|
|
|
def format_summary(in_kev, not_in_kev, total_cves, catalog_info):
|
|
"""Print a human-readable prioritization report."""
|
|
print(f"\n{'='*60}")
|
|
print(f" CISA KEV CVE Prioritization Report")
|
|
print(f"{'='*60}")
|
|
print(f" KEV Catalog : v{catalog_info['catalog_version']} "
|
|
f"({catalog_info['count']} total KEVs)")
|
|
print(f" Input CVEs : {total_cves}")
|
|
print(f" In KEV : {len(in_kev)} (actively exploited)")
|
|
print(f" Not in KEV : {len(not_in_kev)}")
|
|
|
|
overdue = [v for v in in_kev if v.get("overdue")]
|
|
ransomware = [v for v in in_kev if "RANSOMWARE" in v.get("priority", "")]
|
|
|
|
print(f"\n Priority Breakdown:")
|
|
print(f" CRITICAL-OVERDUE : {len(overdue)}")
|
|
print(f" CRITICAL-RANSOMWARE : {len(ransomware)}")
|
|
print(f" CRITICAL (in KEV) : {len(in_kev)}")
|
|
print(f" STANDARD (not in KEV): {len(not_in_kev)}")
|
|
|
|
if in_kev:
|
|
print(f"\n KEV-Listed CVEs (prioritize remediation):")
|
|
for v in in_kev[:20]:
|
|
overdue_flag = " [OVERDUE]" if v.get("overdue") else ""
|
|
ransomware_flag = " [RANSOMWARE]" if "RANSOMWARE" in v.get("priority", "") else ""
|
|
print(f" {v['cve_id']:18s} | Due: {v.get('due_date', 'N/A'):10s} | "
|
|
f"{v.get('vendor', ''):15s} | {v.get('product', ''):20s}"
|
|
f"{overdue_flag}{ransomware_flag}")
|
|
if v.get("required_action"):
|
|
print(f" Action: {v['required_action'][:70]}")
|
|
|
|
|
|
def kev_stats(kev_vulns):
|
|
"""Compute statistics about the KEV catalog."""
|
|
by_vendor = {}
|
|
ransomware_count = 0
|
|
for v in kev_vulns:
|
|
vendor = v.get("vendorProject", "Unknown")
|
|
by_vendor[vendor] = by_vendor.get(vendor, 0) + 1
|
|
if v.get("knownRansomwareCampaignUse", "").lower() == "known":
|
|
ransomware_count += 1
|
|
|
|
print(f"\n KEV Catalog Statistics:")
|
|
print(f" Total vulnerabilities : {len(kev_vulns)}")
|
|
print(f" Ransomware-associated : {ransomware_count}")
|
|
print(f" Top vendors:")
|
|
for vendor, count in sorted(by_vendor.items(), key=lambda x: -x[1])[:10]:
|
|
print(f" {vendor:30s}: {count}")
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(
|
|
description="CISA KEV CVE prioritization agent"
|
|
)
|
|
parser.add_argument("--cves", required=True,
|
|
help="CVE list: comma-separated string or path to file")
|
|
parser.add_argument("--kev-file",
|
|
help="Path to local KEV JSON (skip download)")
|
|
parser.add_argument("--stats", action="store_true",
|
|
help="Show KEV catalog statistics")
|
|
parser.add_argument("--output", "-o", help="Output JSON report path")
|
|
parser.add_argument("--verbose", "-v", action="store_true")
|
|
args = parser.parse_args()
|
|
|
|
if args.kev_file:
|
|
print(f"[*] Loading local KEV file: {args.kev_file}")
|
|
with open(args.kev_file, "r") as f:
|
|
data = json.load(f)
|
|
kev_vulns = data.get("vulnerabilities", [])
|
|
catalog_info = {
|
|
"catalog_version": data.get("catalogVersion", "local"),
|
|
"count": len(kev_vulns),
|
|
"date_released": data.get("dateReleased", "unknown"),
|
|
}
|
|
else:
|
|
kev_vulns, catalog_info = download_kev_catalog()
|
|
|
|
if args.stats:
|
|
kev_stats(kev_vulns)
|
|
|
|
kev_index = build_kev_index(kev_vulns)
|
|
cve_list = load_cve_list(args.cves)
|
|
print(f"[*] Loaded {len(cve_list)} CVE(s) to check")
|
|
|
|
in_kev, not_in_kev = prioritize_cves(cve_list, kev_index)
|
|
format_summary(in_kev, not_in_kev, len(cve_list), catalog_info)
|
|
|
|
report = {
|
|
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
"tool": "CISA KEV Prioritization",
|
|
"catalog_info": catalog_info,
|
|
"input_cve_count": len(cve_list),
|
|
"kev_matched": len(in_kev),
|
|
"kev_unmatched": len(not_in_kev),
|
|
"prioritized": in_kev,
|
|
"standard_priority": not_in_kev,
|
|
"risk_level": (
|
|
"CRITICAL" if any(v.get("overdue") for v in in_kev)
|
|
else "HIGH" if in_kev
|
|
else "LOW"
|
|
),
|
|
}
|
|
|
|
if args.output:
|
|
with open(args.output, "w") as f:
|
|
json.dump(report, f, indent=2)
|
|
print(f"\n[+] Report saved to {args.output}")
|
|
elif args.verbose:
|
|
print(json.dumps(report, indent=2))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|