Appearance
Python Orchestrator
The netvuln Python package is a native, typed CLI that wraps the same scan pipeline as the Bash tooling. It is a drop-in replacement for vulnscan_recon.sh and also handles upload, push, diff, status queries, and daemon control. It shells out to the existing Bash modules for the actual scanning work, then adds Python-native nmap XML parsing, a native scoring engine, checkpoint/resume, progress events, and a license soft gate. Type checking is enforced with strict mypy, and the package ships a py.typed marker.
Installation
bash
# From the repo root (editable install puts the `netvuln` console script on PATH)
pip install -e .
# Or run without installing
python3 -m netvuln --versionThe console script and the module form are equivalent: netvuln recon … and python3 -m netvuln recon ….
Subcommands
recon, scan, upload, push, diff, status, and daemon. The parser lives in netvuln/cli.py; each subcommand dispatches into netvuln/dispatch.py.
recon: multi-phase pipeline
bash
python3 -m netvuln recon -t 192.168.1.0/24 --full -R report.html
python3 -m netvuln recon -t 10.0.0.0/24 --full --exec-summary --email ciso@client.com --diff| Flag | Purpose |
|---|---|
-t/--target | -T/--target-file | Target CIDR/host/domain, or a file of targets (mutually exclusive, one required) |
--full | -p/--phases | -P/--profile | Phase selection (mutually exclusive): all phases, an explicit comma list, or a named profile |
-R/--report FILE | HTML report output path |
-c/--config FILE | Engagement config (client metadata, portal credentials, branding) |
--timing | nmap timing template (default -T4) |
--ports | nmap port spec (default -F) |
--no-cve-lookup | Skip CVE description fetching |
--exec-summary | Also generate the one-page executive summary |
--email ADDR | Email the report |
--diff | Run the cross-session diff after the scan |
--compare DIR | Benchmark against a prior session directory |
--resume | Resume from the last checkpoint |
--dry-run | Print the plan without running |
scan: quick nmap modes
bash
python3 -m netvuln scan -m quick -t 192.168.1.1-m/--mode is one of quick, full, vuln, custom (default quick); --extra-opts passes raw nmap options for custom.
upload / push: send sessions to the portal
bash
python3 -m netvuln upload -c ~/netvuln-tool/configs/acme_corp.conf --latest
python3 -m netvuln push -c ~/netvuln-tool/configs/acme_corp.conf -d ~/…/sessions/20260718_120000 -R report.html -e exec_summary.htmlupload requires -c/--config and selects a session with --latest, -i/--session-id, or -s/--session-dir (--dry-run previews). push takes -d/--session-dir or -j/--session-json (one required), plus -c/--config or explicit -u/--api-url + -k/--api-key, and optional -R/--report-file and -e/--exec-summary. push returns a shareable report link.
diff: compare sessions
bash
python3 -m netvuln diff --latest
python3 -m netvuln diff -c current.json -p previous.json --json--latest diffs the two most recent sessions; otherwise pass -c/--current and -p/--previous. --json and --quiet control output. As with the Bash scan_diff.sh, new critical/high findings drive a non-zero exit for CI use.
status: local and remote
bash
python3 -m netvuln status # local sessions + daemon status
python3 -m netvuln status --remote -c acme_corp.conf --jwt "$NV_JWT"--remote queries the portal session list over JWT bearer auth (from --jwt, NV_JWT, or CONSULTATION_JWT); -c/--config supplies CONSULTATION_API_URL.
daemon: control the scheduler
bash
python3 -m netvuln daemon status
python3 -m netvuln daemon startThe action (start, stop, restart, reload, status) and any trailing args are forwarded to netvuln_daemon_ctl.sh. See Daemon Mode.
Pipeline Runner
netvuln/pipeline.py defines the Pipeline class and netvuln/runner.py the BashRunner that executes it. The runner can invoke a standalone script (run_script) or source a library and call a single function (run_module), tee-ing stdout/stderr through reader threads and enforcing a timeout by killing the whole process group.
Pipeline.run() proceeds through the same phase model as the Bash orchestrator (discovery, enumeration, email_security, vuln, report):
- Check the license (soft gate), initialize the session JSON, and set up the checkpoint.
- Install a SIGINT handler that preserves partial results.
- For each phase: fire
pre-reportwhere applicable, run the phase modules (some in parallel via a thread pool), record phase status/timing in the checkpoint, and fire the matching post-phase hook (post-discovery,post-enumeration,post-assessment,post-report). - Enrich the session from nmap XML, run native scoring, stamp the end time, save, auto-submit if configured, and fire
post-pipeline.
Progress is surfaced through PipelineEvent callbacks (pipeline_start, phase_start, phase_end, pipeline_end), so a caller can render live progress. Checkpoints let --resume skip already-completed phases.
nmap XML Parsing
netvuln/parsers/nmap_xml.py parses nmap -oX output into typed Host and Port models (netvuln/models/):
parse_host_discovery()readsnmap -sn -oXoutput, returning hosts with statusup(IPv4, hostname preferringtype="user"overPTR, and MAC when present).parse_port_scan()readsnmap -sV -oXoutput, returning hosts that have at least one open port, with service name and a composed version string (product version extrainfo) and an OS guess from the firstosmatch.
Parsed hosts are merged into the session dict keyed by IP (ports keyed by (port, protocol), XML values winning), which is safer and faster than re-parsing text output. Malformed or missing XML returns an empty list rather than raising.
Native Scoring
netvuln/scoring.py is a pure-Python port of classify_severity.sh, risk_score.sh, and aggregate_results.sh, operating directly on the session dict:
classify_severity(): three-tier matching: title patterns (critical/high/medium/low, case-insensitive), then port-based risk for enumeration findings, then service-name risk; defaultinfo.calculate_risk_score(): severity weights (critical 25, high 15, medium 5, low 1, info 0) plus bonuses for cleartext ports (FTP/Telnet, +10 each) and management ports (RDP, VNC, databases, +8 each), clamped to 0-100 and mapped to grades A-F.calculate_operational_score(): subtracts the weight of accepted, non-expired exceptions to produce the operational score/grade and anexception_impactblock.aggregate_results(): dedups by(host, port, title), re-numbers IDs, sorts by severity, rebuilds the summary, then runs both scoring functions.
The scoring model matches the Bash implementation exactly, so a session scored in Python is consistent with one scored by the shell tooling. See Scoring Methodology.
License Soft Gate
netvuln/license.py mirrors lib/license.sh (key resolution, parsing, tier matrix) and lib/license_validate.sh (online validation with a 24h cache and 72h grace). It resolves keys of the form nvt_{pro|biz|msp}_{64 hex} with the precedence NV_LICENSE_KEY > NV_API_KEY > CONSULTATION_API_KEY > ~/.netvuln/license.key, gates features by tier (compliance/benchmark/remediation/webhooks need business; c2/agent_commands need msp), and warns rather than blocking. The plaintext key stays in memory only; the cache stores a sha256 fingerprint prefix at mode 600. The portal remains authoritative (a rejected key returns 403). See License Provisioning.
Type Checking and Tests
bash
# Strict static typing
python3 -m mypy netvuln/
# Python test suite
python3 -m pytest tests/python/Strict mypy is configured in pyproject.toml. The pytest suite in tests/python/ covers the CLI subcommands, pipeline runner, scoring engine, upload/diff modules, remote session listing, plugin hooks, license gate, and progress events.
Related
- Pipeline Phases: the shared phase model.
- Session Data: the JSON schema both orchestrators produce.
- Recon Pipeline: the equivalent Bash CLI.
