- What is Plecost?
- Plecost vs WPScan
- Quick Start
- Installation
- CVE Database
- Scanning
- Detection Modules
- WooCommerce Security
- WP eCommerce Security
- Output Formats
- Library Usage
- Environment Variables
- Architecture
- Troubleshooting
- Local Test Environment
- License
Plecost detects vulnerabilities in WordPress installations — core, plugins, and themes — and correlates findings against a daily-updated local CVE database. It runs as a CLI tool, a Python library, or inside task queues like Celery, with a consistent and automation-friendly output format.
No Ruby. No API key. No subscription. No data sent to third parties on every scan.
Plecost was built from scratch to fix the limitations teams hit in production when using WPScan: API rate caps, external data dependencies, no library API, no async architecture, and a narrow detection surface.
| Capability | Plecost v4 | WPScan |
|---|---|---|
| Language / runtime | Python 3.11+ | Ruby |
| Async concurrent scanning | ✅ httpx + asyncio | ❌ |
| Python library API | ✅ from plecost import Scanner |
❌ |
| API key required | ❌ never | |
| CVE data — free tier limit | ✅ unlimited (local DB) | ❌ 25 API tokens/day |
| Offline scanning (CVEs included) | ✅ | ❌ |
| Data sent to third parties on scan | ❌ none | |
| Docker native | ✅ | ✅ |
| Celery / task queue compatible | ✅ | ❌ |
| PostgreSQL support (shared team) | ✅ | ❌ |
| Capability | Plecost v4 | WPScan |
|---|---|---|
| Fast mode (top 150 plugins / 50 themes) | ✅ | ❌ |
| Deep mode (4,750+ plugins / 900+ themes) | ✅ | ✅ |
| Configurable concurrency (10–50 requests) | ✅ | ✅ |
| Stealth mode (random UA + passive only) | ✅ | ✅ |
| Aggressive mode (50 parallel requests) | ✅ | ✅ |
| Authenticated scans | ✅ | ✅ |
| Proxy support (HTTP + SOCKS5) | ✅ | ✅ |
| Bulk scan (multiple URLs from file) | ✅ | ❌ |
| Pre-flight 403 detection (aborts cleanly) | ✅ | ❌ |
Per-module options (--module-option) |
✅ | ❌ |
| Run / skip individual modules | ✅ | ✅ |
Selective module list (--modules) |
✅ | ❌ |
| Auto-retry with SSL verification disabled | ✅ | ❌ |
| Capability | Plecost v4 | WPScan |
|---|---|---|
| WordPress core fingerprinting | ✅ (meta, readme, RSS, wp-login) | ✅ |
| Plugin detection — passive HTML | ✅ | ✅ |
| Plugin detection — active wordlist | ✅ 4,750+ slugs | ✅ |
| Theme detection — passive HTML | ✅ | ✅ |
| Theme detection — active wordlist | ✅ 900+ themes | ✅ |
| CVE correlation (core + plugins + themes) | ✅ local DB, daily NVD sync | ✅ API |
| Exploit availability flag per CVE | ✅ | ✅ |
| CVSS scores per finding | ✅ | ✅ |
| WAF / CDN detection | ✅ 7 providers | |
| User enumeration — REST API | ✅ | ✅ |
| User enumeration — author archives | ✅ | ✅ |
| XML-RPC — access, pingback DoS, method list | ✅ 3 checks | |
| REST API — disclosure, oEmbed, CORS | ✅ 3 checks | ❌ |
| HTTP security headers | ✅ 8 checks (HSTS, CSP, X-Frame…) | ❌ |
| SSL / TLS misconfiguration | ✅ 3 checks | ❌ |
| Misconfiguration (wp-config, .env, .git…) | ✅ 12 checks | |
| Directory listing (wp-content subdirs) | ✅ | ❌ |
| Debug mode / PHP version disclosure | ✅ | ❌ |
| Open user registration | ✅ | ❌ |
| Content / card skimmer analysis | ✅ scripts, iframes, hardcoded keys | ❌ |
| Webshell detection | ✅ 147–523 paths | ❌ |
| Malicious upload detection (PHP in uploads) | ✅ | ❌ |
| WooCommerce dedicated module | ✅ 22 checks | ❌ |
| WP eCommerce dedicated module | ✅ 22 checks | ❌ |
| Semi-active eCommerce CVE probes | ✅ boolean-only, no time-based | ❌ |
| WooCommerce REST API auth bypass | ✅ CVE-2023-28121 | ❌ |
| WooCommerce IDOR / PII disclosure | ✅ CVE-2023-34000 | ❌ |
| Capability | Plecost v4 | WPScan |
|---|---|---|
| Rich terminal output (color-coded) | ✅ | ✅ |
| JSON output (stable schema) | ✅ | ✅ |
Verbose real-time progress (-v) |
✅ | ✅ |
| Quiet mode (HIGH + CRITICAL only) | ✅ | ❌ |
| Stable permanent finding IDs | ✅ 79 IDs (PC-MOD-NNN) |
❌ |
plecost explain <ID> — per-finding remediation |
✅ | ❌ |
| Safe to track findings in JIRA / ticketing | ✅ IDs never change | ❌ |
Remediation ID per finding (REM-MOD-NNN) |
✅ | ❌ |
| i18n / multilingual output | ✅ EN + ES | ❌ |
| Included vulnerable test environment (DVWP) | ✅ Docker Compose | ❌ |
WPScan sends every scan to
wpscan.comto look up CVE data. On the free tier you get 25 API tokens per day — enough for a handful of targets. Plecost keeps the entire CVE database locally, updated daily via GitHub Actions with no per-scan network call to any third-party API.
| Plecost v4 | WPScan | |
|---|---|---|
| Local CVE database (SQLite / PostgreSQL) | ✅ | ❌ |
| Data sent externally on each scan | ❌ none | ✅ to wpscan.com |
| CVE updates mechanism | GitHub Actions, NVD API v2 | SaaS subscription |
| Daily incremental patch download | ✅ (< 100 KB/day) | — |
| First-run full database download | ✅ plecost update-db |
— |
| Works fully air-gapped after DB download | ✅ | ❌ |
| SHA256 integrity check before download | ✅ | ❌ |
pip install plecost
# Download the CVE database (first time only — takes a few seconds)
plecost update-db
# Scan a target
plecost scan https://target.wordpress.comThat's it. No account, no API key, no daemon running in the background.
pip
pip install plecost
pip install plecost[fast] # adds uvloop for higher throughput
pip install plecost[postgres] # adds asyncpg for PostgreSQL supportDocker
docker run --rm ghcr.io/plecost/plecost scan https://target.com
# Save JSON report to local directory
docker run --rm -v $(pwd):/data ghcr.io/plecost/plecost scan https://target.com \
--output /data/report.jsonFrom source
git clone https://github.com/Plecost/plecost.git
cd plecost
pip install -e ".[dev]"Plecost ships with a local SQLite database covering WordPress core, plugins, and themes. It lives at ~/.plecost/db/plecost.db and is never sent to any external service during scans.
The database needs to be downloaded once before the first scan, and kept up to date thereafter.
plecost update-dbThis downloads a pre-built snapshot from plecost-db releases (~10–50 MB). Subsequent runs only download the daily diff — typically under 100 KB.
Run update-db regularly (weekly is fine for most use cases):
plecost update-dbPlecost checks a SHA256 checksum before downloading anything. If nothing changed since your last run, no data is transferred.
The plecost-db repository runs a GitHub Actions workflow daily at 02:00 UTC. It queries the NVD API v2.0 for all WordPress-related CVEs modified in the last 24 hours, applies Jaro-Winkler fuzzy matching to correlate CVE product names against ~50,000 known plugin/theme slugs, and publishes a small JSON patch file as a release asset.
When you run plecost update-db, it:
- Downloads
index.jsonfrom theplecost-dbreleases (64 bytes) - Compares its SHA256 against the local copy
- Downloads only the missing patch files and applies them in order
- On first run, downloads
full.jsoninstead (complete history)
| Run | What's downloaded | Typical size |
|---|---|---|
| First time | full.json (all CVEs) |
10–50 MB |
| Daily update | today's patch | < 100 KB |
| Already up to date | nothing (checksum match) | 64 bytes |
# SQLite at a custom path
export PLECOST_DB_URL=sqlite:////data/plecost.db
plecost update-db
plecost scan https://target.com
# PostgreSQL (shared team setup)
pip install plecost[postgres]
export PLECOST_DB_URL=postgresql+asyncpg://user:pass@host/plecost
plecost update-db
plecost scan https://target.com$ plecost scan https://target.com
Plecost v4.1 — WordPress Security Scanner
Target: https://target.com
WordPress 6.4.2 detected | WAF: Cloudflare
Plugins (3)
woocommerce 8.2.1 VULNERABLE
contact-form-7 5.8 OK
elementor 3.17.0 OK
Findings (7)
PC-CVE-CVE-2023-28121 WooCommerce SQLi CRITICAL
PC-SSL-001 HTTP does not redirect to HTTPS HIGH
PC-HDR-001 Missing Strict-Transport-Security MEDIUM
PC-USR-001 User enumeration via REST API MEDIUM
PC-XMLRPC-001 XML-RPC interface accessible MEDIUM
PC-REST-001 REST API user data exposed LOW
PC-MCFG-009 readme.html discloses WP version LOW
Summary: 1 Critical 1 High 3 Medium 2 Low | Duration: 4.2s
# Authenticated scan
plecost scan https://target.com --user admin --password secret
# Route traffic through Burp Suite or OWASP ZAP
plecost scan https://target.com --proxy http://127.0.0.1:8080
# Run only specific detection modules
plecost scan https://target.com --modules fingerprint,plugins,cves
# Aggressive mode — 50 parallel requests (use on internal targets)
plecost scan https://target.com --aggressive
# Deep mode — full wordlist (4750+ plugins, 900+ themes); default scans top 150/50
plecost scan https://target.com --deep
# Stealth mode — random UA, passive detection only, slower
plecost scan https://target.com --stealth
# Save results as JSON
plecost scan https://target.com --output report.json
# Show only HIGH and CRITICAL findings
plecost scan https://target.com --quiet| Flag | Description | Default |
|---|---|---|
--concurrency N |
Parallel requests | 10 |
--timeout N |
Request timeout (seconds) | 10 |
--proxy URL |
HTTP or SOCKS5 proxy | — |
--user / -u |
WordPress username | — |
--password / -p |
WordPress password | — |
--modules |
Modules to run (comma-separated) | all |
--skip-modules |
Modules to skip | — |
--stealth |
Passive mode, random UA, slower pacing | off |
--aggressive |
Max concurrency (50 requests) | off |
--output / -o |
JSON output file | — |
--no-verify-ssl |
Skip certificate verification | off |
--force |
Scan even if WordPress not detected | off |
--deep |
Full wordlist scan (4750+ plugins, 900+ themes); default is top 150/50 | off |
--verbose / -v |
Real-time module progress and findings during scan | off |
--quiet |
Show only HIGH and CRITICAL findings | off |
--module-option |
Module-specific option: MODULE:KEY=VALUE (repeatable) |
— |
Plecost runs 18 async modules in parallel, wired through an explicit dependency graph. Modules without interdependencies run concurrently from the start; cves waits for plugins and themes to complete before correlating results against the local database.
| Module | What it checks | Finding IDs |
|---|---|---|
fingerprint |
WordPress version (meta, readme, RSS, wp-login) | PC-FP-001/002 |
waf |
WAF/CDN detection (Cloudflare, Sucuri, Wordfence, Imperva, AWS, Akamai, Fastly) | PC-WAF-001 |
plugins |
Plugin enumeration — passive HTML + brute-force against readme.txt |
PC-PLG-NNN |
themes |
Theme detection via passive scan + style.css brute-force |
PC-THM-001 |
users |
User enumeration via REST API and author archive pages | PC-USR-001/002 |
xmlrpc |
XML-RPC access, pingback.ping DoS vector, system.listMethods |
PC-XMLRPC-001/002/003 |
rest_api |
REST API link disclosure, oEmbed, CORS misconfiguration | PC-REST-001/002/003 |
misconfigs |
12 checks: wp-config.php, .env, .git, debug.log, directory traversal... |
PC-MCFG-001–012 |
directory_listing |
Open directory listing in wp-content/ subdirs |
PC-DIR-001–004 |
http_headers |
Missing HSTS, CSP, X-Frame-Options, X-Content-Type, Referrer-Policy... | PC-HDR-001–008 |
ssl_tls |
HTTP→HTTPS redirect, certificate validity, HSTS preload | PC-SSL-001/002/003 |
debug_exposure |
Active WP_DEBUG, PHP version disclosure via response headers |
PC-DBG-001/003 |
content_analysis |
Card skimming scripts, suspicious iframes, hardcoded API keys | PC-CNT-001/002/003 |
auth |
Authenticated checks: login verification, open user registration | PC-AUTH-001/002 |
cves |
CVE correlation for core + plugins + themes against local DB | PC-CVE-{CVE-ID} |
webshells |
Webshell detection across upload paths (147–523 paths depending on mode) | PC-WS-NNN |
woocommerce |
WooCommerce-specific security checks (see below) | PC-WC-000–021 |
wp_ecommerce |
WP eCommerce-specific security checks (see below) | PC-WPEC-000–021 |
Use plecost explain <ID> for full technical detail and remediation steps on any finding ID.
The woocommerce module performs dedicated security checks for WooCommerce installations and its official extensions (Payments, Blocks, Stripe Gateway). It runs automatically when WooCommerce is detected.
- Fingerprinting — detects WooCommerce version, active extensions (Payments, Blocks, Stripe Gateway), and exposed API namespaces
- REST API without authentication — checks whether
/wp-json/wc/v3/customers,/orders,/coupons, and/system-statusare accessible without credentials (CRITICAL/HIGH) - Sensitive file exposure — directory listing on
/wp-content/uploads/wc-logs/, access to/wp-content/uploads/woocommerce_uploads/
Semi-active checks send additional HTTP requests that could leave traces in server logs. Enable explicitly:
plecost scan https://target.com --module-option woocommerce:mode=semi-active| Check | CVE | CVSS |
|---|---|---|
| WooCommerce Payments authentication bypass | CVE-2023-28121 | 9.8 Critical |
| WooCommerce Stripe Gateway IDOR (PII disclosure) | CVE-2023-34000 | 7.5 High |
Provide WooCommerce REST API credentials to unlock additional checks (system configuration disclosure, payment gateway enumeration):
plecost scan https://target.com \
--module-option woocommerce:wc_consumer_key=ck_xxx \
--module-option woocommerce:wc_consumer_secret=cs_xxxWhen WooCommerce is detected, the scan result includes a dedicated woocommerce section:
{
"woocommerce": {
"detected": true,
"version": "8.5.2",
"active_plugins": ["core", "payments", "blocks", "stripe-gateway"],
"api_namespaces": ["wc/store/v1", "wc/v3"]
}
}The wp_ecommerce module performs dedicated security checks for the WP eCommerce (wp-e-commerce) plugin. It runs automatically when WP eCommerce is detected.
Important: WP eCommerce has been abandoned since 2020 (last version: 3.15.1). All current installations are vulnerable to unpatched CVEs. PC-WPEC-003 is always emitted when the plugin is detected.
- Fingerprinting — detects version via
readme.txt, active payment gateways (ChronoPay) - Directory exposure — plugin directory listing,
uploads/wpsc/,uploads/wpsc/digital/(digital downloads) - Admin scripts — direct access to
wpsc-admin/db-backup.phpandwpsc-admin/display-log.php - ChronoPay endpoint — callback endpoint accessibility check
Enable explicitly:
plecost scan https://target.com --module-option wpec:mode=semi-active| Check | CVE | CVSS |
|---|---|---|
| ChronoPay SQL Injection | CVE-2024-1514 | 9.8 Critical |
| PHP Object Injection via AJAX | CVE-2026-1235 | 8.1 High |
Detection is boolean-only (SQL error strings, deserialization patterns) — no time-based probes.
When WP eCommerce is detected, the scan result includes a dedicated wp_ecommerce section:
{
"wp_ecommerce": {
"detected": true,
"version": "3.15.1",
"active_gateways": ["chronopay"],
"checks_run": ["readme", "directories", "sensitive_files", "chronopay_endpoint"]
}
}Rich-formatted tables with color-coded severities. Use --quiet to suppress LOW/MEDIUM findings.
plecost scan https://target.com --output report.json{
"url": "https://target.com",
"scanned_at": "2026-04-13T09:00:00Z",
"is_wordpress": true,
"wordpress_version": "6.4.2",
"waf_detected": "Cloudflare",
"plugins": [{ "slug": "woocommerce", "version": "8.2.1" }],
"themes": [{ "slug": "twentytwentyfour", "version": "1.2" }],
"users": ["admin", "editor"],
"findings": [
{
"id": "PC-CVE-CVE-2023-28121",
"remediation_id": "REM-CVE-CVE-2023-28121",
"title": "WooCommerce SQLi (CVE-2023-28121)",
"severity": "CRITICAL",
"cvss_score": 9.8,
"description": "...",
"remediation": "Update WooCommerce to version 7.8.0 or later.",
"references": ["https://nvd.nist.gov/vuln/detail/CVE-2023-28121"],
"evidence": { "plugin": "woocommerce", "version": "8.2.1" },
"module": "cves"
}
],
"summary": { "critical": 1, "high": 1, "medium": 3, "low": 2 },
"duration_seconds": 4.2,
"blocked": false,
"woocommerce": {
"detected": true,
"version": "8.2.1",
"active_plugins": ["core", "payments", "blocks"],
"api_namespaces": ["wc/store/v1", "wc/v3"]
},
"wp_ecommerce": null
}Plecost is a first-class Python library. The same logic that powers the CLI is available as an importable API — no subprocess, no parsing CLI output.
import asyncio
from plecost import Scanner, ScanOptions
async def main():
options = ScanOptions(
url="https://target.com",
concurrency=10,
timeout=10,
modules=["fingerprint", "plugins", "cves"], # None = all modules
)
result = await Scanner(options).run()
print(f"WordPress {result.wordpress_version} | WAF: {result.waf_detected}")
for finding in result.findings:
print(f"[{finding.severity.value}] {finding.id}: {finding.title}")
asyncio.run(main())from celery import Celery
from plecost import Scanner, ScanOptions
import asyncio
app = Celery("tasks")
@app.task
def scan_wordpress(url: str) -> dict:
opts = ScanOptions(url=url, modules=["fingerprint", "plugins", "cves"])
result = asyncio.run(Scanner(opts).run())
return {
"url": result.url,
"critical": result.summary.critical,
"findings": [f.id for f in result.findings],
}| Variable | Description | Used by |
|---|---|---|
PLECOST_DB_URL |
Database URL (SQLite or PostgreSQL) | update-db, scan |
PLECOST_TIMEOUT |
Request timeout in seconds | scan |
PLECOST_OUTPUT |
JSON output file path | scan |
GITHUB_TOKEN |
GitHub token to avoid download rate limiting | update-db |
Modules without interdependencies run concurrently from the start. cves waits for plugins and themes to complete so it has a full list of installed software to match against the CVE database.
"CVE database not found"
The local database hasn't been downloaded yet:
plecost update-dbTarget returns 429 (rate limiting)
# Reduce concurrency
plecost scan https://target.com --concurrency 3
# Or use stealth mode (includes automatic pacing)
plecost scan https://target.com --stealthSSL certificate errors
plecost scan https://target.com --no-verify-sslOnly use
--no-verify-sslin controlled environments.
Target returns 403 (scanner blocked)
Plecost detects this automatically on the pre-flight probe and aborts cleanly with finding PC-PRE-001. Try a different IP, a proxy, or a different User-Agent:
plecost scan https://target.com --proxy http://127.0.0.1:8080
plecost scan https://target.com --random-user-agentWordPress not detected
plecost scan https://target.com --forceA self-contained Docker Compose environment — Damn Vulnerable WordPress (DVWP) — is included for local testing and development. It spins up a fully configured WordPress instance with a curated set of outdated, intentionally vulnerable plugins.
Located at tests/dvwp/.
cd tests/dvwp
docker compose up -d
docker compose logs wpcli -f # watch setup (~60s), wait for plugin tableOnce wpcli exits, the environment is ready:
| URL | Credentials |
|---|---|
| http://localhost:8765 | — |
| http://localhost:8765/wp-admin | admin / admin |
| Plugin | Version | CVE |
|---|---|---|
| wpDiscuz | 7.0.4 | CVE-2020-24186 — unauthenticated RCE via file upload (CVSS 9.8) |
| Contact Form 7 | 5.3.1 | CVE-2020-35489 — unrestricted file upload |
| WooCommerce | 5.0.0 | CVE-2021-32790 — multiple |
| WooCommerce Payments | 3.9.0 | CVE-2023-28121 — unauthenticated privilege escalation (CVSS 9.8) |
| WooCommerce Stripe Gateway | 4.3.0 | CVE-2019-15826 — order information disclosure |
| Easy Digital Downloads | 2.11.5 | CVE-2021-39351 — stored XSS |
| Give – Donation Plugin | 2.10.3 | CVE-2021-34634 — SQL injection |
| YITH WooCommerce Wishlist | 2.2.9 | CVE-2021-24987 — stored XSS |
| Ninja Forms | 3.4.34.2 | CVE-2021-34648 — unauthenticated email injection |
| Duplicator | 1.3.26 | CVE-2020-11738 — path traversal |
| Loginizer | 1.6.3 | CVE-2020-27615 — SQL injection |
| Elementor | 3.1.2 | CVE-2022-1329 — authenticated RCE |
| WP Super Cache | 1.7.1 | CVE-2021-33203 — authenticated XSS |
| Wordfence | 7.5.0 | CVE-2021-24875 — reflected XSS |
plecost scan http://localhost:8765 -v
plecost scan http://localhost:8765 --deep -vdocker compose down -v && docker compose up -dSee tests/dvwp/README.md for full details.
Warning: For local/isolated use only. Never expose to the internet.
Plecost is distributed under the PolyForm Noncommercial License 1.0.0.
Free for: personal security research, internal corporate audits, academic and educational use, open source projects, charitable and government organizations.
Requires a commercial license for: scanning-as-a-service, inclusion in a commercial product, or any use generating direct or indirect revenue.
For commercial licensing: cr0hn@cr0hn.com (Dani) · ffranz@mrlooquer.com (Fran)