WPSecScan
⚠ AUTHORIZED USE ONLY
WPSecScan is a defensive security tool. Use it only on sites you own or sites whose owner has given you written permission to test. Unauthorised scanning is illegal in most jurisdictions (e.g. the US Computer Fraud and Abuse Act, the UK Computer Misuse Act 1990, the EU Network and Information Security Directive). The maintainers accept no liability for misuse. By using this software you confirm you have the required authorisation for every target you scan.
Open-source (AGPLv3) WordPress vulnerability scanner that runs on your own machine.
294 checks (31 of them aggressive) plus an authenticated check that runs
when you supply credentials. CVE feed aggregated nightly from up to 8 public
sources; per-source counts are in the feed header. Sigstore-signed releases
with GitHub build-provenance attestations. Aggressive checks run passive
unless the target is marked as owned (see Safety).
Distribution: PyPI (pip install wpsecscan), the GitHub release assets
(wpsecscan.exe, wpsecscan-gui.exe, wheel, sdist), or a source install.
The Dockerfile in this repo is for building an image yourself; no
pre-built image is published.
Ships as two standalone Windows binaries — no Python required on the machine you run them on.
wpsecscan.exe— command-line scanner.--formattakes 9 values (json, html, csv, md, xlsx, sarif, burp, docx, exec-pdf);wpsecscan emitwrites 14 more export formats from a saved report (CycloneDX / SPDX SBOM, CEF, LEEF, …);wpsecscan badge URLwrites a shields.io-style status badge SVG.wpsecscan-gui.exe— full GUI with live progress tree, finding details, risk score, scan profiles, multi-target queue, scheduled scans, webhook alerts, exploit playbooks, and more.wp-plugin/wpsecscan-companion/— WordPress plugin (source in this repo, not a release asset) that exposes a read-only, token-gated REST endpoint so the scanner gets authoritative plugin/theme diagnostics in one round-trip instead of HTTP-probe guessing.
What it does
- Nightly CVE feed — a GitHub Action merges up to 8 public sources (NVD, GitHub Security Advisories, Mitre CVE List, OSV.dev, Wordfence, WPVulnerability, CIRCL, Patchstack RSS) into one deduped feed. Not every source returns data: on 2026-10-12 four did (NVD 500, Mitre 185, GHSA 23, OSV 10; 710 entries after merge) and four returned nothing (Wordfence API withdrawn, WPVulnerability fetch failing, Patchstack RSS discontinued, CIRCL no WordPress-relevant entries). See docs/data-sources.md.
- Daily DB refresh + per-CVE webhook alerts —
wpsecscan schedule installregisters a daily 02:00 CVE-refresh + weekly 03:00 site scan on Windows Task Scheduler / macOS launchd / Linux systemd.wpsecscan db subscribe https://hooks.slack.com/...fires the moment a new CVE drops for a plugin you have installed. - Compliance mappings for 12 frameworks, per check: PCI-DSS 4.0, NIST
800-53, ISO 27001, HIPAA, SOC 2, FedRAMP, GDPR, HITRUST CSF v11.4,
CMMC 2.0, NIST CSF 2.0, CIS Critical Controls v8, ISO 27001:2022 Annex A.
Every check also carries OWASP Top 10 and MITRE ATT&CK tags; CWE and
D3FEND tags are present on most checks, not all. (Cyber Essentials Plus
and Essential 8 exist only as scorecard helpers in
compliance_v28.py, not as per-check mappings.) - Report and export formats:
--formattakes json, html, csv, md, xlsx, sarif, burp, docx and exec-pdf;wpsecscan emitadds 14 export formats from a saved JSON report. - Ticketing and push destinations:
wpsecscan pushhas 16 providers;--push-jira,--push-linear,--push-servicenow,--push-github,--push-redmine,--push-bugzillaand--push-tracfile findings directly during a scan. - Monitoring: one continuous file-change monitor (
--continuous, needs the companion plugin and its token) plus watchers inwatchers.pyfor WordPress version drift, core-file hash diffs, DNS changes, subdomain takeover and new-CVE alerts. - Threat-intel helpers: CISA KEV and EPSS enrichment, plus wrappers
for Exploit-DB links, Metasploit module mapping, ATT&CK Navigator and
STIX export, MISP, OpenCTI, OTX and GreyNoise (
threat_intel_v2.py). - Enterprise-oriented modules in the package: OIDC and SAML SSO, RBAC, audit log, approval workflow, multi-tenant, quotas. These are library modules, not a hosted service.
- AI-assisted remediation with PII masking + prompt-injection guard +
per-backend cost tracking (7
wpsecscan aihelpers). Bring your own OpenAI / Anthropic / Ollama / llama.cpp key.WPSECSCAN_NO_AI=1to hard-disable. - Local-first: scans run on your machine, supports SOCKS5/HTTP
proxies (Tor friendly),
WPSECSCAN_NO_NETWORK=1for air-gapped mode. Usage analytics are off by default and opt-in (wpsecscan analytics).
Quick install
Option A — pip install wpsecscan (any platform)
The simplest path on Linux, macOS, or Windows-with-Python:
pip install wpsecscan
wpsecscan --version
wpsecscan https://example.com --json-only
PyPI: https://pypi.org/project/wpsecscan/
For the optional GUI minimize-to-tray feature, install with the
[ui] extra (pulls in Pillow + pystray):
pip install "wpsecscan[ui]"
Other optional extras: [pdf] (reportlab for true PDF exec reports),
[browser] (playwright for headless DOM-XSS), [yaml] (pyyaml for
daemon config), [ops] (redis + bcrypt for enterprise mode), or
[all] to install everything.
Option B — pre-built Windows binaries
- Download
wpsecscan.exeandwpsecscan-gui.exefrom the latest GitHub release. - Copy them somewhere on your PATH
(e.g.
C:\Tools\orC:\Users\<you>\bin\). - Done. No Python, no installer, no admin rights needed.
Each release also carries SHA256SUMS.txt, Sigstore .sig/.pem files and
a CycloneDX SBOM; see docs/verify-release.md to
check them.
The first time you run them, Windows SmartScreen may warn that the publisher is unknown (the binaries aren't code-signed). Click More info → Run anyway.
Option C — build from source
Requires Python 3.10+ and PyInstaller. Open PowerShell in the project root:
.\build.ps1
This creates a virtualenv in .venv\, installs the project and PyInstaller
(pip install -e .), and runs PyInstaller. Output:
dist\wpsecscan.exe # CLI (~31 MB)
dist\wpsecscan-gui.exe # GUI (~31 MB)
Both are single-file executables — copy them anywhere and they run on their own.
Option D — run from source directly (development)
python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install .
python run.py https://example.com # CLI
python run_gui.py # GUI
pytest
First scan
GUI
- Double-click
wpsecscan-gui.exe. - Paste a URL into the URL field (e.g.
https://your-wp-site.com). - Click Scan. Watch the live tree on the left and click any finding to read evidence, remediation, and the Exploit Playbook (concrete sqlmap/Metasploit/curl/nuclei commands).
- When the scan finishes, the Risk Score badge at the top shows
0-100color-coded (green/yellow/orange/red). HTML and JSON reports are saved to your user folder.
CLI
# Simple scan, HTML + JSON saved to current directory
wpsecscan.exe https://your-wp-site.com
# Custom output folder
wpsecscan.exe https://your-wp-site.com --out C:\scans\
# JSON only, no HTML
wpsecscan.exe https://your-wp-site.com --json-only --out C:\scans\
# Multiple targets from a file
wpsecscan.exe --file my-sites.txt --concurrency 5 --out C:\scans\
# Aggressive mode (active payload checks — SQLi, XSS, SSRF, etc.)
wpsecscan.exe https://your-wp-site.com --aggressive
# Authenticated scan
wpsecscan.exe https://your-wp-site.com --auth-user admin --auth-pass <pwd>
# Use a saved WPScan API token for richer plugin CVE lookups
wpsecscan.exe https://your-wp-site.com --wpscan-token <KEY>
Exit codes: 0 = clean / info only · 1 = medium findings · 2 = critical or high findings · 130 = Ctrl+C.
v2.8.x subcommand families
# Emit any of 14 formats from a saved JSON report (SBOM, CEF, LEEF,
# HIPAA/FedRAMP/CMMC mappings, risk-CSV, attestation letter, …)
wpsecscan emit cef report.json --out splunk-events.cef
wpsecscan emit spdx-sbom report.json --out sbom.json
# Push a saved report to one of 16 destinations
wpsecscan push gitlab-ci report.json # GitLab Code Quality JSON
wpsecscan push sentry report.json # Sentry release-health correlation (v2.8.3)
wpsecscan push defectdojo report.json # DefectDojo SARIF import (v2.8.3)
wpsecscan push chat report.json # Mattermost / RocketChat / Telegram
# AI helpers (LLM-backed; respects existing AI provider config)
wpsecscan ai injection-check response.txt
wpsecscan ai control-map report.json --framework hipaa
wpsecscan ai waf-rule finding.json --target-waf cloudflare # v2.8.3
# v2.8.3 utilities
wpsecscan init # interactive first-run wizard
wpsecscan check disable wpgraphql # skip a check on future scans
wpsecscan benchmark https://example.com # time each check individually
wpsecscan export-config # show effective merged config
wpsecscan compare-pypi-version # is the installed version current?
# v2.8.4 — mobile API + GUI Phase 4
wpsecscan-mobile-api # PWA backend + GUI launcher with QR enrol
# In the GUI: File menu → Push to… / Export As… / AI (16 push, 14 export, 7 AI helpers)
# Right-click a finding for "Push to…" / "AI explain" / "Export As…" context items.
# CodeQL Python SAST workflow added.
# v2.8.5 — bug-fix + CI repair release
# 3 Critical (gui _save_pref lock TOCTOU race, scanner parallel-groups WAF streak,
# history .json/.sig atomic ordering), 10 High (mobile_api dead /findings/ branch,
# do_OPTIONS scope, POST /api/scan rate-limit, QR-URL token leak, PhotoImage base64,
# cdn_edge_audit precedence, payment_commerce or-await, a11y walrus, sites atomic,
# creds_vault RMW), 7 Medium, 1 syntax-fix (3.10/3.11 CI green).
What it checks (294 checks)
Passive checks always run; aggressive checks need --aggressive and a target marked as owned (see Safety).
- Recon: WP core version · plugin enum (slug + version) · theme enum · user enum (
?author=, RESTwp/v2/users) - Surface: 40+ exposed-path probes (
.env,wp-config.php.bak,.git/config, debug.log, backup-plugin dumps, phpinfo, adminer, …) · WebDAV / OPTIONS enum · beta/test/debug query-parameter discovery - Auth surface:
wp-login.php+ XML-RPC method enum +system.multicallamplifier check + rate-limit probe · OAuth2/OIDC discovery audit · SAML / XSW endpoint discovery · JWT audit (alg=none+ weak HS256 brute-force) - Transport: TLS version, cert expiry, HSTS, CSP, X-Frame-Options, Referrer-Policy, Permissions-Policy, cookie flags
- APIs: REST namespace map, REST OPTIONS write-method enum, WPGraphQL introspection, CORS misconfig (full preflight matrix incl.
nullorigin reflection) - Defensive posture: WAF / CDN detection · WAF rule-set identification (CRS / AWS / Cloudflare Managed / Wordfence Premium) · DNS SPF / DMARC / DKIM · security.txt · AbuseIPDB reputation (opt-in)
- Supply-chain: external JS hosts + SRI hash check · source-map exposure · JS library version audit · S3 bucket discovery + public-ACL probe · GitHub leaked-token search (opt-in, scans your domain against AKIA/sk_live_/ghp_/etc.)
- Subdomain attack surface: certificate-transparency discovery · dangling-CDN takeover candidates · cookie-tossing chain detection (apex-cookie + takeover-able subdomain)
- Server fingerprint: Server-Timing, X-Request-ID, X-Debug-Token leaks
- CVE matching: the nightly aggregated feed (plus a small embedded fallback) + 311 exploit signatures + 224 payloads · CISA KEV catalog enrichment · EPSS percentile scoring · VirusTotal URL/IP enrichment (opt-in)
- Aggressive (
--aggressive): SQLi (error-based + time-blind escalator) · reflected XSS · SSRF · path traversal · open redirect · file upload · default credentials (max 10) · SSTI (7 template engines) · NoSQL operator injection · path-normalisation bypass (..%2f,..;/, …) · race-condition probe (parallel POSTs) · active HTTP smuggling (CL.TE / TE.CL) · headless DOM-XSS (Playwright, optional) - Deep (
--deep-throttle): 10-500 wrong-password attempts at 5-60s pacing to map your login throttle threshold (synthetic non-existent user, fixed wrong password — never brute-force) - Authenticated (
--auth-user/--auth-pass): logs in, audits user roles, plugins, Site Health, options
Round-54 additions (A1-G4 catalogue)
Round fifty-four added the checks and non-check tooling below (the current registry total is given in the heading of the previous section):
| Area | New |
|---|---|
| Active probes | ssti, nosql_injection, path_bypass, race_condition, dom_xss_headless (Playwright optional) |
| Passive / intel checks | webdav, dev_params, abuseipdb_lookup (--abuseipdb-token), waf_ruleset, oauth_oidc, saml_xsw, s3_bucket_discovery, github_leak_search (--github-search-token), jwt_audit |
| Modified checks | subdomains (B7 cookie-tossing chain), cors (B8 preflight matrix incl. Origin: null), sqli (A3 time-blind escalator), smuggling_probe (A6 active CL.TE/TE.CL) |
| Threat-intel integrations | CISA KEV, EPSS, VirusTotal, Sucuri SiteCheck, NVD/Wordfence CVE explainer |
| Per-check tags | new cwe (e.g. CWE-79) + d3fend (e.g. D3-IVA) fields in data/check_tags.json |
| Reporters | one-page executive PDF (--exec-pdf, uses reportlab or HTML fallback) · two-report drag-and-drop HTML diff viewer · Burp Suite scope XML (--burp-export) · severity × OWASP-category SVG heatmap embedded in HTML report |
| CLI flags | --fail-on, --diff-against, --shell, --replay-har, --daemon, --abuseipdb-token, --vt-token, --github-search-token, --burp-export, --exec-pdf |
| GUI windows | step-by-step exploit-playbook walker (right-click any finding) · drill historical findings by OWASP/ATT&CK/CWE/D3FEND tag · multi-URL risk-score trend overlay · drop-in marketplace browser · 5-step first-run tutorial |
| Collab | assign-owner + comment threads per finding (right-click) |
| Infra / docs | .github/workflows/wpsecscan.yml (nightly + PR scans) · GitLab CI / Jenkins / Azure DevOps templates in ci/ · Dockerfile + docker-compose.yml · SDK.md · DISTRIBUTED-SCAN.md · audit-log JSONL of every scan invocation · custom signature / payload drop-in (~/.wpsecscan/{signatures,payloads}/) · i18n stub (en + es) |
Output formats
Every scan produces:
| Flag | File | Use case |
|---|---|---|
| (default) | <host>-<ts>.html |
Open in a browser. Has copy-to-clipboard buttons for every command, color-coded exploit playbooks, and a "🖨 Print / Save as PDF" button in the top-right corner. |
| (default) | <host>-<ts>.json |
Includes per-finding confidence (low/medium/high) and per-check tags (OWASP Top 10 + MITRE ATT&CK). For downstream tooling. |
--csv |
<host>-<ts>.csv |
Spreadsheet import. Cells are escaped against Excel formula-injection. |
--sarif |
<host>-<ts>.sarif |
GitHub Code Scanning, Azure DevOps, anything that ingests SARIF 2.1.0. |
--json-only |
suppresses HTML | CI / scripted use. |
--md |
<host>-<ts>.md |
Markdown report for Confluence / GitHub / Slack threads. |
--xlsx |
<host>-<ts>.xlsx |
Excel workbook with per-OWASP-category sheets. |
--har FILE.har |
FILE.har |
HAR 1.2 recording of every HTTP request (Cookie/Authorization redacted). Replay with --replay-har. |
--burp-export |
<host>-<ts>-burp-scope.xml |
Burp Suite scope XML for hand-off to manual testing. |
--exec-pdf |
<host>-<ts>-exec.pdf |
One-page non-technical executive summary. Uses reportlab if installed, else writes a print-friendly HTML file. |
Round-54 CLI additions
| Flag | Purpose |
|---|---|
--fail-on critical|high|medium |
Override exit-code logic — non-zero only when a finding meets or exceeds the threshold. |
--diff-against BASELINE.json |
Compute the NEW / RESOLVED delta vs a saved JSON report, print to stdout. |
--shell |
After scan, drop into a Python REPL with report pre-bound (for power users / IR). |
--replay-har HAR_FILE |
Re-run every request in a HAR file; optionally override the origin with <target>. |
--daemon CONFIG.yml |
Cron-style scheduled scans driven by a YAML config (no Task Scheduler required). |
--abuseipdb-token TOKEN |
Enables the AbuseIPDB reputation check for the target's IP. |
--vt-token TOKEN |
Enables VirusTotal URL/IP enrichment. |
--github-search-token PAT |
Enables GitHub code-search for the target's domain + common secret prefixes. |
Round-56 visibility flags
| Flag | Purpose |
|---|---|
--demo |
Synthetic scan against a fake target — every check fires fake findings, every integration fires a fake activity event. Writes one of every artifact to ~/.wpsecscan/demo/. Great for screenshots, smoke-testing an install, or training new users. |
--no-live |
Disable the live multi-panel rich dashboard during scans. The static console reporter still renders at the end. Useful for CI logs / piped output. |
Power-user features (GUI)
- Risk score: 0–100, color-coded. Calculated from severity weights with per-tier caps.
- Profiles (File → Profiles): save the current toggle/pacing/threshold set as
"Quick","Deep","Audit"etc. Loads with one click. Stored in~/.wpsecscan/profiles.json. - Recent URLs: the URL field is a dropdown of the last 20 scanned sites.
- Diff with last scan: button appears after a scan if a previous JSON for the same URL exists in
~/.wpsecscan/reports/. Shows[NEW]/[RESOLVED]per finding. - Multi-target scan (Tools → Multi-target): paste/load a list of URLs, scan each in turn, one-row-per-site dashboard with risk score and Δ-vs-last-scan.
- Scheduled recurring scan (Tools → Schedule): registers a Windows Task Scheduler job (
WPSecScan_<host>) that runs daily/weekly/monthly at a chosen time. Outputs to a folder you pick. Remove withschtasks /Delete /TN WPSecScan_<host> /F. - Risk-score trend (Tools → Show risk trend): ASCII sparkline of historical scores for the current URL.
- Webhook notify (File → Settings → "Webhook notify"): one POST to Slack/Discord/Teams/PagerDuty when a scan finds ≥ chosen severity. Hosts validated against an allow-list — won't post to arbitrary URLs or raw IPs.
- Finding annotations: right-click any finding → "Accepted risk" / "False positive" with an optional note. Persisted per-URL in
~/.wpsecscan/annotations.json. - Filter pills: Only NEW (vs last scan), Only CONFIRMED (signature engine actively verified), Hide annotated, per-severity show/hide.
- Exploit playbook: every finding's detail pane includes concrete attacker-side commands (curl PoCs · sqlmap · Metasploit · nuclei · wpscan · ffuf) with
{target}already substituted, plus a plain-English "How an attacker uses this" paragraph. - OWASP + MITRE chips: every check is tagged with its OWASP Top 10 category (e.g.
A03:2021) and MITRE ATT&CK technique (e.g.T1190). Shown inline in the GUI and console. - Exploit confidence: each finding carries a confidence badge (HIGH / MED / LOW) separate from severity —
[CONFIRMED]findings are HIGH; presence of a WAF downgrades unconfirmed findings by one tier. - Cancel-mid-scan: clicking Cancel during the 20-min deep throttle test returns a partial result with what was learned so far.
CLI flag reference (most-used)
USAGE: wpsecscan.exe [URL] [options]
Targets:
URL A single site (https://example.com)
--file FILE Newline-separated list of URLs
Output:
--out PATH Output directory or filename stem (default: cwd)
--json-only Suppress HTML
--html-only Suppress JSON
--csv Also write CSV
--sarif Also write SARIF 2.1.0
--quiet, -q Suppress the colored console table (alias: --no-console)
-v / -vv Increase console verbosity (per-check / HTTP-level)
Modes:
--aggressive Enable active payload checks (SQLi, XSS, SSRF, etc.)
--prove For each confirmed aggressive finding, run a read-only
proof extractor. Requires --aggressive. Read-only.
--deep-throttle Run the deep login-throttle mapper
--deep-throttle-attempts N (10-500, default 120)
--deep-throttle-pacing S (5-60 seconds, default 10)
--auth-user USER Admin username for authenticated scan (env: WPSECSCAN_AUTH_USER)
--auth-pass PASS Admin password (env: WPSECSCAN_AUTH_PASS; use `-` to read from stdin)
--ssh-audit user@host Connect via SSH and run a read-only wp-cli audit
--password-audit FILE Offline: convert wp_users dump to a hashcat-ready file (NO network)
Tuning:
--timeout SECONDS Per-request timeout (default 15)
--concurrency N Concurrent requests per host (default 10)
--user-agent STRING Custom User-Agent
--insecure Don't verify TLS certs
--wpscan-token TOKEN WPScan API token (richer plugin CVE data)
--hibp-token TOKEN HaveIBeenPwned API key
Maintenance:
--update-db Refresh the local vulnerability database (aggregated feed)
(exits 75 on remote-fetch failure for CI detection)
--diff OLD.json NEW.json Diff two saved JSON reports
--baseline BASELINE.json Diff scan-in-progress against a saved baseline (alias: --diff-against)
--debug Verbose internal logging to ~/.wpsecscan/logs/
--completion {bash,zsh,powershell} Print shell-completion script and exit
--version
Subcommands (66 in total; `wpsecscan --help` lists them, `wpsecscan <subcommand> --help` gives details; a few of them):
sites Manage a list of sites (add/list/scan/remove)
schedule Install/uninstall a Windows-Scheduler / launchd / systemd cron
digest Configure SMTP / webhook digests of new findings
ai-cost Print AI-triage cost summary
ai-options Read/set Advanced AI-triage toggles
analytics Manage opt-in analytics
db vuln DB management (status / update / signatures / source-stats / subscribe / alert-check)
compare URL Diff the two most-recent saved snapshots of a URL
badge URL Emit a shields.io-style SVG of the latest scan grade
Configuration files
Everything is stored in ~/.wpsecscan/ (i.e. C:\Users\<you>\.wpsecscan\):
| Path | Purpose |
|---|---|
history.json |
Last 20 scanned URLs (GUI dropdown) |
profiles.json |
Named scan profiles (toggles + deep-throttle settings) |
settings.json |
Tokens saved via the GUI onboarding wizard |
sites.json |
Managed-sites list for wpsecscan sites + scheduling |
schedule_state.json |
Cron-style state for wpsecscan schedule |
digest.json |
Configured SMTP / webhook digest destinations |
annotations.json |
Per-finding annotations (accepted-risk / FP) |
comments.json |
Per-finding free-text comments |
stars.json |
Starred findings (GUI sidebar) |
disabled_checks.json |
Persistently disabled check IDs |
reports/{host}.json |
Latest-scan snapshot per URL (canonical) |
reports/{host}-{YYYYmmdd-HHMMSS}.json |
Timestamped snapshot history (for compare, trend) |
cache/wporg/{slug}.json |
24h-cached wp.org plugin metadata (plugin_cemetery) |
checkpoints/ |
--checkpoint resumable scan state |
logs/ |
--debug log files |
demo/ |
--demo synthetic-scan artifacts |
analytics/events.jsonl |
Opt-in analytics (off by default; wpsecscan analytics) |
wordfence.json |
Local cache of the aggregated CVE database |
Override the base dir with the WPSECSCAN_HOME environment variable.
Shell completions
# bash
wpsecscan --completion bash > /etc/bash_completion.d/wpsecscan
# zsh
wpsecscan --completion zsh > "${fpath[1]}/_wpsecscan"
# PowerShell
wpsecscan --completion powershell | Out-File -Append $PROFILE
Restart the shell to activate.
Secrets via env vars
Every sensitive flag — --auth-pass, --auth-app-password,
--companion-token, --proxy-auth, --wpscan-token,
--patchstack-token, --hibp-token, --vt-token, --abuseipdb-token,
--github-search-token — reads from a matching WPSECSCAN_<UPPER>
environment variable when not passed on the CLI. Use --auth-pass -
to read the password from stdin via getpass (stops it leaking into
ps aux / shell history).
Safety
- Use only on sites you own or have written permission to test. Online password brute-force is permanently out of scope. The "deep throttle" probe uses a synthetic non-existent username and a fixed wrong password — it maps your defense, it does not guess passwords.
- Aggressive mode runs passive unless the target is marked as owned: pass
--owned, setWPSECSCAN_OWNED_TARGETS, or runwpsecscan owned add <host>. - All active payloads are read-only. The payload library is enforced at load-time with a pytest invariant that scans for any write-side operations.
- The webhook URL allow-list rejects raw IPs, internal addresses (incl. AWS metadata
at
169.254.169.254), and unknown hosts. - Authenticated scans run with the credentials you provide but never log them.
- The scheduled-task URL validator enforces a strict regex to prevent shell-meta
injection in the registered
schtaskscommand.
Troubleshooting
"Windows protected your PC" SmartScreen warning — click More info → Run anyway. The binaries aren't code-signed.
Defender quarantines wpsecscan.exe with Backdoor:JS/Chopper.GG!dha — known false positive.
This is a defensive scanner: to detect webshells (China Chopper, c99, r57) on your sites
it ships references to those attack patterns. Defender's pattern-matching heuristic flags
the .exe even though it never executes any of those patterns locally. The same kind of
detection trips sqlmap, Metasploit, nuclei, and Gophish — all legitimate security tools.
Three ways to fix it:
-
In the GUI: a dialog pops up on first launch with an "Add exclusion now (UAC)" button. You can also open it any time via Tools → Add Windows Defender exclusion...
-
From admin PowerShell (manual, one line):
Add-MpPreference -ExclusionPath 'C:\path\to\dist'
Replace
C:\path\to\distwith the actual folder containing the.exebinaries. -
Via the bundled helper script (auto-detects the binary location, prompts UAC):
.\scripts\add-defender-exclusion.ps1
To restore a quarantined file: Windows Security → Virus & threat protection → Protection history → Allow.
This program does NOT:
- Install a backdoor on your computer.
- Open any listening port on your machine.
- Send data anywhere except to the WordPress URLs you type in.
- Run any of the webshells in its signature list — those are strings used to RECOGNISE webshells on your sites, not to execute them.
"DB: not loaded — click Refresh" in the GUI — click Refresh vuln DB. Or from the CLI: wpsecscan.exe --update-db.
Scan stalls on a hung target — --timeout 5 cuts the per-request wait.
Multi-target scan freezes for one bad URL — each URL has its own per-request timeout. If one consistently hangs, drop it from the list.
Cron / scheduled-task entries pile up — list them with schtasks /Query /TN WPSecScan_* and remove individually with schtasks /Delete /TN <name> /F.
GUI crashes immediately on launch — check C:\Users\<you>\.wpsecscan\ is writable.
Run from a terminal to see the traceback: wpsecscan-gui.exe (the windowed
build suppresses console output by design — run via python run_gui.py from a checkout
to see errors).
Inventory
| Category | Count |
|---|---|
| Checks | 294 (+ authenticated; 31 aggressive) |
| Payloads | 224 |
| Exploit signatures | 311 |
| Plugin CVE database | nightly aggregated feed from up to 8 public sources (see docs/data-sources.md) |
| Exploit-playbook entries | 39 |
License & disclaimer
Licensed under AGPLv3+ (from v1.9.0 onward — v1.0.0..v1.8.0 were MIT). See LICENSE and NOTICE.
AGPL network clause: if you run a modified WPSecScan as a hosted service (SaaS, web UI, paid scanning tier), you must publish your modified source under the same AGPLv3+ terms. Private internal use and modifications stay private. For commercial-distribution licensing terms outside AGPLv3, contact bryaninbangkok@gmail.com.
This tool is for defensive use on sites you own. Use against third-party sites without explicit written permission is illegal in most jurisdictions under the Computer Fraud and Abuse Act (US) / Computer Misuse Act (UK) / equivalent laws elsewhere.
The authors take no responsibility for misuse.
Metadata
Release files for wpsecscan 2.9.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| wpsecscan-2.9.0.tar.gz | 1.3 MB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| wpsecscan-2.9.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 2.7 MB
Release files / wpsecscan-2.9.0.tar.gz
| Download URL | wpsecscan-2.9.0.tar.gz |
|---|---|
| Size | 1.3 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
824736e50ac2db554a84dd36f276e5c2feaedce65026fd75f90d666812983cfc
|
|
BLAKE2b-256 checksum How to use checksums |
caff62db35ce0602052fc8817cd0f00d4b830631311d155a7e1f7f1e3e1471b4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.
Transparency logRelease files / wpsecscan-2.9.0-py3-none-any.whl
| Download URL | wpsecscan-2.9.0-py3-none-any.whl |
|---|---|
| Size | 1.4 MB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a4a6188997b359bc037616e83988aa33ae0a0ad001958fa4adc0ee5f605c249d
|
|
BLAKE2b-256 checksum How to use checksums |
4f05f17cbe70b56cd8617e4df898d3ad5a4cc78b75828cbcfb01c5bcf1d5ba78
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.
Transparency log