Skip to content

ValtersIT Open-Source CVE Scanner Suite: Linux, Docker, WordPress and Windows Setup Guide

Most vulnerability scanners are either paid SaaS with an agent you can’t audit, or open-source tools that require a local database the size of a small appliance. The ValtersIT scanner suite is neither: five small scripts — two to four files each, no pip install, standard-library Python or a single PowerShell file — that send your installed component list to the ValtersIT CVE API and return the CVEs that match.

This guide covers every scanner in the suite: installation, a first run, scheduling, and what to do with the output.

Each scanner detects what is actually installed on the machine you run it on, then hands that inventory to the ValtersIT CVE API for matching. The result is a ranked list of CVEs that affect your specific versions — not a generic advisory feed, not a cloud agent phoning home with your traffic.

ToolWhat it scansLanguageSize
Linux Scannerdpkg / rpm / apk / pacman packages + service versionsPython 3.7+~350 lines
Docker ScannerDocker Engine version + images used by running/stopped containersPython 3.7+~350 lines
WordPress ScannerWP core + all themes + all plugins (+ WP-CLI status if present)Python 3.7+~450 lines
Windows ScannerAll installed software (registry Uninstall keys, 64-bit + 32-bit)PowerShell 5.1+~350 lines
Threat-IP BlocklistPulls the ValtersIT IP threat feed → nftables / ipset / fail2ban / pfSense / MikroTikPython 3.7+~300 lines

All five are Apache-2.0. All are small enough to read in a few minutes — that is deliberate.

Every scanner follows the same data-minimisation rule:

  • Sent to the API: component name + version only (e.g. openssl 3.0.13, woocommerce 9.4.1, nginx alpine). A locally-generated random identifier (32 hex chars, stored in ~/.valtersit/fingerprint) lets the API recognise repeat scans of the same system — it is never derived from your IP address, hostname, MAC address, or any other stable machine identifier.
  • Never sent: IP address, hostname, MAC address, encryption keys, passwords, database contents, file contents. The Linux scanner reads dpkg-query / rpm -qa / apk info / pacman -Q output only. The WordPress scanner reads plugin header comments and, optionally, WP-CLI output — it never opens wp-config.php or touches MySQL. The Docker scanner issues only read-only docker info / docker version / docker ps -a commands — it refuses to run against a remote DOCKER_HOST. The Windows scanner reads only HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\* registry keys, the same data Control Panel reads.
  • Threat-IP Blocklist is the mirror image: it sends nothing about your system — it only pulls threat data down from the feed endpoint.

Every tool is open source. The privacy claims above are falsifiable: clone the repo and read the two-file source before you run it.

  • Python 3.7 or later with no additional packages (all tools use the standard library only). Present by default on every major Linux distribution and macOS.
  • Windows Scanner: Windows PowerShell 5.1 (built into every supported Windows version) or PowerShell 7+. No modules to install.
  • Docker Scanner: a working docker CLI with access to the local daemon (user must be in the docker group, or run with sudo).
  • WordPress Scanner: optional WP-CLI for active/inactive plugin status — degrades gracefully to filesystem-only detection without it.
  • An API key from valtersit.com/cve/pricing. Set it as VALTERSIT_API_KEY in your environment.
  1. Go to valtersit.com/cve/pricing and pick a scan plan (or a Standard/Pro API plan that includes scanner slots).
  2. After signup you receive a key that looks like vit_v1_xxxxxxxxxxxxxxxxxxxxxxxx.
  3. Set it once — either method works:
Terminal window
# Method 1: environment variable (recommended for cron / CI)
export VALTERSIT_API_KEY="vit_v1_your_key_here"
# Method 2: edit one line in valtersit_client.py
# API_KEY = "vit_v1_your_key_here"
Terminal window
# Windows — Method 1: environment variable
$env:VALTERSIT_API_KEY = "vit_v1_your_key_here"
# Windows — Method 2: edit one line in ValtersIT-Scan.ps1
# $ApiKey = "vit_v1_your_key_here"

Detects every installed OS package across the four major package managers — dpkg (Debian/Ubuntu), rpm (RHEL/Fedora/openSUSE), apk (Alpine), and pacman (Arch) — whichever is present on the machine you run it on.

Terminal window
# Clone from GitLab
git clone https://gitlab.com/valtersit/linux-cve-scanner
cd linux-cve-scanner
# Or one-liner (no git required)
mkdir -p linux-cve-scanner && cd linux-cve-scanner
curl -fsSLO https://gitlab.com/valtersit/linux-cve-scanner/-/raw/main/valtersit-linux-scan.py
curl -fsSLO https://gitlab.com/valtersit/linux-cve-scanner/-/raw/main/valtersit_client.py
Terminal window
export VALTERSIT_API_KEY="vit_v1_your_key_here"
python3 valtersit-linux-scan.py

On first run the tool requires you to type YES at an authorised-use confirmation prompt. After that, use --yes to skip the prompt in cron:

Terminal window
python3 valtersit-linux-scan.py --yes
ValtersIT Linux Package Scanner - target: Ubuntu 24.04.4 LTS (dpkg)
==============================================================================
INSTALLED PACKAGES (1203 total, showing 60)
==============================================================================
Package Version
------------------------------------------------------------
openssl 3.0.13-0ubuntu3.4
nginx-common 1.24.0-2ubuntu7.4
...
60 item(s) detected. No IP address, hostname, MAC address, file
contents, or credentials were read or transmitted by this scan.
==============================================================================
[+] Scan submitted. 1203 component(s) sent for matching.
{
"matched_cves": 1,
"results": [
{"slug": "openssl", "version": "3.0.13-0ubuntu3.4", "cve_id": "CVE-2026-11023",
"cvss": 7.5, "patched_in": "3.0.13-0ubuntu3.6"}
]
}

For every matched CVE, visit https://www.valtersit.com/cve/CVE-XXXX-XXXXX/ for the full write-up: CVSS vector, EPSS probability, exploit availability, patch guidance, and Shodan dorks where applicable.

Terminal window
# Daily at 03:00 — confirm authorised use interactively once first
0 3 * * * cd /opt/linux-cve-scanner && \
VALTERSIT_API_KEY=vit_v1_xxx /usr/bin/python3 valtersit-linux-scan.py --yes \
>> /var/log/valtersit-linux-scan.log 2>&1

The tool reads your package manager’s own metadata — dpkg-query, rpm -qa, apk info, or pacman -Q. It never installs, removes, or upgrades anything.


Detects the Docker Engine version and every image used by a running or stopped container on the local host (deduplicated repository + tag/digest). It only ever talks to the local Docker daemon: if DOCKER_HOST points at a remote endpoint, the scanner refuses to run.

Terminal window
# Clone from GitLab
git clone https://gitlab.com/valtersit/docker-cve-scanner
cd docker-cve-scanner
# Or one-liner
mkdir -p docker-cve-scanner && cd docker-cve-scanner
curl -fsSLO https://gitlab.com/valtersit/docker-cve-scanner/-/raw/main/valtersit-docker-scan.py
curl -fsSLO https://gitlab.com/valtersit/docker-cve-scanner/-/raw/main/valtersit_client.py
Terminal window
export VALTERSIT_API_KEY="vit_v1_your_key_here"
python3 valtersit-docker-scan.py

If you’re not in the docker group: sudo python3 valtersit-docker-scan.py.

ValtersIT Docker Scanner - Engine 29.4.3
==============================================================================
DOCKER ENGINE
==============================================================================
Component Version
-------------------------------------
docker-engine 29.4.3
==============================================================================
IMAGES IN USE BY CONTAINERS (5)
==============================================================================
Repository Tag / Digest
---------------------------------------------------------------
nginx alpine
redis 7-alpine
postgres 15
directus/directus latest
minio/minio latest
5 item(s) detected. No IP address, hostname, MAC address, file
contents, or credentials were read or transmitted by this scan.
==============================================================================
[+] Scan submitted. 6 component(s) sent for matching.
{
"matched_cves": 1,
"results": [
{"slug": "redis", "version": "7-alpine", "cve_id": "CVE-2026-44017",
"cvss": 6.8, "patched_in": "7.4.2-alpine"}
]
}
Terminal window
# Daily at 05:00
0 5 * * * cd /opt/docker-cve-scanner && \
VALTERSIT_API_KEY=vit_v1_xxx /usr/bin/python3 valtersit-docker-scan.py --yes \
>> /var/log/valtersit-docker-scan.log 2>&1

The scanner issues only docker info, docker version, and docker ps -a — it never starts, stops, or modifies any container or image.


Detects WordPress core version, every installed theme (with version and active/inactive status), and every installed plugin (version + status). If WP-CLI is available it reports active vs. inactive states; otherwise it lists everything it finds on disk. It only scans a WordPress installation physically present on the local filesystem — pass it a URL and it refuses to run.

Terminal window
# Clone from GitLab
git clone https://gitlab.com/valtersit/wordpress-cve-scanner
cd wordpress-cve-scanner
# Or one-liner
mkdir -p wordpress-cve-scanner && cd wordpress-cve-scanner
curl -fsSLO https://gitlab.com/valtersit/wordpress-cve-scanner/-/raw/main/valtersit-wp-scan.py
curl -fsSLO https://gitlab.com/valtersit/wordpress-cve-scanner/-/raw/main/valtersit_client.py
Terminal window
export VALTERSIT_API_KEY="vit_v1_your_key_here"
python3 valtersit-wp-scan.py --path /var/www/html

If run from inside the WordPress root, --path can be omitted. WP-CLI is picked up automatically if it’s in PATH.

ValtersIT WordPress Scanner - target: /var/www/html
Detection method: WP-CLI (active/inactive known)
==============================================================================
WORDPRESS CORE
==============================================================================
Component Version
-------------------------------------
wordpress-core 6.7.1
==============================================================================
ACTIVE / INSTALLED THEMES (2)
==============================================================================
Slug Version Status
--------------------------------------------------------
twentytwentyfour 1.2 active
twentytwentythree 1.4 inactive
==============================================================================
INSTALLED PLUGINS (14)
==============================================================================
Slug Version Status
------------------------------------------------------------
akismet 5.3.3 active
woocommerce 9.4.1 active
...
[+] Scan submitted. 17 component(s) sent for matching.
{
"matched_cves": 2,
"results": [
{"slug": "woocommerce", "version": "9.4.1", "cve_id": "CVE-2026-31842",
"cvss": 8.1, "patched_in": "9.4.3"},
{"slug": "akismet", "version": "5.3.3", "cve_id": "CVE-2025-90210",
"cvss": 5.4, "patched_in": "5.3.4"}
]
}

Anything with a patched_in version newer than what’s installed is your priority list. Prioritise by CVSS score, then check EPSS on the full CVE page — a high-CVSS CVE with a low EPSS score is less likely to be actively exploited than a medium-CVSS one with high EPSS.

The scanner never opens wp-config.php, never connects to MySQL, never writes to wp-content. It needs only read access to the WordPress directory — a low-privilege user is sufficient.

Terminal window
# Daily at 04:00
0 4 * * * cd /opt/wordpress-cve-scanner && \
VALTERSIT_API_KEY=vit_v1_xxx /usr/bin/python3 valtersit-wp-scan.py \
--path /var/www/html --yes >> /var/log/valtersit-wp-scan.log 2>&1

Reads every installed program from the standard HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\* registry keys — the same read-only data Control Panel uses — across both 64-bit and 32-bit entries, plus per-user installs.

Terminal window
# Clone from GitLab
git clone https://gitlab.com/valtersit/windows-cve-scanner
cd windows-cve-scanner
# Or download the single script directly
Invoke-WebRequest `
-Uri "https://gitlab.com/valtersit/windows-cve-scanner/-/raw/main/ValtersIT-Scan.ps1" `
-OutFile "ValtersIT-Scan.ps1"
Terminal window
$env:VALTERSIT_API_KEY = "vit_v1_your_key_here"
.\ValtersIT-Scan.ps1

If script execution is blocked by policy:

Terminal window
powershell -ExecutionPolicy Bypass -File .\ValtersIT-Scan.ps1

Works on Windows PowerShell 5.1 (built into Windows 10/11/Server) and PowerShell 7+. No modules to install.

ValtersIT Windows Scanner - DESKTOP-AB12CD3
==============================================================================
INSTALLED SOFTWARE (87)
==============================================================================
Name Version Publisher
---- ------- ---------
7-Zip 23.01 23.01 Igor Pavlov
Mozilla Firefox 129.0.2 Mozilla
Notepad++ (64-bit x64) 8.6.9 Notepad++ Team
...
87 item(s) detected. No IP address, hostname, MAC address, file
contents, or credentials were read or transmitted by this scan.
==============================================================================
[+] Scan submitted. 87 component(s) sent for matching.
{
"matched_cves": 1,
"results": [
{"slug": "mozilla-firefox", "version": "129.0.2",
"cve_id": "CVE-2026-27310", "cvss": 4.3, "patched_in": "130.0.1"}
]
}

Run once interactively first (to clear the authorised-use confirmation), then register the scheduled task:

Terminal window
$action = New-ScheduledTaskAction `
-Execute "powershell.exe" `
-Argument '-ExecutionPolicy Bypass -File "C:\ValtersIT\ValtersIT-Scan.ps1" -Yes'
$trigger = New-ScheduledTaskTrigger -Daily -At 4am
Register-ScheduledTask `
-TaskName "ValtersIT Windows Scan" `
-Action $action -Trigger $trigger -RunLevel Highest

The scanner does not require Administrator privileges to read the Uninstall registry keys.


Pulls the ValtersIT threat-IP feed (GET /api/v1/ip/feed, Standard plan and above) and renders it into the firewall format you need: nftables, ipset, fail2ban, pfSense (URL Table alias), or MikroTik RouterOS. For nftables and ipset it can apply the result directly with --apply.

This is the mirror image of the scanners: it sends nothing about your system — it only pulls threat data down.

Requires a Standard or Pro API plan. See API pricing →

Terminal window
# Clone from GitLab
git clone https://gitlab.com/valtersit/threat-ip-blocklist
cd threat-ip-blocklist
# Or one-liner
mkdir -p threat-ip-blocklist && cd threat-ip-blocklist
curl -fsSLO https://gitlab.com/valtersit/threat-ip-blocklist/-/raw/main/valtersit-blocklist.py
curl -fsSLO https://gitlab.com/valtersit/threat-ip-blocklist/-/raw/main/valtersit_client.py
Terminal window
export VALTERSIT_API_KEY="vit_v1_your_key_here"
# First run: verify the feed response shape
python3 valtersit-blocklist.py --format nftables --debug
# Write output to a file
python3 valtersit-blocklist.py --format nftables --output blocklist.nft
# Apply directly to this host's nftables
python3 valtersit-blocklist.py --format nftables --apply --yes
# ipset
python3 valtersit-blocklist.py --format ipset --apply --yes
# fail2ban (ban IPs into a named jail — the jail must already exist)
python3 valtersit-blocklist.py --format fail2ban --jail valtersit-threat
# pfSense — writes a plain IP list, host this file and point a URL Table alias at it
python3 valtersit-blocklist.py --format pfsense --output /srv/blocklist/valtersit.txt
# MikroTik RouterOS — generates a .rsc script to import
python3 valtersit-blocklist.py --format mikrotik --output blocklist.rsc
#!/usr/sbin/nft -f
# ValtersIT threat-IP blocklist - generated 2026-09-25T15:00:00Z
# Load with: nft -f <this file> (or pipe it in: nft -f -)
table inet valtersit_threat_ip {
set blocklist_v4 {
type ipv4_addr
flags interval
elements = {
203.0.113.5,
203.0.113.6
}
}
chain input {
type filter hook input priority 0; policy accept;
ip saddr @blocklist_v4 counter drop
}
}

The generated table fully replaces itself each run — stale entries are dropped automatically. It only ever touches the single table/set named valtersit_threat_ip (override with --list-name); it does not modify, flush, or reorder any of your existing rules.

Schedule with cron — nftables, every 6 hours

Section titled “Schedule with cron — nftables, every 6 hours”
Terminal window
0 */6 * * * cd /opt/threat-ip-blocklist && \
VALTERSIT_API_KEY=vit_v1_xxx /usr/bin/python3 valtersit-blocklist.py \
--format nftables --apply --yes >> /var/log/valtersit-blocklist.log 2>&1

For pfSense: host the generated file behind a small web server and point a Firewall > Aliases > URL Table (IPs) alias at that URL. pfSense fetches and applies it on its own refresh schedule.

For MikroTik: schedule /tool fetch to pull the regenerated .rsc file and /import it via /system scheduler.


All five scanners return the same shape: matched_cves (count) and a results array with cve_id, cvss, and patched_in. For each matched CVE:

  1. Open https://www.valtersit.com/cve/{cve-id}/ — the full record includes CVSS vector, EPSS score (probability of exploitation in the next 30 days), exploit availability, CISA KEV status, Nuclei template if one exists, and patch guidance.
  2. Sort your fix list by CVSS descending, then by EPSS descending. A CVSS 9.8 with EPSS 0.0001 is theoretically severe but rarely exploited; a CVSS 6.5 with EPSS 0.85 is being actively used in the wild.
  3. Anything in CISA KEV — cisa_kev: true — has a known exploitation record. Treat it as P1 regardless of CVSS.
  4. For has_exploit: true records, the Nuclei template or PoC link is on the CVE page. Run it against your own system before patching to confirm exploitability.

Every scanner requires you to type YES at a consent prompt on first run. The prompt text:

------------------------------------------------------------------------------
ValtersIT Scanner — Authorised Use Confirmation
------------------------------------------------------------------------------
Run this tool ONLY against systems you own, or for which you have explicit
written authorisation to assess.
This scan sends only component name + version (plus a random local
identifier) to the ValtersIT API — no IP address, hostname, or file
contents. See the Privacy Policy: https://www.valtersit.com/privacy
Type YES to confirm you are authorised to scan this system and continue.
Anything else aborts without scanning.
------------------------------------------------------------------------------

After confirming once interactively, use --yes (or -Yes on Windows) for non-interactive runs in cron or CI. The Docker scanner additionally refuses to run if DOCKER_HOST points at a remote endpoint. The WordPress scanner refuses to accept a URL as a target — --path must be a local filesystem path.

PlanFoundingRegularSystem slotsScans
Solo€8/mo€12/mo1Unlimited
Team€29/mo€44/mo5Unlimited
Agency€89/mo€135/mo25Unlimited

Founding price locked for life while the subscription stays active. Offer ends 31 Dec 2026. Standard and Pro API plans (€19/mo and €65/mo founding) include 1 and 5 scanner slots respectively — no separate scan plan needed if you already have an API subscription.

Get started →

Do the scanners need root? The Linux scanner does not — it runs the same package-manager read commands an unprivileged user can run. The Docker scanner needs docker group membership or sudo. The WordPress scanner needs read access to the WordPress directory (no need for www-data or root). The Windows scanner reads registry keys without Administrator rights.

Can I scan a remote server? No. Every scanner is designed to run on the machine it scans. The Docker scanner actively refuses to run against a remote DOCKER_HOST. The WordPress scanner only accepts a local filesystem path. This is a deliberate design choice — scanning third-party systems you don’t own requires explicit authorisation.

What if a CVE ID appears but I can’t reproduce the exploit? CVSS measures potential severity, not active exploitation. Check the EPSS score and has_exploit flag on the CVE page. If EPSS is low and no public PoC exists, monitor and patch in your normal cycle. If has_exploit: true, prioritise.

I installed a fix — how do I confirm the scanner sees it? Run the scanner again with --yes. If patched_in appears in the result, the match was on the old version; update the package/plugin/software and re-scan to confirm the CVE no longer appears.

Do the scripts need internet access beyond the API call? No. The only outbound connection is the one HTTPS call to api.valtersit.com. No CDN, no telemetry, no update checks.