endpoint security

Hardening Windows Endpoint with CIS Benchmark

Hardens Windows endpoints using CIS (Center for Internet Security) Benchmark recommendations to reduce attack surface, enforce security baselines, and meet compliance requirements. Use when deploying new Windows workstations or servers, remediating audit findings, or establishing organization-wide security baselines. Activates for requests involving Windows hardening, CIS benchmarks, GPO security baselines, or endpoint configuration compliance.

baseline-configurationcis-benchmarkendpointgpohardeningwindows-security
Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-Skills
Framework mappings

When to Use

Use this skill when:

  • Deploying new Windows 10/11 or Server 2019/2022 endpoints that require security hardening
  • Establishing organization-wide security baselines using CIS Level 1 or Level 2 profiles
  • Remediating findings from compliance audits (PCI DSS, HIPAA, SOC 2) that reference CIS benchmarks
  • Validating existing endpoint configurations against current CIS benchmark versions

Do not use this skill for Linux endpoints (use hardening-linux-endpoint-with-cis-benchmark) or for cloud-native workloads that require CIS cloud benchmarks.

Prerequisites

  • Windows 10/11 Enterprise or Windows Server 2019/2022 target endpoints
  • Active Directory Group Policy Management Console (GPMC) for enterprise deployment
  • CIS-CAT Pro Assessor or CIS-CAT Lite for automated benchmark assessment
  • Administrative access to target endpoints or domain controller
  • Current CIS Benchmark PDF for the target Windows version (download from cisecurity.org)

Workflow

Step 1: Select CIS Benchmark Profile Level

CIS provides two profile levels for Windows endpoints:

Level 1 (L1) - Corporate/Enterprise Environment:

  • Practical hardening settings that can be applied to most organizations
  • Minimal impact on functionality and user experience
  • Covers: password policy, audit policy, user rights, security options, Windows Firewall

Level 2 (L2) - High Security/Sensitive Data:

  • Includes all L1 settings plus additional restrictions
  • May impact usability (disabling autorun, restricting remote desktop, enhanced audit logging)
  • Appropriate for systems handling PII, PHI, PCI data, or classified information

Select profile based on data classification and risk tolerance of the endpoint.

Step 2: Import CIS GPO Baselines

CIS provides pre-built GPO templates (Build Kits) for each benchmark version:

# Download CIS Build Kit from CIS WorkBench (requires CIS SecureSuite membership)
# Extract the GPO backup to a staging directory
 
# Import the CIS GPO into Active Directory
Import-GPO -BackupGpoName "CIS Microsoft Windows 11 Enterprise v3.0.0 L1" `
  -TargetName "CIS-Win11-L1-Baseline" `
  -Path "C:\CIS-GPO-Backups\Win11-Enterprise" `
  -CreateIfNeeded
 
# Link GPO to target OU
New-GPLink -Name "CIS-Win11-L1-Baseline" `
  -Target "OU=Workstations,DC=corp,DC=example,DC=com" `
  -LinkEnabled Yes

Step 3: Apply Key CIS Benchmark Categories

Account Policies (Section 1):

Password Policy:
  - Minimum password length: 14 characters (1.1.4)
  - Maximum password age: 365 days (1.1.3)
  - Password complexity: Enabled (1.1.5)
  - Store passwords using reversible encryption: Disabled (1.1.6)
 
Account Lockout Policy:
  - Account lockout threshold: 5 invalid logon attempts (1.2.1)
  - Account lockout duration: 15 minutes (1.2.2)
  - Reset account lockout counter after: 15 minutes (1.2.3)

Local Policies - Audit Policy (Section 17):

Audit Policy Configuration:
  - Audit Credential Validation: Success and Failure (17.1.1)
  - Audit Security Group Management: Success (17.2.5)
  - Audit Logon: Success and Failure (17.5.1)
  - Audit Process Creation: Success (17.6.1)
  - Audit Removable Storage: Success and Failure (17.6.4)

Security Options (Section 2.3):

  - Interactive logon: Do not display last user name: Enabled (2.3.7.1)
  - Interactive logon: Machine inactivity limit: 900 seconds (2.3.7.3)
  - Network access: Do not allow anonymous enumeration of SAM accounts: Enabled (2.3.10.2)
  - Network security: LAN Manager authentication level: Send NTLMv2 response only (2.3.11.7)
  - UAC: Run all administrators in Admin Approval Mode: Enabled (2.3.17.6)

Windows Firewall (Section 9):

  - Domain Profile: Firewall state: On (9.1.1)
  - Domain Profile: Inbound connections: Block (9.1.2)
  - Private Profile: Firewall state: On (9.2.1)
  - Public Profile: Firewall state: On (9.3.1)
  - Public Profile: Inbound connections: Block (9.3.2)

Step 4: Validate with CIS-CAT Assessment

# Run CIS-CAT Pro Assessor against target endpoint
# CIS-CAT produces an HTML/XML report with pass/fail per recommendation
 
.\Assessor-CLI.bat `
  -b "benchmarks\CIS_Microsoft_Windows_11_Enterprise_Benchmark_v3.0.0-xccdf.xml" `
  -p "Level 1 (L1) - Corporate/Enterprise Environment" `
  -rd "C:\CIS-Reports" `
  -nts
 
# Review report for failed controls
# Score target: 95%+ for L1, 90%+ for L2 (due to operational exceptions)

Step 5: Document Exceptions and Compensating Controls

For each CIS recommendation that cannot be applied:

  1. Document the specific recommendation ID and title
  2. State the business justification for the exception
  3. Define the compensating control that addresses the residual risk
  4. Set a review date (quarterly) to reassess the exception
  5. Obtain sign-off from the information security officer

Example exception:

Recommendation: 2.3.7.3 - Interactive logon: Machine inactivity limit: 900 seconds
Exception: Kiosk systems in manufacturing floor require 1800 seconds
Compensating Control: Physical badge-access to manufacturing area, CCTV monitoring
Review Date: 2026-06-01
Approved By: CISO

Step 6: Continuous Compliance Monitoring

Configure recurring CIS-CAT scans via scheduled tasks or SCCM:

# Create scheduled task for weekly CIS-CAT assessment
$action = New-ScheduledTaskAction -Execute "C:\CIS-CAT\Assessor-CLI.bat" `
  -Argument "-b benchmarks\CIS_Win11_v3.0.0-xccdf.xml -p Level1 -rd C:\CIS-Reports -nts"
$trigger = New-ScheduledTaskTrigger -Weekly -DaysOfWeek Sunday -At 2am
$principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -RunLevel Highest
Register-ScheduledTask -TaskName "CIS-Benchmark-Scan" -Action $action `
  -Trigger $trigger -Principal $principal

Feed results into SIEM for drift detection and dashboard reporting.

Key Concepts

Term Definition
CIS Benchmark Consensus-based security configuration guide developed by CIS with input from government, industry, and academia
Level 1 Profile Practical security baseline suitable for most organizations with minimal operational impact
Level 2 Profile Extended security baseline for high-security environments that may reduce functionality
CIS-CAT CIS Configuration Assessment Tool that automates benchmark compliance checking
Build Kit Pre-configured GPO templates provided by CIS that implement benchmark recommendations
Scoring CIS recommendations are either Scored (compliance-measurable) or Not Scored (best-practice guidance)

Tools & Systems

  • CIS-CAT Pro Assessor: Automated benchmark compliance scanner (requires CIS SecureSuite license)
  • Microsoft Security Compliance Toolkit (SCT): Microsoft's own GPO baselines (complementary to CIS)
  • Group Policy Management Console (GPMC): Enterprise GPO deployment and management
  • LGPO.exe: Microsoft tool for applying GPOs to standalone (non-domain) systems
  • Nessus/Tenable: Vulnerability scanner with CIS benchmark audit files

Common Pitfalls

  • Applying L2 to all endpoints: Level 2 restrictions (disabling Autoplay, restricting Remote Desktop) break workflows on standard workstations. Reserve L2 for endpoints handling sensitive data.
  • Not testing GPOs in pilot OU: Deploy CIS GPOs to a test OU with representative hardware/software before organization-wide rollout to avoid breaking line-of-business applications.
  • Ignoring CIS benchmark version updates: CIS benchmarks update with each Windows feature release. Running an outdated benchmark misses new security settings and generates false compliance reports.
  • Forgetting local admin accounts: CIS benchmarks assume domain-joined endpoints. Standalone systems require LGPO.exe or Microsoft Intune for baseline enforcement.
  • No exception process: Applying 100% of CIS recommendations is rarely feasible. Without a formal exception process, teams either ignore hardening or break applications.
Source materials

References and resources

Everything below is rendered for inspection. Script files are read-only and never run.

References 3

api-reference.md2.3 KB

API Reference: Windows CIS Benchmark Hardening

CIS Benchmark Sections

Section Topic
1 Account Policies (passwords, lockout)
2 Local Policies (audit, user rights, security options)
9 Windows Firewall
17 Advanced Audit Policy
18 Administrative Templates
19 User Configuration

PowerShell Commands

Password Policy

net accounts
# or
Get-ADDefaultDomainPasswordPolicy

Audit Policy

auditpol /get /category:*

Firewall Status

Get-NetFirewallProfile | Select-Object Name, Enabled

Registry Checks

Get-ItemProperty -Path 'HKLM:\...' -Name 'ValueName'

Key Registry Settings

Path Value Recommended
HKLM\SYSTEM\CurrentControlSet\Control\Lsa\LmCompatibilityLevel DWORD 5 (NTLMv2 only)
HKLM\...\Policies\System\EnableLUA DWORD 1 (UAC enabled)
HKLM\...\LanManServer\Parameters\SMB1 DWORD 0 (disabled)
HKLM\...\Policies\System\ConsentPromptBehaviorAdmin DWORD 2

Password Policy Settings

Setting CIS Recommendation
Minimum length >= 14 characters
Maximum age <= 365 days
Minimum age >= 1 day
Complexity Enabled
Lockout threshold <= 5 attempts
Lockout duration >= 15 minutes

Advanced Audit Policy

Subcategory Recommended
Credential Validation Success and Failure
Logon/Logoff Success and Failure
Account Management Success
Process Creation Success
Policy Change Success

GPO Export and Analysis

Export GPO

gpresult /H gpo-report.html

Secedit Export

secedit /export /cfg security-config.inf

Automated Tools

Microsoft Security Compliance Toolkit

# Download from Microsoft
# Includes GPO baselines and LGPO tool
LGPO.exe /g .\GPO-Backup

CIS-CAT

# CIS Configuration Assessment Tool
cis-cat.bat -b benchmark.xml -p "CIS Windows 11 Enterprise"

Windows Optional Features

Check SMBv1

Get-WindowsOptionalFeature -Online -FeatureName SMB1Protocol

Disable SMBv1

Disable-WindowsOptionalFeature -Online -FeatureName SMB1Protocol
standards.md2.7 KB

Standards & References - Hardening Windows Endpoint with CIS Benchmark

Primary Standards

CIS Microsoft Windows 11 Enterprise Benchmark v3.0.0

CIS Microsoft Windows Server 2022 Benchmark v3.0.0

NIST SP 800-123 - Guide to General Server Security

  • Publisher: NIST
  • Relevance: Foundational server hardening guidance that CIS benchmarks operationalize
  • Key sections: OS hardening, user account management, resource access controls

Compliance Mappings

PCI DSS v4.0 Mapping

PCI DSS Requirement CIS Benchmark Section
2.2 - Develop configuration standards CIS Benchmark entire scope
5.2 - Anti-malware mechanisms Section 18.10 (Windows Defender)
8.3 - Strong authentication Section 1.1 (Password Policy)
10.2 - Audit trail implementation Section 17 (Advanced Audit Policy)

NIST 800-53 Rev 5 Mapping

NIST Control CIS Benchmark Section
CM-6 Configuration Settings Entire CIS Benchmark
AC-2 Account Management Section 1 (Account Policies)
AU-2 Audit Events Section 17 (Advanced Audit Policy)
SC-7 Boundary Protection Section 9 (Windows Firewall)

HIPAA Security Rule Mapping

HIPAA Requirement CIS Benchmark Section
164.312(a)(1) Access Control Section 2.3 (Security Options)
164.312(b) Audit Controls Section 17 (Advanced Audit Policy)
164.312(a)(2)(iv) Encryption BitLocker Profile
164.312(c)(1) Integrity Section 18.9 (Windows Defender)

Supporting References

workflows.md3.5 KB

Workflows - Hardening Windows Endpoint with CIS Benchmark

Workflow 1: Initial Baseline Deployment

[Select Windows Version & CIS Benchmark]


[Choose Profile Level (L1 or L2)]


[Download CIS Build Kit GPOs from CIS WorkBench]


[Import GPOs into Active Directory via GPMC]


[Link GPO to Pilot OU with 5-10 test endpoints]


[Run CIS-CAT assessment on pilot endpoints]

    ├── Score >= 95% ──► [Test application compatibility for 2 weeks]
    │                         │
    │                         ├── No issues ──► [Deploy GPO to production OUs]
    │                         │
    │                         └── Issues found ──► [Document exceptions, add compensating controls]
    │                                                  │
    │                                                  ▼
    │                                              [Redeploy with exceptions]

    └── Score < 95% ──► [Investigate GPO application failures]


                         [Fix WMI filters, security filtering, or GPO precedence]


                         [Re-run CIS-CAT assessment]

Workflow 2: Continuous Compliance Monitoring

[Weekly CIS-CAT Scheduled Scan]


[Parse XML results → ingest into SIEM]


[Compare against baseline score]

    ├── Score drift > 2% ──► [Generate compliance drift alert]
    │                              │
    │                              ▼
    │                         [Identify changed settings via GPResult /H]
    │                              │
    │                              ▼
    │                         [Determine if change was authorized]
    │                              │
    │                              ├── Authorized ──► [Update baseline, document exception]
    │                              │
    │                              └── Unauthorized ──► [Revert change, investigate as security incident]

    └── Score stable ──► [Log compliance status, update dashboard]

Workflow 3: New CIS Benchmark Version Upgrade

[CIS releases new benchmark version]


[Download updated benchmark and Build Kit]


[Diff new vs. current benchmark recommendations]


[Identify new/changed/removed recommendations]


[Impact assessment: Will new settings break applications?]

    ├── Yes ──► [Lab test, document new exceptions]

    └── No ──► [Update GPO with new Build Kit]


               [Deploy to pilot OU first]


               [Run CIS-CAT with new benchmark profile]


               [Production rollout after 2-week pilot]

Workflow 4: Standalone Endpoint Hardening (Non-Domain)

[Identify standalone Windows endpoint]


[Download LGPO.exe from Microsoft SCT]


[Export CIS Build Kit GPO to local policy format]


[Apply via LGPO.exe: LGPO.exe /g C:\CIS-Policy]


[Run CIS-CAT Lite assessment]


[Document results and exceptions]


[Schedule quarterly manual reassessment]

Scripts 2

agent.py5.7 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""Agent for auditing Windows endpoints against CIS Benchmark hardening controls."""

import argparse
import json
import subprocess
import sys
from datetime import datetime, timezone


def run_ps(command, timeout=15):
    """Run PowerShell command and return output."""
    try:
        return subprocess.check_output(
            ["powershell", "-NoProfile", "-Command", command],
            text=True, errors="replace", timeout=timeout
        ).strip()
    except subprocess.SubprocessError:
        return ""


def check_password_policy():
    """CIS 1.1 — Password Policy."""
    findings = []
    result = run_ps("net accounts")
    for line in result.splitlines():
        if "Minimum password length" in line:
            val = int(line.split(":")[-1].strip())
            if val < 14:
                findings.append({"check": "1.1.4", "issue": f"Min password length: {val} (should be >= 14)", "severity": "HIGH"})
        if "Maximum password age" in line:
            val = line.split(":")[-1].strip()
            if val == "Unlimited":
                findings.append({"check": "1.1.2", "issue": "No max password age", "severity": "MEDIUM"})
        if "Lockout threshold" in line:
            val = line.split(":")[-1].strip()
            if val == "Never" or (val.isdigit() and int(val) > 10):
                findings.append({"check": "1.2.1", "issue": f"Account lockout threshold: {val}", "severity": "MEDIUM"})
    return findings


def check_audit_policy():
    """CIS 17 — Advanced Audit Policy."""
    findings = []
    result = run_ps("auditpol /get /category:*")
    required_audits = {
        "Credential Validation": "Success and Failure",
        "Logon": "Success and Failure",
        "Security Group Management": "Success",
        "User Account Management": "Success and Failure",
        "Process Creation": "Success",
    }
    for subcategory, expected in required_audits.items():
        if subcategory in result:
            for line in result.splitlines():
                if subcategory in line:
                    if "No Auditing" in line:
                        findings.append({
                            "check": "17.x", "issue": f"Audit not configured: {subcategory}",
                            "severity": "HIGH",
                        })
    return findings


def check_windows_firewall():
    """CIS 9 — Windows Firewall."""
    findings = []
    profiles = ["Domain", "Private", "Public"]
    for profile in profiles:
        result = run_ps(f"Get-NetFirewallProfile -Name {profile} | Select-Object Enabled | ConvertTo-Json")
        try:
            data = json.loads(result) if result else {}
            if not data.get("Enabled"):
                findings.append({"check": "9.1", "issue": f"Firewall {profile} profile disabled", "severity": "HIGH"})
        except json.JSONDecodeError:
            pass
    return findings


def check_security_options():
    """CIS 2.3 — Security Options."""
    findings = []
    checks = [
        ("HKLM:\\SYSTEM\\CurrentControlSet\\Control\\Lsa", "LmCompatibilityLevel", 5,
         "2.3.11.7", "LAN Manager auth level not NTLMv2 only"),
        ("HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System", "EnableLUA", 1,
         "2.3.17.1", "UAC not enabled"),
        ("HKLM:\\SYSTEM\\CurrentControlSet\\Services\\LanManServer\\Parameters", "SMB1", 0,
         "18.3.2", "SMBv1 not disabled"),
    ]
    for path, name, expected, cis_id, desc in checks:
        result = run_ps(
            f"(Get-ItemProperty -Path '{path}' -Name '{name}' -ErrorAction SilentlyContinue).{name}"
        )
        if result.strip().isdigit() and int(result.strip()) != expected:
            findings.append({"check": cis_id, "issue": desc, "current": result.strip(), "severity": "HIGH"})
    return findings


def check_windows_features():
    """CIS 18 — Windows Features."""
    findings = []
    risky_features = ["SMB1Protocol", "TelnetClient", "TFTP"]
    for feature in risky_features:
        result = run_ps(
            f"Get-WindowsOptionalFeature -Online -FeatureName {feature} 2>$null | "
            f"Select-Object State | ConvertTo-Json"
        )
        try:
            data = json.loads(result) if result else {}
            if data.get("State") == 1:  # Enabled
                findings.append({"check": "18.x", "issue": f"Risky feature enabled: {feature}", "severity": "MEDIUM"})
        except json.JSONDecodeError:
            pass
    return findings


def main():
    parser = argparse.ArgumentParser(
        description="Audit Windows endpoint against CIS Benchmark"
    )
    parser.add_argument("--output", "-o", help="Output JSON report")
    args = parser.parse_args()

    print("[*] Windows CIS Benchmark Hardening Audit Agent")
    if sys.platform != "win32":
        print("[!] This agent requires Windows")
        return

    all_findings = []
    all_findings.extend(check_password_policy())
    all_findings.extend(check_audit_policy())
    all_findings.extend(check_windows_firewall())
    all_findings.extend(check_security_options())
    all_findings.extend(check_windows_features())

    high = sum(1 for f in all_findings if f["severity"] == "HIGH")
    report = {
        "timestamp": datetime.now(timezone.utc).isoformat(),
        "findings": all_findings,
        "total": len(all_findings),
        "high_severity": high,
        "compliance_score": max(0, 100 - len(all_findings) * 5),
    }
    print(f"[*] Findings: {len(all_findings)} (HIGH: {high})")

    if args.output:
        with open(args.output, "w") as f:
            json.dump(report, f, indent=2)
        print(f"[*] Report saved to {args.output}")
    else:
        print(json.dumps(report, indent=2))


if __name__ == "__main__":
    main()
process.py8.2 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""
CIS Benchmark Compliance Processor

Parses CIS-CAT Pro XML assessment results, calculates compliance scores,
identifies failed controls, and generates remediation reports.
"""

import xml.etree.ElementTree as ET
import json
import csv
import sys
import os
from datetime import datetime
from collections import defaultdict


def parse_ciscat_xccdf_results(xml_path: str) -> dict:
    """Parse CIS-CAT XCCDF results XML into structured findings."""
    tree = ET.parse(xml_path)
    root = tree.getroot()

    ns = {
        "xccdf": "http://checklists.nist.gov/xccdf/1.2",
        "cpe": "http://cpe.mitre.org/dictionary/2.0",
    }

    results = {
        "benchmark_id": "",
        "benchmark_title": "",
        "profile": "",
        "target": "",
        "scan_date": "",
        "total_rules": 0,
        "passed": 0,
        "failed": 0,
        "not_applicable": 0,
        "error": 0,
        "score": 0.0,
        "findings": [],
    }

    benchmark = root.find(".//xccdf:benchmark", ns)
    if benchmark is not None:
        results["benchmark_id"] = benchmark.get("id", "")

    title = root.find(".//xccdf:title", ns)
    if title is not None:
        results["benchmark_title"] = title.text or ""

    test_result = root.find(".//xccdf:TestResult", ns)
    if test_result is not None:
        results["scan_date"] = test_result.get("end-time", "")
        target = test_result.find("xccdf:target", ns)
        if target is not None:
            results["target"] = target.text or ""

        profile = test_result.find("xccdf:profile", ns)
        if profile is not None:
            results["profile"] = profile.get("idref", "")

        for rule_result in test_result.findall("xccdf:rule-result", ns):
            rule_id = rule_result.get("idref", "")
            result_elem = rule_result.find("xccdf:result", ns)
            result_value = result_elem.text if result_elem is not None else "unknown"

            results["total_rules"] += 1

            if result_value == "pass":
                results["passed"] += 1
            elif result_value == "fail":
                results["failed"] += 1
                results["findings"].append(
                    {
                        "rule_id": rule_id,
                        "result": "FAIL",
                        "severity": rule_result.get("severity", "unknown"),
                    }
                )
            elif result_value == "notapplicable":
                results["not_applicable"] += 1
            else:
                results["error"] += 1

    scored_rules = results["passed"] + results["failed"]
    if scored_rules > 0:
        results["score"] = round((results["passed"] / scored_rules) * 100, 2)

    return results


def generate_remediation_csv(findings: list, output_path: str) -> None:
    """Generate CSV of failed controls for remediation tracking."""
    with open(output_path, "w", newline="", encoding="utf-8") as f:
        writer = csv.writer(f)
        writer.writerow(
            [
                "Rule ID",
                "Severity",
                "Result",
                "Remediation Status",
                "Assigned To",
                "Due Date",
                "Notes",
            ]
        )
        for finding in findings:
            writer.writerow(
                [
                    finding["rule_id"],
                    finding["severity"],
                    finding["result"],
                    "Open",
                    "",
                    "",
                    "",
                ]
            )


def compare_scan_results(current: dict, previous: dict) -> dict:
    """Compare two CIS-CAT scan results to detect compliance drift."""
    drift = {
        "current_score": current["score"],
        "previous_score": previous["score"],
        "score_delta": round(current["score"] - previous["score"], 2),
        "new_failures": [],
        "resolved_failures": [],
        "persistent_failures": [],
    }

    current_failed = {f["rule_id"] for f in current["findings"]}
    previous_failed = {f["rule_id"] for f in previous["findings"]}

    drift["new_failures"] = sorted(current_failed - previous_failed)
    drift["resolved_failures"] = sorted(previous_failed - current_failed)
    drift["persistent_failures"] = sorted(current_failed & previous_failed)

    return drift


def generate_compliance_report(results: dict, output_path: str) -> None:
    """Generate a compliance summary report in JSON format."""
    report = {
        "report_generated": datetime.utcnow().isoformat() + "Z",
        "benchmark": results["benchmark_title"],
        "profile": results["profile"],
        "target_host": results["target"],
        "scan_date": results["scan_date"],
        "compliance_score": results["score"],
        "summary": {
            "total_rules_assessed": results["total_rules"],
            "passed": results["passed"],
            "failed": results["failed"],
            "not_applicable": results["not_applicable"],
            "errors": results["error"],
        },
        "failed_controls": results["findings"],
        "compliance_status": "COMPLIANT"
        if results["score"] >= 95.0
        else "NON-COMPLIANT",
    }

    with open(output_path, "w", encoding="utf-8") as f:
        json.dump(report, f, indent=2)


def categorize_findings_by_section(findings: list) -> dict:
    """Group failed findings by CIS benchmark section for prioritized remediation."""
    sections = defaultdict(list)

    section_map = {
        "1.1": "Password Policy",
        "1.2": "Account Lockout Policy",
        "2.2": "User Rights Assignment",
        "2.3": "Security Options",
        "5": "System Services",
        "9": "Windows Firewall",
        "17": "Advanced Audit Policy",
        "18": "Administrative Templates",
        "19": "Administrative Templates (User)",
    }

    for finding in findings:
        rule_id = finding["rule_id"]
        categorized = False
        for prefix, section_name in section_map.items():
            if f"_section_{prefix}" in rule_id.lower() or f".{prefix}." in rule_id:
                sections[section_name].append(finding)
                categorized = True
                break
        if not categorized:
            sections["Other"].append(finding)

    return dict(sections)


if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: python process.py <ciscat-results.xml> [previous-results.xml]")
        print()
        print("Parses CIS-CAT XCCDF results and generates compliance reports.")
        print()
        print("Arguments:")
        print("  ciscat-results.xml      Current CIS-CAT assessment results")
        print("  previous-results.xml    (Optional) Previous results for drift detection")
        sys.exit(1)

    xml_path = sys.argv[1]
    if not os.path.exists(xml_path):
        print(f"Error: File not found: {xml_path}")
        sys.exit(1)

    results = parse_ciscat_xccdf_results(xml_path)
    base_name = os.path.splitext(os.path.basename(xml_path))[0]
    output_dir = os.path.dirname(xml_path) or "."

    report_path = os.path.join(output_dir, f"{base_name}_compliance_report.json")
    generate_compliance_report(results, report_path)
    print(f"Compliance report: {report_path}")

    if results["findings"]:
        csv_path = os.path.join(output_dir, f"{base_name}_remediation.csv")
        generate_remediation_csv(results["findings"], csv_path)
        print(f"Remediation tracker: {csv_path}")

    print(f"\nCompliance Score: {results['score']}%")
    print(f"Status: {'COMPLIANT' if results['score'] >= 95.0 else 'NON-COMPLIANT'}")
    print(f"Passed: {results['passed']} | Failed: {results['failed']} | N/A: {results['not_applicable']}")

    if len(sys.argv) >= 3:
        prev_path = sys.argv[2]
        if os.path.exists(prev_path):
            prev_results = parse_ciscat_xccdf_results(prev_path)
            drift = compare_scan_results(results, prev_results)
            drift_path = os.path.join(output_dir, f"{base_name}_drift.json")
            with open(drift_path, "w") as f:
                json.dump(drift, f, indent=2)
            print(f"\nDrift report: {drift_path}")
            print(f"Score delta: {drift['score_delta']:+.2f}%")
            print(f"New failures: {len(drift['new_failures'])}")
            print(f"Resolved: {len(drift['resolved_failures'])}")

Assets 1

template.mdtext/markdown · 2.0 KB
Keep exploring