mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-07-20 14:30:59 +03:00
Complete folder anatomy for all 649 cybersecurity skills + update LICENSE to Mahipal
- Add scripts/agent.py and references/api-reference.md to all remaining skills - Update all 648 LICENSE files: copyright now reads 'Mahipal' - Add implementing-security-monitoring-with-datadog (new skill with full anatomy) - All 649 skills now have: SKILL.md, LICENSE, scripts/agent.py, references/api-reference.md
This commit is contained in:
@@ -0,0 +1,149 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Agent for implementing EPSS (Exploit Prediction Scoring System) for vulnerability prioritization."""
|
||||
|
||||
import json
|
||||
import argparse
|
||||
import csv
|
||||
from datetime import datetime
|
||||
from io import StringIO
|
||||
|
||||
try:
|
||||
import requests
|
||||
except ImportError:
|
||||
requests = None
|
||||
|
||||
EPSS_API_URL = "https://api.first.org/data/v1/epss"
|
||||
|
||||
|
||||
def get_epss_scores(cve_list):
|
||||
"""Fetch EPSS scores for a list of CVE IDs from the FIRST.org API."""
|
||||
if not requests:
|
||||
return {"error": "requests library not installed"}
|
||||
results = []
|
||||
# API supports up to 100 CVEs per request
|
||||
for i in range(0, len(cve_list), 100):
|
||||
batch = cve_list[i:i + 100]
|
||||
params = {"cve": ",".join(batch)}
|
||||
resp = requests.get(EPSS_API_URL, params=params, timeout=30)
|
||||
resp.raise_for_status()
|
||||
data = resp.json()
|
||||
for item in data.get("data", []):
|
||||
results.append({
|
||||
"cve": item["cve"],
|
||||
"epss": float(item["epss"]),
|
||||
"percentile": float(item["percentile"]),
|
||||
})
|
||||
return {"total": len(results), "scores": results}
|
||||
|
||||
|
||||
def get_epss_csv():
|
||||
"""Download the full EPSS score CSV from FIRST.org."""
|
||||
if not requests:
|
||||
return {"error": "requests library not installed"}
|
||||
resp = requests.get(f"{EPSS_API_URL}?envelope=true&pretty=true", timeout=60)
|
||||
resp.raise_for_status()
|
||||
return resp.json()
|
||||
|
||||
|
||||
def prioritize_vulnerabilities(cve_scores, epss_threshold=0.1, percentile_threshold=0.9):
|
||||
"""Prioritize vulnerabilities based on EPSS score and percentile."""
|
||||
critical = []
|
||||
high = []
|
||||
medium = []
|
||||
low = []
|
||||
for item in cve_scores:
|
||||
epss = item["epss"]
|
||||
pct = item["percentile"]
|
||||
if epss >= epss_threshold or pct >= percentile_threshold:
|
||||
item["priority"] = "CRITICAL"
|
||||
critical.append(item)
|
||||
elif epss >= 0.05:
|
||||
item["priority"] = "HIGH"
|
||||
high.append(item)
|
||||
elif epss >= 0.01:
|
||||
item["priority"] = "MEDIUM"
|
||||
medium.append(item)
|
||||
else:
|
||||
item["priority"] = "LOW"
|
||||
low.append(item)
|
||||
return {
|
||||
"thresholds": {"epss": epss_threshold, "percentile": percentile_threshold},
|
||||
"summary": {
|
||||
"critical": len(critical),
|
||||
"high": len(high),
|
||||
"medium": len(medium),
|
||||
"low": len(low),
|
||||
},
|
||||
"critical": sorted(critical, key=lambda x: x["epss"], reverse=True),
|
||||
"high": sorted(high, key=lambda x: x["epss"], reverse=True),
|
||||
}
|
||||
|
||||
|
||||
def enrich_from_scan(scan_file, output_file=None):
|
||||
"""Enrich a vulnerability scan CSV with EPSS scores."""
|
||||
with open(scan_file, "r") as f:
|
||||
reader = csv.DictReader(f)
|
||||
rows = list(reader)
|
||||
cve_col = None
|
||||
for col in ["CVE", "cve", "CVE-ID", "cve_id", "vulnerability_id"]:
|
||||
if col in (rows[0] if rows else {}):
|
||||
cve_col = col
|
||||
break
|
||||
if not cve_col:
|
||||
return {"error": "No CVE column found in scan file"}
|
||||
cves = [row[cve_col] for row in rows if row.get(cve_col, "").startswith("CVE-")]
|
||||
if not cves:
|
||||
return {"error": "No CVE IDs found in scan file"}
|
||||
epss_data = get_epss_scores(cves)
|
||||
epss_map = {s["cve"]: s for s in epss_data.get("scores", [])}
|
||||
|
||||
enriched = []
|
||||
for row in rows:
|
||||
cve = row.get(cve_col, "")
|
||||
epss_info = epss_map.get(cve, {})
|
||||
row["epss_score"] = epss_info.get("epss", "N/A")
|
||||
row["epss_percentile"] = epss_info.get("percentile", "N/A")
|
||||
enriched.append(row)
|
||||
|
||||
if output_file:
|
||||
fieldnames = list(enriched[0].keys())
|
||||
with open(output_file, "w", newline="") as f:
|
||||
writer = csv.DictWriter(f, fieldnames=fieldnames)
|
||||
writer.writeheader()
|
||||
writer.writerows(enriched)
|
||||
|
||||
prioritized = prioritize_vulnerabilities(
|
||||
[s for s in epss_data.get("scores", [])]
|
||||
)
|
||||
return {
|
||||
"scan_file": scan_file,
|
||||
"total_cves": len(cves),
|
||||
"enriched_count": sum(1 for r in enriched if r["epss_score"] != "N/A"),
|
||||
"prioritization": prioritized["summary"],
|
||||
"top_10_exploitable": prioritized.get("critical", [])[:10],
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="EPSS Vulnerability Prioritization Agent")
|
||||
sub = parser.add_subparsers(dest="command")
|
||||
s = sub.add_parser("score", help="Get EPSS scores for CVE IDs")
|
||||
s.add_argument("--cves", nargs="+", required=True, help="CVE IDs (e.g., CVE-2024-1234)")
|
||||
e = sub.add_parser("enrich", help="Enrich vulnerability scan with EPSS scores")
|
||||
e.add_argument("--scan-file", required=True, help="CSV vulnerability scan report")
|
||||
e.add_argument("--output", help="Output enriched CSV file")
|
||||
args = parser.parse_args()
|
||||
if args.command == "score":
|
||||
epss = get_epss_scores(args.cves)
|
||||
result = prioritize_vulnerabilities(epss.get("scores", []))
|
||||
result["raw_scores"] = epss["scores"]
|
||||
elif args.command == "enrich":
|
||||
result = enrich_from_scan(args.scan_file, args.output)
|
||||
else:
|
||||
parser.print_help()
|
||||
return
|
||||
print(json.dumps(result, indent=2, default=str))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user