Skip to main content

A portable Windows security posture auditor

Project description

Apotrope

Portable Windows security posture auditor. A Lynis for Windows. A single executable (or pip install apotrope, MIT-licensed) that runs entirely on the machine it audits, talks to no network, and is read-only. It checks 50+ controls across 14 categories against CIS Microsoft Windows Benchmarks (Windows 11 v5.0.0, Windows 10 v4.0.0), scores the box 0 to 100, and hands back a scored terminal report or a self-contained HTML report you can send to someone who wasn't in the room.

Tests PyPI Python 3.12+ License: MIT Website

Website: apotrope.sh


Why Apotrope?

Most posture tools want something before they'll help you: a cloud account, a license key, an agent to install, your data shipped off to a dashboard somewhere. Apotrope wants none of it. It's a single executable. Drop it on a USB stick, run it on any Windows machine, and you get a 0–100 score plus a list of exactly what's wrong and how to fix it — in plain English, not bare control IDs, with a ready-to-paste PowerShell command for every issue.

Run it as Administrator for the full picture. It works without admin too; a handful of checks (BitLocker, some policy reads) just come back limited.

How Apotrope compares

Apotrope CIS-CAT Lite HardeningKitty Lynis
Platform Windows 10/11 Windows (+others) Windows Linux/macOS/BSD
Install Single .exe or pip Java app PowerShell module Shell script
Account / signup None Yes¹ None None
Mode Read-only audit Read-only audit Audit and apply¹ Read-only audit
CIS mapping CIS Win11 v5.0.0 / Win10 v4.0.0 CIS (authoritative) CIS / Microsoft / BSI¹ CIS / various
Output Score + HTML + JSON Scored HTML CSV¹ Terminal + log
License MIT Free tier / paid Pro MIT¹ GPLv3

¹ Verify current details with each project before relying on them. Lynis is listed for context; it does not run on Windows.


Quick Start — Standalone Executable

No Python required.

  1. Download apotrope.exe from the Releases page
  2. Open Command Prompt or PowerShell as Administrator (Right-click the Start button → Terminal (Admin) or search for cmdRun as administrator)
  3. Navigate to the folder where you saved the file — for example, if it's in Downloads:
cd $env:USERPROFILE\Downloads

(in Command Prompt: cd %USERPROFILE%\Downloads)

  1. Run:
.\apotrope.exe

Note: the .\ prefix is required — PowerShell doesn't run programs from the current folder by bare name. .\apotrope.exe works in Command Prompt too (where plain apotrope.exe is also fine).

For a full HTML report:

.\apotrope.exe --html report.html

Then open report.html in your browser.

Every issue is shown with a copy-paste-ready PowerShell command by default — no extra flags needed.


Terminal Output

Standard scan (default view) — a triage view: every category with issues gets its own box listing each FAIL/WARN finding with its fix and a ready-to-paste PowerShell command:

Apotrope scan overview

Verbose mode (--verbose) — the same boxes for every category and every check, passing ones included:

Apotrope verbose output


Installation via pip

Requires Python 3.12+ and Windows 10/11 or Server 2019/2022.

Install from PyPI:

pip install apotrope
apotrope

Or install from source:

git clone https://github.com/hexorcist404/apotrope.git
cd apotrope
pip install -e .
apotrope

Authorized Use Notice

Apotrope is a READ-ONLY auditing tool. It does not modify any system settings, write to the registry, or make network connections. All data stays on the machine being audited.

Only run Apotrope on systems you own or have explicit written authorization to audit. Unauthorized use may violate computer fraud laws in your jurisdiction.

How Apotrope queries your system

Apotrope uses PowerShell subprocesses with -ExecutionPolicy Bypass to read system configuration. This flag is required so the tool can run on machines with any execution policy setting — including the default Restricted policy — without requiring you to permanently change your policy. No scripts are written to disk. Each command is a read-only query passed directly to the PowerShell process; the bypass applies only to that subprocess and does not change the machine's policy setting.


Usage

apotrope [OPTIONS]

Options:
  --html PATH          Save a self-contained HTML report to PATH
  --json PATH          Save a JSON report to PATH
  --baseline FILE      Save current scan as a JSON baseline for future comparisons
  --compare  FILE      Compare current scan against a saved baseline
  --profile  FILE      Load a custom check profile from a TOML file
  --category CATS      Comma-separated list of categories to audit
                       (e.g. firewall,encryption,patching)
  --dry-run            List check modules that would run without executing them
  --verbose            Show detail for every check, including PASSes
  --no-color           Disable Rich color output (for CI / log files)
  --log-level LEVEL    Logging verbosity: DEBUG, INFO, WARNING (default), ERROR
  --version            Show version and exit
  -h, --help           Show this help message and exit

Exit codes:
  0  Score >= 70 (passing)
  1  Score < 70 (failing)
  2  Fatal scan error

Examples

# Full audit, terminal only
apotrope

# Save HTML report
apotrope --html report.html

# Save JSON for automation / SIEM integration
apotrope --json report.json

# Audit only firewall and patching
apotrope --category firewall,patching

# Show pass/fail details for every check
apotrope --verbose

# Silent mode for scripts (exits 0 if score>=70, 1 if score<70, 2 on error)
apotrope --no-color --log-level ERROR
echo Exit code: %ERRORLEVEL%

# Save a baseline, then compare on the next run
apotrope --baseline baseline.json
apotrope --compare  baseline.json

# Apply a custom check profile (e.g. for MSP clients)
apotrope --profile myprofile.toml

# List which checks would run without executing anything
apotrope --dry-run

Custom Profiles (apotrope.toml)

Create a apotrope.toml in your working directory (or pass --profile FILE) to customise scan behaviour:

[profile]
name = "MSP-Baseline"

[disabled_checks]
# Skip checks irrelevant to this environment
checks = [
    "SMBv1 Disabled",
    "Firewall — Public Default Inbound Action",
]

[severity_overrides]
# Downgrade noisy low-risk checks
"Defender Tamper Protection" = "LOW"

[thresholds]
# Allow 45 days between updates before warning (default: 30)
max_update_age_warn = 45
max_update_age_fail = 90

Scoring System

Apotrope calculates a 0–100 security score by starting at 100 and deducting points for failed and warned checks, weighted by severity:

Outcome Severity Deduction
FAIL CRITICAL -15
FAIL HIGH -10
FAIL MEDIUM -5
FAIL LOW -2
WARN CRITICAL -7
WARN HIGH -5
WARN MEDIUM -2
WARN LOW -1

The score is clamped to [0, 100].

Grade scale:

Score Grade Label
90-100 A Excellent
80-89 B Good
70-79 C Fair
60-69 D Poor
0-59 F Critical

INFO and ERROR results do not affect the score.


CIS Benchmark Mapping

Where applicable, findings are mapped to CIS Microsoft Windows Benchmark control IDs. These references appear as blue badges in the HTML report's detailed findings section, making Apotrope useful for compliance documentation and audit preparation. Mappings are based on the CIS Microsoft Windows 11 Enterprise Benchmark v5.0.0 and CIS Microsoft Windows 10 Enterprise Benchmark v4.0.0. The correct version is selected automatically based on the OS build number at scan time.

Attribution: CIS Benchmarks are the registered trademarks of the Center for Internet Security, Inc. Apotrope is an independent tool that references CIS Benchmark recommendations for informational purposes. This project is not affiliated with, endorsed by, or sponsored by CIS. To obtain the official CIS Benchmarks, visit cisecurity.org.


Checks Performed

Category Check Description
Access Control UAC Admin Consent Behavior Checks the UAC consent prompt behavior for administrator accounts
Access Control UAC Enabled Checks whether User Account Control (UAC) is enabled
Access Control UAC Secure Desktop Checks whether UAC prompts are shown on the isolated secure desktop
Access Control UAC Standard User Behavior Checks the UAC consent prompt behavior for standard user accounts
Accounts Built-in Administrator Account Checks whether the built-in Administrator account is enabled or renamed
Accounts Guest Account Checks whether the built-in Guest account is disabled
Accounts Local Administrators Counts members of the local Administrators group (warns if > 2)
Accounts Password Policy — Account Lockout Checks whether account lockout is configured to deter brute-force attacks
Accounts Password Policy — Complexity Checks whether password complexity requirements are enforced
Accounts Password Policy — Minimum Length Checks minimum password length (fail < 8 chars, warn < 12 chars)
Antivirus Defender Real-Time Protection Checks whether Windows Defender real-time protection is active
Antivirus Defender Signature Age Checks whether virus definitions are less than 7 days old
Antivirus Defender Tamper Protection Checks whether Tamper Protection prevents unauthorised Defender changes
Antivirus Registered AV Products Lists antivirus products registered with Windows Security Center
Encryption BitLocker — {drive} * BitLocker encryption and protection status per fixed drive (one result per drive)
File Sharing SMB Encryption * Checks whether SMB encryption (EncryptData) is enforced
File Sharing SMB Signing Required * Checks that SMB message signing is required (mitigates NTLM relay attacks)
File Sharing SMBv1 Disabled * Checks that SMBv1 is disabled (mitigates EternalBlue/WannaCry/NotPetya)
Firewall Firewall — Domain Default Inbound Action Checks that the Domain profile does not explicitly allow all inbound connections
Firewall Firewall — Domain Profile Enabled Checks whether Windows Firewall is enabled for domain networks
Firewall Firewall — Private Default Inbound Action Checks that the Private profile does not explicitly allow all inbound connections
Firewall Firewall — Private Profile Enabled Checks whether Windows Firewall is enabled for private networks
Firewall Firewall — Public Default Inbound Action Checks that the Public profile does not explicitly allow all inbound connections
Firewall Firewall — Public Profile Enabled Checks whether Windows Firewall is enabled for public networks
Hardening Audit Policy Checks that key subcategories (Logon, Lockout, etc.) log success/failure events
Hardening AutoPlay Disabled Checks whether AutoPlay is disabled for all drive types
Hardening Screen Lock Timeout Checks that the screen automatically locks within 15 minutes of inactivity
Hardening Speculative Execution Mitigations Checks whether Spectre/Meltdown mitigations have been explicitly disabled
Hardening WinRM Status Checks whether the Windows Remote Management (WinRM) service is running
Network IPv6 Status Reports whether IPv6 is active on any network adapter (informational)
Network LLMNR Disabled Checks whether LLMNR is disabled (susceptible to poisoning/Responder attacks)
Network Listening Port — {port}/{service} Flags known-dangerous listening ports: FTP (21), Telnet (23), TFTP (69), RDP (3389)
Network Listening Ports — Summary Enumerates all TCP ports currently in LISTEN state (informational)
Network NetBIOS over TCP/IP Checks whether NetBIOS over TCP/IP is disabled on all network adapters
Patching Last Windows Update Checks when the most recent update was installed (warn > 30 days, fail > 60 days)
Patching Pending Windows Updates Counts Windows Updates that are available but not yet installed
Patching Windows Update Service Checks whether the Windows Update (wuauserv) service is running
Persistence Scheduled Tasks Enumerates non-Microsoft scheduled tasks (potential persistence points)
Persistence Startup Programs Enumerates programs configured to run at startup (registry Run keys + folders)
PowerShell PowerShell Constrained Language Mode Checks whether PowerShell Constrained Language Mode is active
PowerShell PowerShell Execution Policy Checks the LocalMachine execution policy (warns on Unrestricted/Bypass)
PowerShell PowerShell Module Logging Checks whether PowerShell module pipeline logging is enabled
PowerShell PowerShell Script Block Logging Checks whether Script Block Logging is enabled (critical for forensics/IR)
PowerShell PowerShell v2 Checks whether PowerShell v2 is installed (downgrade attack vector)
Remote Access RDP Enabled Checks whether Remote Desktop Protocol is enabled
Remote Access RDP Network Level Authentication † Checks whether NLA is required for RDP connections
Remote Access RDP Port † Reports the RDP listening port (informational)
Services Risky Services / Risky Service — {name} Flags known-dangerous services if running: Remote Registry, Telnet, SNMP
Services Unquoted Service Paths Detects services with unquoted executable paths containing spaces (privilege-escalation vector)
System Domain Membership Reports whether the machine is domain-joined or in a workgroup (informational)
System OS End-of-Support Status Checks whether the installed Windows build is still supported by Microsoft
System OS Version Reports the installed Windows version and build number (informational)
System Secure Boot Checks whether UEFI Secure Boot is enabled
System System Uptime Checks system uptime (warns if > 30 days, suggesting pending patch reboots)
System TPM Status Checks whether a TPM chip is present and functional

* Requires Administrator privileges for full results. † Only emitted when RDP is enabled.


Building the Executable

Prerequisites: Python 3.12+, pip install pyinstaller pillow

python build_exe.py

The exe will be at dist/apotrope.exe. To build without the custom icon:

python build_exe.py --no-icon

Contributing

  1. Fork the repo and create a branch: git checkout -b feat/my-change
  2. Make your changes — each check module is self-contained in src/apotrope/checks/
  3. Add or update tests in tests/
  4. Run pytest tests/ -q — all tests must pass
  5. Open a pull request into main

Adding a New Check Module

Create src/apotrope/checks/mycheck.py with:

from apotrope.models import CheckResult, Severity, Status

CATEGORY = "MyCategory"
# REQUIRES_ADMIN = True  # uncomment if elevation is needed

def run() -> list[CheckResult]:
    # ... query the system ...
    return [CheckResult(
        category=CATEGORY,
        check_name="My Check Name",
        status=Status.PASS,       # PASS | FAIL | WARN | INFO | ERROR
        severity=Severity.HIGH,   # CRITICAL | HIGH | MEDIUM | LOW | INFO
        description="What this check verifies.",
        details="What was found.",
        remediation="",           # empty string for PASS
    )]

The scanner auto-discovers all modules in checks/ — no registration needed.


License

MIT — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

apotrope-0.1.8.tar.gz (115.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

apotrope-0.1.8-py3-none-any.whl (95.0 kB view details)

Uploaded Python 3

File details

Details for the file apotrope-0.1.8.tar.gz.

File metadata

  • Download URL: apotrope-0.1.8.tar.gz
  • Upload date:
  • Size: 115.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for apotrope-0.1.8.tar.gz
Algorithm Hash digest
SHA256 d009c1a5eb74638b162c6fdef0666b841e32591a6e938db546179d0152139e3f
MD5 8f2b80dcbf88b73ff4be8c35ff82e597
BLAKE2b-256 9fa01cb3923e8324edbbf8f3a836b6e28d4325a88f7500c83e84b1b229b76b2b

See more details on using hashes here.

Provenance

The following attestation bundles were made for apotrope-0.1.8.tar.gz:

Publisher: publish.yml on hexorcist404/apotrope

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file apotrope-0.1.8-py3-none-any.whl.

File metadata

  • Download URL: apotrope-0.1.8-py3-none-any.whl
  • Upload date:
  • Size: 95.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for apotrope-0.1.8-py3-none-any.whl
Algorithm Hash digest
SHA256 f77e4c58d407f56884b095847405271a93096a8d3478b49763e713e702a2d4d0
MD5 111955e555812a9b198a38dfe3c9e0f4
BLAKE2b-256 20af3d00dcb387dfddb6cf43b66c4002e8bff4d9428dbac18fa647442718d548

See more details on using hashes here.

Provenance

The following attestation bundles were made for apotrope-0.1.8-py3-none-any.whl:

Publisher: publish.yml on hexorcist404/apotrope

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page