mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-06-12 22:24: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
147 lines
6.5 KiB
Python
147 lines
6.5 KiB
Python
#!/usr/bin/env python3
|
|
"""NERC CIP Compliance Agent - audits critical infrastructure against NERC CIP standards."""
|
|
|
|
import json
|
|
import argparse
|
|
import logging
|
|
import subprocess
|
|
from datetime import datetime
|
|
|
|
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
|
|
logger = logging.getLogger(__name__)
|
|
|
|
NERC_CIP_CONTROLS = {
|
|
"CIP-002": {"name": "BES Cyber System Categorization", "checks": [
|
|
"asset_inventory_complete", "impact_ratings_assigned", "annual_review_documented"
|
|
]},
|
|
"CIP-003": {"name": "Security Management Controls", "checks": [
|
|
"cyber_security_policy_exists", "senior_manager_designated", "delegation_documented"
|
|
]},
|
|
"CIP-004": {"name": "Personnel and Training", "checks": [
|
|
"security_awareness_training", "role_based_training", "personnel_risk_assessment",
|
|
"access_revocation_process"
|
|
]},
|
|
"CIP-005": {"name": "Electronic Security Perimeters", "checks": [
|
|
"esp_defined", "eap_controls_configured", "remote_access_encrypted",
|
|
"interactive_remote_access_mfa"
|
|
]},
|
|
"CIP-006": {"name": "Physical Security", "checks": [
|
|
"physical_security_plan", "visitor_control_program", "psp_access_monitoring"
|
|
]},
|
|
"CIP-007": {"name": "System Security Management", "checks": [
|
|
"ports_services_minimized", "patch_management_process", "malware_prevention",
|
|
"security_event_monitoring", "system_access_controls"
|
|
]},
|
|
"CIP-008": {"name": "Incident Reporting and Response", "checks": [
|
|
"incident_response_plan", "incident_response_testing", "reporting_procedures"
|
|
]},
|
|
"CIP-009": {"name": "Recovery Plans", "checks": [
|
|
"recovery_plans_exist", "backup_procedures", "recovery_testing_annual"
|
|
]},
|
|
"CIP-010": {"name": "Configuration Change Management", "checks": [
|
|
"baseline_configurations", "change_management_process", "vulnerability_assessments"
|
|
]},
|
|
"CIP-011": {"name": "Information Protection", "checks": [
|
|
"information_classification", "bcsi_protection", "bcsi_disposal"
|
|
]},
|
|
"CIP-013": {"name": "Supply Chain Risk Management", "checks": [
|
|
"supply_chain_plan", "vendor_risk_assessment", "vendor_notification_process"
|
|
]},
|
|
}
|
|
|
|
|
|
def check_esp_controls(target_ip=None):
|
|
"""Check Electronic Security Perimeter controls via network scan."""
|
|
findings = []
|
|
if target_ip:
|
|
cmd = ["nmap", "-sS", "-p", "1-1024", "--open", target_ip, "-oX", "-"]
|
|
result = subprocess.run(cmd, capture_output=True, text=True, timeout=120)
|
|
open_ports = result.stdout.count("state=\"open\"")
|
|
if open_ports > 10:
|
|
findings.append({"control": "CIP-005", "issue": f"{open_ports} open ports on ESP boundary",
|
|
"severity": "high"})
|
|
return findings
|
|
|
|
|
|
def check_system_hardening():
|
|
"""Check CIP-007 system hardening controls."""
|
|
findings = []
|
|
svc_cmd = ["systemctl", "list-units", "--type=service", "--state=running", "--no-pager"]
|
|
result = subprocess.run(svc_cmd, capture_output=True, text=True, timeout=120)
|
|
service_count = len([l for l in result.stdout.split("\n") if ".service" in l])
|
|
if service_count > 50:
|
|
findings.append({"control": "CIP-007-R1", "issue": f"{service_count} running services (minimize unused)",
|
|
"severity": "medium"})
|
|
patch_cmd = ["apt", "list", "--upgradable"] if subprocess.run(["which", "apt"], capture_output=True, timeout=120).returncode == 0 else ["yum", "check-update"]
|
|
result = subprocess.run(patch_cmd, capture_output=True, text=True, timeout=120)
|
|
pending = len([l for l in result.stdout.split("\n") if l.strip() and not l.startswith("Listing")])
|
|
if pending > 0:
|
|
findings.append({"control": "CIP-007-R2", "issue": f"{pending} pending security patches",
|
|
"severity": "high"})
|
|
return findings
|
|
|
|
|
|
def audit_compliance_status(evidence_file=None):
|
|
"""Audit compliance status against all NERC CIP controls."""
|
|
evidence = {}
|
|
if evidence_file:
|
|
with open(evidence_file) as f:
|
|
evidence = json.load(f)
|
|
results = {}
|
|
for cip_id, control in NERC_CIP_CONTROLS.items():
|
|
check_results = {}
|
|
for check in control["checks"]:
|
|
status = evidence.get(cip_id, {}).get(check, "not_assessed")
|
|
check_results[check] = status
|
|
passed = sum(1 for v in check_results.values() if v == "pass")
|
|
total = len(check_results)
|
|
results[cip_id] = {
|
|
"name": control["name"],
|
|
"checks": check_results,
|
|
"passed": passed,
|
|
"total": total,
|
|
"compliance_rate": round(passed / max(total, 1) * 100, 1),
|
|
}
|
|
return results
|
|
|
|
|
|
def generate_report(compliance, esp_findings, hardening_findings):
|
|
total_checks = sum(r["total"] for r in compliance.values())
|
|
total_passed = sum(r["passed"] for r in compliance.values())
|
|
all_findings = esp_findings + hardening_findings
|
|
report = {
|
|
"timestamp": datetime.utcnow().isoformat(),
|
|
"framework": "NERC CIP v6/v7",
|
|
"overall_compliance_rate": round(total_passed / max(total_checks, 1) * 100, 1),
|
|
"total_controls_assessed": total_checks,
|
|
"total_passed": total_passed,
|
|
"cip_standard_results": compliance,
|
|
"technical_findings": all_findings,
|
|
"high_severity_findings": len([f for f in all_findings if f.get("severity") == "high"]),
|
|
}
|
|
return report
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="NERC CIP Compliance Audit Agent")
|
|
parser.add_argument("--evidence-file", help="JSON evidence file with control assessment results")
|
|
parser.add_argument("--target-ip", help="ESP boundary IP to scan")
|
|
parser.add_argument("--skip-hardening", action="store_true", help="Skip system hardening checks")
|
|
parser.add_argument("--output", default="nerc_cip_report.json")
|
|
args = parser.parse_args()
|
|
|
|
compliance = audit_compliance_status(args.evidence_file)
|
|
esp_findings = check_esp_controls(args.target_ip) if args.target_ip else []
|
|
hardening = check_system_hardening() if not args.skip_hardening else []
|
|
report = generate_report(compliance, esp_findings, hardening)
|
|
with open(args.output, "w") as f:
|
|
json.dump(report, f, indent=2, default=str)
|
|
logger.info("NERC CIP compliance: %.1f%% (%d/%d), %d findings",
|
|
report["overall_compliance_rate"], report["total_passed"],
|
|
report["total_controls_assessed"], len(report["technical_findings"]))
|
|
print(json.dumps(report, indent=2, default=str))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|