Skip to main content

🛡️ WinSecAudit v2

A CLI-first Windows Security Misconfiguration Auditor

Weighted scoring · Threat intelligence enrichment · Multi-format reporting · Drift detection

Python Platform License Checks Tests


✨ Overview

WinSecAudit v2 audits Windows 10/11 machines for common security misconfigurations, assigns a weighted risk score, enriches every finding with live CVE threat intelligence, and produces boardroom-ready reports in four formats. It's built as a plugin system — every check is a self-contained class auto-discovered at runtime, so extending the suite requires zero wiring.

┌──────────────┐     ┌──────────────┐     ┌──────────────┐     ┌──────────────┐
│  39 CHECKS   │ ──▶ │   SCORING    │ ──▶ │  THREAT INTEL│ ──▶ │   REPORTS    │
│ (PowerShell) │     │  (weighted)  │     │ NVD+EPSS+KEV │     │ PDF/DOCX/CSV │
└──────────────┘     └──────────────┘     └──────────────┘     └──────────────┘

📚 Table of Contents


🚀 Quick Start

# 1. Clone & install
git clone https://github.com/KavyaJain321/winsecaudit-v2.git
cd winsecaudit-v2
pip install -r requirements.txt

# 2. Run your first audit (open an elevated PowerShell first)
python winsecaudit.py scan

# 3. Export a beautiful PDF report
python winsecaudit.py report --format pdf

💡 Tip: The SQLite database and all caches are created automatically on first run inside data/. No setup scripts, no migrations.


⚙️ Installation

Requirements

Requirement Version
Python 3.11 or newer
OS Windows 10 / 11 (elevated shell for most checks)
Dependencies See requirements.txt

Setup

git clone https://github.com/KavyaJain321/winsecaudit-v2.git
cd winsecaudit-v2
pip install -r requirements.txt

Optional

# Set your NVD API key to bump rate limit from 5 → 50 req/s
$env:NVD_API_KEY = "your-key-here"     # PowerShell
export NVD_API_KEY="your-key-here"     # Bash

🧰 Commands

WinSecAudit ships with 6 Typer-powered commands. Run python winsecaudit.py --help to see them all.

scan — Run the full audit

python winsecaudit.py scan [OPTIONS]
Option Default Description
--profile basic Profile name (basic or hardened)
--output terminal Output mode: terminal or json
--no-threat-intel off Skip NVD / EPSS / CISA KEV enrichment

report — Generate a formatted report

python winsecaudit.py report [OPTIONS]
Option Default Description
--scan-id latest Specific scan ID to report on
--format terminal terminal, pdf, docx, or csv

list — List saved scans

python winsecaudit.py list [--machine HOSTNAME] [--limit N]

drift — Compare two scans

python winsecaudit.py drift [--scan-a ID] [--scan-b ID]

Defaults to comparing the two most recent scans. Under the hood, drift emulates a FULL OUTER JOIN with two LEFT JOINs + UNION ALL (SQLite doesn't support full outer joins natively).

fix — List or apply remediations

python winsecaudit.py fix --list                      # show all remediable checks
python winsecaudit.py fix --check "Check Name"        # apply the fix

dashboard — Launch the FastAPI read-only dashboard

python winsecaudit.py dashboard
# Opens http://localhost:8080

🔍 Security Checks

39 checks across 8 categories, all auto-discovered via CheckRegistry.discover():

Category # Sample Checks
🔐 Authentication 6 Password complexity, min length, account lockout, guest account, admin rename
🚪 Access Control 5 UAC level, admin shares, AutoRun, WSH, PowerShell execution policy
🌐 Network 6 SMBv1 disabled, LLMNR, NetBIOS, WPAD, RDP NLA, NTLMv1
⚙️ Services 5 Print Spooler, Telnet, SNMP, FTP, WinRM
🧬 Kernel 4 Secure Boot, DEP, ASLR, Kernel DMA Protection, VBS/HVCI
🖥️ System 5 BitLocker, Defender, Firewall, Windows Update, Secure Boot
📝 Logging 4 Audit policy, PowerShell module logging, script-block logging, Sysmon
🔑 Credentials 4 Credential Guard, LAPS, WDigest disabled, cached logons

Each check emits an immutable CheckResult with CVE IDs, MITRE ATT&CK technique, CIS benchmark ID, severity, weight, and a ready-to-run remediation command.


🎛️ Profiles

Profiles live in profiles/*.yaml and control three levers:

Key Effect
relaxed_checks Named checks whose FAIL is flipped to PASS (with a note). Use for controls intentionally disabled on a machine class.
weight_overrides Override the default weight of any check by name.
required_checks (Reserved) Checks that must pass for the scan to succeed.

Bundled Profiles

Profile Target Relaxations
basic Workstations, developer machines BitLocker, Secure Boot, NTLMv1, PS exec policy, Kernel DMA
hardened Servers, high-security workstations None — all checks enforced with higher weights on crypto/creds

📊 Scoring & Grading

score = (earned_weight / max_possible_weight) × 100
Status Contribution
✅ PASS earns full check weight
❌ FAIL / ERROR earns 0
⏭️ SKIPPED excluded from numerator and denominator

Edge case: if every check is skipped → score = 100.0

Grade Bands

Grade Score Range Meaning
🟢 A ≥ 90 Excellent — hardened baseline met
🟢 B ≥ 75 Good — minor gaps
🟡 C ≥ 60 Acceptable — remediation recommended
🟠 D ≥ 40 Poor — significant exposure
🔴 F < 40 Critical — immediate action required

🌐 Threat Intelligence

Every CVE associated with a failed check is enriched from three sources:

Source Data Rate Limit Cache TTL
NIST NVD CVSS score, severity, description 5/s anon · 50/s with key 7 days
FIRST EPSS Exploitation probability (0.0–1.0) None documented 7 days
CISA KEV Known-exploited flag + ransomware use Bulk download 24 hours

Caches live in data/cve_map.json and data/cisa_kev_cache.json. Enrichment degrades gracefully — a 429 from NVD does not crash the scan; affected CVEs simply ship without TI metadata.


📄 Output Formats

Format File Highlights
🖥️ Terminal (stdout) Rich-rendered tables · ANSI colour · live progress
📕 PDF output/<scan_id>.pdf Cover page · executive summary · category breakdown · failure deep-dive · "Page N of M" footer
📘 DOCX output/<scan_id>.docx Word-native styles · FAIL rows bold + italic
📗 CSV output/<scan_id>.csv UTF-8 BOM · scan metadata denormalised per row (SIEM-friendly)

🧪 Testing

python tests/smoke_test.py

10 standalone tests cover: imports, check discovery, profile loading, scoring math, grade thresholds, DB round-trip, profile relaxation, TI offline cache, CLI entry point, and the full pipeline. No pytest required — exits 0 on success.

WinSecAudit v2 — Smoke Tests
========================================
  PASS  01 Import health
  PASS  02 Check discovery
  PASS  03 Profile loading
  PASS  04 Scoring correctness
  PASS  05 Grade thresholds
  PASS  06 DB round-trip
  PASS  07 Profile relaxation
  PASS  08 TI cache offline-safe
  PASS  09 CLI entry point
  PASS  10 Full pipeline
========================================
Results: 10/10 passed

⚠️ Known Limitations

  • 🔒 Elevation required — Most PowerShell checks call secedit, auditpol, or protected registry paths. Run from an elevated terminal.
  • 🪟 Windows-only checks — All checks are PowerShell/Windows-specific. The DB, scoring engine, and exporters are cross-platform.
  • 📉 NVD rate limit — Without an API key, NVD allows 5 req/s. Set NVD_API_KEY to raise this to 50 req/s.
  • 📥 CISA KEV download — First scan of the day downloads ~5 MB from cisa.gov. Subsequent scans within 24 h use the cache.

📂 Project Structure

winsecaudit-v2/
├── winsecaudit.py          # Entry point — forces UTF-8 stdout/stderr on Windows
├── requirements.txt
│
├── checks/                 # 🔍 Security check plugins (auto-discovered)
│   ├── base.py             #    BaseCheck, CheckResult, CheckRegistry
│   ├── auth/               #    Authentication (6)
│   ├── access/             #    Access control (5)
│   ├── network/            #    Network (6)
│   ├── services/           #    Services (5)
│   ├── kernel/             #    Kernel/hardware (4)
│   ├── system/             #    System config (5)
│   ├── logging/            #    Audit & logging (4)
│   └── credentials/        #    Credential protection (4)
│
├── engine/                 # ⚙️ Core orchestration
│   ├── runner.py           #    Parallel check execution
│   ├── scorer.py           #    Weighted scoring
│   ├── comparator.py       #    Profile loading & adjustment
│   ├── risk.py             #    Grade assignment & priority
│   └── threat_intel.py     #    NVD / EPSS / CISA KEV pipeline
│
├── db/                     # 💾 Persistence
│   ├── database.py         #    SQLAlchemy Core layer
│   └── schema.sql          #    Reference DDL
│
├── cli/                    # 🧰 CLI surface
│   ├── main.py             #    Typer commands
│   └── output.py           #    Rich rendering
│
├── dashboard/              # 🌐 FastAPI read-only dashboard
│   ├── app.py
│   ├── models.py
│   └── static/index.html
│
├── exporters/              # 📄 Report generators
│   ├── pdf.py              #    reportlab Platypus
│   ├── docx_export.py      #    python-docx
│   └── csv_export.py       #    csv module
│
├── profiles/               # 🎛️ YAML profiles
│   ├── basic.yaml
│   └── hardened.yaml
│
├── data/                   # 🗃️ Runtime data (gitignored)
└── tests/
    └── smoke_test.py       # ✅ 10 standalone smoke tests

🤝 Contributing

Adding a new check is a three-step affair:

  1. Create a file under the appropriate checks/<category>/ directory.
  2. Subclass BaseCheck and set the class attributes (name, category, weight, severity, cve_ids, mitre_technique, cis_id, remediation_cmd, remediation_supported).
  3. Implement run() -> CheckResult. That's it — CheckRegistry.discover() picks it up on the next scan.
from checks.base import BaseCheck, CheckResult, CheckStatus, Severity, run_powershell

class MyNewCheck(BaseCheck):
    name = "My New Check"
    category = "System"
    weight = 5
    severity = Severity.HIGH
    remediation_cmd = "Set-ItemProperty ..."
    remediation_supported = True

    def run(self) -> CheckResult:
        value = run_powershell("Get-Something")
        return CheckResult(
            check_name=self.name,
            category=self.category,
            status=CheckStatus.PASS if value == "expected" else CheckStatus.FAIL,
            system_value=value,
            expected_value="expected",
            severity=self.severity,
            weight=self.weight,
            cve_ids=(),
            mitre_technique="",
            cis_id="",
            remediation_cmd=self.remediation_cmd,
            remediation_supported=self.remediation_supported,
        )

Built with ❤️ for defenders.

Report Bug · Request Feature · View Changelog

Metadata

Release files for winsecaudit 1.1.7

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for winsecaudit 1.1.7
File Size Uploaded Provenance
winsecaudit-1.1.7.tar.gz 194.3 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for winsecaudit 1.1.7
File Interpreter ABI Platform
winsecaudit-1.1.7-py3-none-any.whl Python 3 none any Details

Total release size: 432.2 kB

Release files / winsecaudit-1.1.7.tar.gz

Download URL winsecaudit-1.1.7.tar.gz
Size 194.3 kB
Tags Source
SHA-256 checksum
How to use checksums
0bdffb7350184c6ba580e8ca6366da5dde2eb751e6e19dcfc20313f416ca567f
BLAKE2b-256 checksum
How to use checksums
dbd21e00a3eb7b44bb176622210ac8273995f086dade6520fb851c9fa193ff2f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.3

Release files / winsecaudit-1.1.7-py3-none-any.whl

Download URL winsecaudit-1.1.7-py3-none-any.whl
Size 237.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
57aebafd3dbb10baaaed783995d425a798e8ea7b6a74210834dcdc650bbcc9e0
BLAKE2b-256 checksum
How to use checksums
4287c9444160280f95b52e79a039398e730c7fc561b2404e6bbc7f46d5cf6ea7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.3

Security for winsecaudit 1.1.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page