Portmaster Endpoint Network Audit

The following is AI-generated (aka vibe-coded) software. The software is specific to my needs and my system and may not work for you or your system. Support is limited, but if you report a bug I'll certainly look into it. All code is provided in a zip file for you to review should you choose.

Audits every program that Portmaster has seen make network connections. For each Portmaster profile whose executable is an EXE, it combines Portmaster’s connection history with what Windows says about the file and the running process: the Authenticode signature, SHA256, version information, who can write to the file and its folder, data streams, the running instances and their parents, modules loaded from unexpected places, scheduled tasks and Run keys that start it, the service it belongs to (svchost.exe services in depth), and its network behavior (periodic beacons, direct-to-IP traffic, rare destinations, uncommon ports).

Each item is rated PASS, REVIEW (something to look at) or FAIL (a hard contradiction, such as a missing file or a broken signature), with a concern level of low, moderate or high. The results go to a text, JSON, CSV and HTML report; a summary of the items that need attention is printed. The Portmaster database is opened read-only and is never changed.

Items you have reviewed can be added to a validated list, so later audits accept them while their identity and findings stay the same, and flag them again when either changes.

Requirements

  • Python 3.8 or later. Nothing else to install.
  • The audit needs Windows 10 or later, with Windows PowerShell, and is best run from an elevated prompt (see Troubleshooting). The other commands and --help run on any system.
  • Portmaster’s history database (history.db, in Portmaster’s data folder when its network history is turned on).

Quick start

python portmaster-endpoint-network-audit.py --command audit --portmaster-db-file-path "PATH\TO\history.db"

The audit prints a summary of the FAIL and high-concern REVIEW items, and writes its reports to the working folder (%APPDATA%\portmaster-endpoint-network-audit unless you give --working-folder-path). Open the HTML report to sort and filter every item.

After reviewing the items in the summary, accept them:

python portmaster-endpoint-network-audit.py --command validate

The next audit reports them as validated, unless the file changes or a new finding appears.

Commands

Every run names its command with --command:

Command What it does
audit Audits every profile, writes the reports and prints the summary.
Needs --portmaster-db-file-path.
show Prints the summary again from the last audit’s JSON report, with each item’s validation checked against the validated list as it is now.
The files are not read again.
validate Adds every item the summary would show to the validated list (with the same filters), and lists them.
prune Removes validated-list entries whose executable has had no connection for --inactive-days days. Needs --portmaster-db-file-path.
selftest Checks the audit’s own functions without touching your files, then exits (see Testing). Takes no other options.

The summary shows, by default, the FAIL and high-concern REVIEW items that are not on the validated list. The --console-... options choose other items; the reports always have every item.

The validated list matches an executable by its path and SHA256. A shared host such as svchost.exe or rundll32.exe runs many unrelated components, so it is matched by its profile and the SHA256 of its ServiceDll too. A missing executable is added as a MISSING_FILE exception, which stops applying if a file appears at that path. The findings an item had when it was validated are remembered: a new one (a new scheduled task, beaconing, direct-to-IP traffic) puts it back in the summary as VALIDATION-CHANGED. Validating it again accepts the new findings.

The baseline (--write-baseline TRUE) records each executable’s SHA256, signer and destinations, so later audits report files that changed and destinations never seen before.

Command line

python portmaster-endpoint-network-audit.py --command audit|show|validate|prune|selftest [options]

Every option is written --name VALUE or --name=VALUE, in any order. A yes/no option takes TRUE or FALSE (also 1/0, YES/NO, ON/OFF, in any case). An option left out, or given blank, takes the default named below. --help lists them all.

Option Commands What it does
--command audit\|show\|validate\|prune\|selftest What to do (see Commands). Required.
--portmaster-db-file-path FILE audit, prune Portmaster’s history database, opened read-only.
--working-folder-path FOLDER all The folder for the reports, the baseline, the validated list and temporary files, created if needed. Default: %APPDATA%\portmaster-endpoint-network-audit.
--validated-list-file-path FILE all The validated list. Default: portmaster-endpoint-network-audit-validated.json in the working folder.
--console-show-status STATUSES audit, show, validate The items the summary shows, and validate adds: one or more of PASS, FAIL, REVIEW-LOW, REVIEW-MODERATE and REVIEW-HIGH, separated by commas. Default: FAIL,REVIEW-HIGH.
--console-show-folder-match TEXT audit, show, validate Show only executables whose path contains this text, in any case.
--console-hide-folder-match TEXT audit, show, validate Hide executables whose path contains this text, in any case (--console-hide-folder-match Windows).
--console-show-validated TRUE\|FALSE audit, show, validate TRUE: show only items on the validated list; FALSE: only those that aren’t. Default: FALSE.
--detail-limit N audit The most recent connection records listed in the text and JSON reports, 1 or more. Default: 200.
--behavior-rows-per-profile N audit The recent connections of each profile analyzed for network behavior, 1 or more. Default: 200.
--limit-to-days-before-today DAYS audit Only use connections started on or after midnight this many days before today; 0 is today only. Default: all the history.
--baseline-file-path FILE audit A baseline from an earlier audit. Default: portmaster-endpoint-network-audit-baseline.json in the working folder, if it is there.
--write-baseline TRUE\|FALSE audit TRUE: add this audit’s results to the baseline (the file above, or the default). Default: FALSE.
--beacon-min-span-minutes MINUTES audit How long a periodic pattern must last to be reported as a beacon candidate; it must also cover at least four of its intervals. Default: 30.
--beacon-allowlist-file-path FILE audit Endpoints known to be periodic, reported as information instead of as beacons (see below). Default: portmaster-endpoint-network-audit-beacon-allowlist.txt in the working folder, if it is there.
--inactive-days DAYS prune Remove entries whose executable (or, for a shared host, whose profile) has had no connection in this many days. Refused when the history is shorter.
--dry-run TRUE\|FALSE prune TRUE: list what would be removed without changing the validated list. Default: FALSE.
--help List the commands and options.

Giving an option to a command it doesn’t apply to is a mistake (--detail-limit only applies to --command audit).

The beacon allowlist is a text file with one rule per line; # starts a comment. A rule is a glob matched against the host, IP, host:port and ip:port, in any case, optionally after profile=GLOB:

*.windowsupdate.com
profile=Firefox  push.services.mozilla.com:443
profile=Teams*   52.112.*

DNS, DNS over TLS, NTP, mDNS and LLMNR traffic, and traffic to the DNS servers this computer uses, are never beacons.

Results and messages: the summary (and what validate adds and prune removes) goes to stdout; the steps of the run, where the reports went, warnings (Warning: ...) and errors (Error: ...) go to stderr. During the audit, a progress line counts the profiles on the console; it is left out when stderr is redirected.

Exit codes say only whether the run worked, never what the audit found:

Code Meaning
0 Done, whatever the audit found. FAIL and REVIEW items are in the summary and the reports.
1 The task couldn’t be done: no database, no report to show, a damaged, locked or unusable data file, a failed step, or Ctrl+C.
2 A mistake on the command line.

Files in the working folder

File What
portmaster-endpoint-network-audit.txt The text report: the run’s steps, each item in detail, validated items, validation changes, the recent connection records and the full summary. Written as the audit runs, so a failed run leaves what it reached.
portmaster-endpoint-network-audit.json Every item and finding, for scripts and for show and validate.
portmaster-endpoint-network-audit-findings.csv One row per finding, for Excel (UTF-8 with a byte-order mark).
portmaster-endpoint-network-audit.html A self-contained, sortable and filterable report, light or dark.
portmaster-endpoint-network-audit-validated.json The validated list. prune keeps a timestamped .bak- copy before changing it.
portmaster-endpoint-network-audit-baseline.json The baseline, when --write-baseline TRUE has been used.
portmaster-endpoint-network-audit-beacon-allowlist.txt The beacon allowlist, if you create one.

The JSON, CSV and HTML files, the validated list and the baseline are written through a temporary file, so an interrupted run never leaves a half-written one. A validated list or baseline that can’t be read as JSON is renamed <name>.damaged-<date and time>.json with a warning, and the run starts without it. A list or baseline that is valid JSON but not one this app writes stops the run (exit 1) and is left as it is.

Keyboard shortcuts

Ctrl+C stops a run (exit 1). The reports are not written; the text report has what the run reached.

Testing

python portmaster-endpoint-network-audit.py --command selftest
python -m pytest

The self-test checks the analysis without touching your files or Windows: timestamps, paths, signer matching, validated identities, the console filters, beacon detection and the allowlist, the validated list (a damaged one is kept aside, one of the wrong shape refused), the CSV’s encoding, the HTML report’s escaping, and pruning. Its last line before the result says whether the Windows audit can run here.

The tests (pytest) run the script as a separate process, with its own working folder, and build their inputs (an audit’s JSON report, a Portmaster database) in the test. They cover the summary and its filters, an empty result exiting with 0, exit codes 1 and 2 (every kind of command-line mistake), validating, a damaged or unusable validated list, pruning with and without a dry run, a history too short to prune, the default working folder, --help, --command selftest and a reader that stops early. 16 tests pass in about 5 seconds on Linux. The audit itself needs Windows, so the tests check only that it says so elsewhere; check an audit on Windows after changing it.

Troubleshooting

  • Many “Loaded-module enumeration … was unavailable” or ACL notes: run the audit from an elevated prompt. Without administrator rights, Windows hides other users’ and system processes’ modules, and some files’ ACLs.
  • “there is no audit report” with show or validate: run --command audit first, with the same --working-folder-path.
  • “the history only covers about N day(s)” with prune: Portmaster’s history doesn’t reach back --inactive-days days, so an executable’s absence can’t be shown. Use a smaller number, or wait.
  • “could not be read … kept as …damaged-…”: the validated list or baseline was damaged (for example by a crash while it was written by an older version). The run went on without it; the damaged file is beside it, to recover entries from by hand.
  • “is not a validated list written by this app”: --validated-list-file-path points at another JSON file. The file was left as it is.
  • A launcher passes None for an empty option: leave the option blank instead. None is not a number of days.

Limitations

  • The audit needs Windows and Windows PowerShell; it reads Portmaster’s history but doesn’t talk to Portmaster.
  • A beacon must have at least 5 connections whose intervals vary by no more than 20% (median absolute deviation), over at least --beacon-min-span-minutes. Beacons with more jitter, or sampled beyond --behavior-rows-per-profile, are not found.
  • Direct-to-IP detection needs a history that records DNS names (a remote_host or domain column).
  • show and validate use the identities in the last report; they don’t hash the files again. Run an audit first if files may have changed.
  • A REVIEW or FAIL is a lead for a person to follow, not proof of malware.

Changes to the command line

This version follows the owner’s command-line templates. Earlier command lines need these changes:

Before Now
(no option: the audit) --command audit
--console-from-output-file TRUE --command show
--build-validated-list-from-output TRUE --command validate
--prune-validated DAYS --command prune --inactive-days DAYS
--prune-validated-dry-run TRUE --dry-run TRUE
--write-baseline --write-baseline TRUE
--validated-list-path FILE --validated-list-file-path FILE
--beacon-allowlist-path FILE --beacon-allowlist-file-path FILE
--console-show-folder-match -TEXT --console-hide-folder-match TEXT
--selftest TRUE --command selftest
--working-folder-path required Optional; default %APPDATA%\portmaster-endpoint-network-audit
None for a blank value Leave it blank
Exit code 3 (any error), 130 (Ctrl+C) 1 (couldn’t be done) or 2 (command-line mistake)
windows-portmaster-endpoint-network-audit.py portmaster-endpoint-network-audit.py

The app was renamed from Windows Portmaster Endpoint Network Audit, so its default working folder and its files lost the windows- prefix. To keep an existing validated list, baseline and allowlist, move them from %APPDATA%\windows-portmaster-endpoint-network-audit to %APPDATA%\portmaster-endpoint-network-audit and drop the windows- prefix from their names (their formats haven’t changed). Otherwise the next audit starts without them.

Download Release:

⬇️ Portmaster Endpoint Network Audit.zipLast Updated: October 13, 2026
(1 votes, average: 5.00 out of 5)

Leave a Reply

Your email address will not be published. Required fields are marked *

Notify me of followup comments via e-mail.