wpscan: WordPress security scanner

wpscan: WordPress security scanner

WPScan is a free (for non-commercial use), black-box WordPress security scanner written in Ruby. It is developed and maintained by the WPScan team (now part of Automattic) and comes pre-installed on Kali Linux. WPScan is purpose-built to enumerate and audit WordPress installations, and it is considered the de-facto standard tool for WordPress penetration testing.

WPScan works by sending a series of HTTP requests to a target WordPress site and analyzing the responses (HTML source, HTTP headers, readme files, changelogs, JSON REST API endpoints, and more) to fingerprint:

Every detected component (core, theme, plugin) is automatically checked against the WPScan Vulnerability Database, a continuously updated repository of thousands of WordPress-related CVEs, giving testers immediate insight into exploitable weaknesses.

Key Features

Installation

WPScan comes pre-installed on Kali Linux by default. Verify the installation first:

wpscan --version

If it is not installed, or you want to update to the latest release, use the following methods.

Method 1 – APT (Kali Linux default repository)
sudo apt update
sudo apt install wpscan -y
Method 2 – RubyGems (latest version, cross-distro)
sudo apt install ruby ruby-dev build-essential libcurl4-openssl-dev libxml2-dev libxslt1-dev zlib1g-dev -y
sudo gem install wpscan
Method 3 – From Source (GitHub)
git clone https://github.com/wpscanteam/wpscan.git
cd wpscan
sudo gem install bundler
bundle install --without test
Post-Installation: Updating the Vulnerability Database

WPScan requires a free API token from https://wpscan.com/api to pull live vulnerability data (up to 25 requests/day on the free tier). Once you have a token:

wpscan --api-token YOUR_API_TOKEN_HERE --update

You can also save the token permanently so you don’t need to pass it every time:

mkdir -p ~/.wpscan
echo "YOUR_API_TOKEN_HERE" > ~/.wpscan/scan.log

(Alternatively, export it as an environment variable: export WPSCAN_API_TOKEN=YOUR_API_TOKEN_HERE)

To manually refresh the local vulnerability database cache:

wpscan --update

Syntax

The general syntax of WPScan is:

wpscan --url <target-url> [options]

Basic example:

wpscan --url http://target-site.com

All Command-Line Options

Below is the complete reference of WPScan CLI options as available in Kali Linux.

Target Options
OptionDescription
--url | -u <target url>The URL of the target WordPress site
--force | -fDo not check if the target is running WordPress before scanning
--user-agent | --ua <value>Set a custom User-Agent string
--random-user-agent | --ruaUse a random User-Agent for every request
--http-auth <login:password>HTTP Basic Authentication credentials
--cookie-string <string>Set a custom cookie string
--proxy <protocol://IP:port>Use an HTTP(S) proxy
--proxy-auth <login:password>Proxy authentication credentials
--disable-tls-checksDisable TLS/SSL certificate verification
Enumeration Options (-e / --enumerate)
ValueDescription
vpVulnerable plugins only
apAll plugins
pPopular plugins
vtVulnerable themes only
atAll themes
tPopular themes
ttTimthumbs
cbConfig backups
dbeDb exports
uUser IDs range (e.g. u1-10)
mMedia IDs range (uploaded files)
ap,at,cb,dbe,uCombine multiple modules (comma-separated, no spaces)

Example:

wpscan --url http://target-site.com -e vp,vt,u
Password Attack Options
OptionDescription
--passwords | -P <file>Wordlist file path for password brute-forcing
--usernames | -U <file/string>Username(s) or file of usernames
--multicall-max-passwords <n>Max passwords per XML-RPC multicall request
--login-uri <uri>Custom login page URI (e.g. for renamed wp-login.php)
--password-attack <mode>Attack mode: xmlrpc, wp-login, xmlrpc-multicall
Detection & Scan Behavior
OptionDescription
--detection-mode <mode>mixed (default), passive, or aggressive
--plugins-detection <mode>mixed, passive, aggressive
--plugins-version-detection <mode>mixed, passive, aggressive
--exclude-content-based <regex/string>Exclude results matching a pattern
--stealthyAlias that forces passive detection, no aggressive checks
Throttling & Connection
OptionDescription
--max-threads | -t <n>Number of concurrent threads (default: 5)
--throttle <milliseconds>Delay between requests
--request-timeout <seconds>HTTP request timeout (default: 60)
--connect-timeout <seconds>Connection timeout
--max-scan-duration <seconds>Stop the scan after N seconds
Output Options
OptionDescription
--output | -o <file>Save output to a file
--format | -f <format>cli, cli-no-colour, cli-no-color, json
--verbose | -vVerbose output
--no-bannerSuppress the ASCII banner
--log <file>Log HTTP requests/responses
API / Database
OptionDescription
--api-token <token>WPScan.com API token
--updateUpdate the vulnerability database
--no-updateSkip the auto-update check for this run
Misc
OptionDescription
--help | -hShow help menu
--versionShow installed version
--clear-cacheClear the local scan cache
--cache-ttl <seconds>Cache time-to-live

Basic Usage

The simplest possible scan:

wpscan --url http://testphp-wordpress.local

Expected output (truncated for readability):

_______________________________________________________________
         __          _______   _____
         \ \        / /  __ \ / ____|
          \ \  /\  / /| |__) | (___   ___  __ _ _ __ ®
           \ \/  \/ / |  ___/ \___ \ / __|/ _` | '_ \
            \  /\  /  | |     ____) | (__| (_| | | | |
             \/  \/   |_|    |_____/ \___|\__,_|_| |_|

         WordPress Security Scanner by the WPScan Team
                         Version 3.8.25
       Sponsored by Automattic - https://automattic.com/
       @_WPScan_, @ethicalhack3r, @erwan_lr, @firefart
_______________________________________________________________

[+] URL: http://testphp-wordpress.local/ [192.168.56.101]
[+] Started: Sun Jul 19 10:12:03 2026

Interesting Finding(s):

[+] Headers
 | Interesting Entry: Server: Apache/2.4.52 (Ubuntu)
 | Found By: Headers (Passive Detection)
 | Confidence: 100%

[+] XML-RPC seems to be enabled: http://testphp-wordpress.local/xmlrpc.php
 | Found By: Direct Access (Aggressive Detection)
 | Confidence: 100%

[+] WordPress readme found: http://testphp-wordpress.local/readme.html
 | Found By: Direct Access (Aggressive Detection)
 | Confidence: 100%

[+] WordPress version 6.5.3 identified (Insecure, released on 2024-04-09)
 | Found By: Rss Generator (Passive Detection)

[+] WordPress theme in use: twentytwentyfour
 | Location: http://testphp-wordpress.local/wp-content/themes/twentytwentyfour/
 | Latest Version: 1.1
 | Last Updated: 2024-04-02T00:00:00.000Z

[+] Enumerating All Plugins (via Passive and Aggressive Methods)
[+] Checking Plugin Versions (via Passive and Aggressive Methods)

[i] Plugin(s) Identified:

[+] contact-form-7
 | Location: http://testphp-wordpress.local/wp-content/plugins/contact-form-7/
 | Latest Version: 5.9.3
 | Last Updated: 2024-04-10T13:00:00.000Z
 | Found By: Urls In Homepage (Passive Detection)

[+] WPScan DB API OK
 | Plan: free
 | Requests Done (this run): 6
 | Requests Remaining: 19

[+] Finished: Sun Jul 19 10:13:41 2026
[+] Requests Done: 47
[+] Cached Requests: 5
[+] Data Sent: 12.611 KB
[+] Data Received: 391.223 KB
[+] Memory used: 214.652 MB
[+] Elapsed time: 00:01:38

Practical Examples with Output

Example 1 – Full vulnerability-focused scan with an API token
wpscan --url http://target-site.com --api-token abc123XYZ456 -e vp,vt

Output (excerpt):

[+] contact-form-7
 | [!] Title: Contact Form 7 < 5.8.4 - Unrestricted File Upload
 | Fixed in: 5.8.4
 | References:
 |  - https://wpscan.com/vulnerability/abcd1234
 |  - CVE-2024-XXXXX
Example 2 – Enumerate users only
wpscan --url http://target-site.com -e u1-20

Output (excerpt):

[i] User(s) Identified:

[+] admin
 | Found By: Author Id Brute Forcing - Author Pattern (Aggressive Detection)
 | Confirmed By: Login Error Messages (Aggressive Detection)

[+] j.smith
 | Found By: Rss Generator (Passive Detection)
Example 3 – Brute-force login using a known username list and rockyou.txt
wpscan --url http://target-site.com \
  --usernames admin,j.smith \
  --passwords /usr/share/wordlists/rockyou.txt \
  --password-attack wp-login

Output (excerpt):

[i] Valid Combinations Found:
 | Username: admin, Password: Summer2024!
Example 4 – Scan behind HTTP Basic Auth
wpscan --url http://staging.target-site.com --http-auth admin:staging123
Example 5 – Full plugin & theme enumeration with JSON output for automation
wpscan --url http://target-site.com -e ap,at,cb,dbe --format json --output scan_results.json
cat scan_results.json | jq '.plugins | keys'

Output:

[
  "akismet",
  "contact-form-7",
  "elementor",
  "woocommerce"
]
Example 6 – Using a random User-Agent and proxy through Burp Suite
wpscan --url http://target-site.com --random-user-agent --proxy http://127.0.0.1:8080
Example 7 – Aggressive detection mode for maximum coverage
wpscan --url http://target-site.com --detection-mode aggressive -e vp,vt,tt,cb,dbe,u
Example 8 – Stealthy/passive scan to avoid triggering WAF/IDS
wpscan --url http://target-site.com --stealthy
Example 9 – Scanning a target with a custom (renamed) login page
wpscan --url http://target-site.com --login-uri /secure-admin-login \
  -U admin -P /usr/share/wordlists/rockyou.txt
Example 10 – Limiting scan duration in a time-boxed engagement
wpscan --url http://target-site.com --max-scan-duration 300 -e vp,vt,u

Output (excerpt):

[!] Max scan duration reached, exiting.
[+] Elapsed time: 00:05:00
Example 11 – Scan multiple targets from a list via bash loop
for site in $(cat targets.txt); do
  wpscan --url "$site" -e vp,vt --output "${site//[:\/]/_}.txt"
done
Example 12 – Detecting config backups and database exports (common misconfig)
wpscan --url http://target-site.com -e cb,dbe

Output (excerpt):

[+] Config Backup(s) Found:
[+] wp-config.php.bak
 | http://target-site.com/wp-config.php.bak
 | Found By: Direct Access (Aggressive Detection)

Common Use Cases


Automation with Bash

Automated Multi-Target Scan with Report Aggregation
#!/bin/bash
# wpscan_batch.sh - scan a list of WordPress sites and aggregate vulnerable findings

TARGETS="targets.txt"
API_TOKEN="YOUR_API_TOKEN_HERE"
OUTDIR="wpscan_reports_$(date +%F)"
mkdir -p "$OUTDIR"

while IFS= read -r url; do
    name=$(echo "$url" | sed -E 's#https?://##; s#[/:]#_#g')
    echo "[*] Scanning $url ..."
    wpscan --url "$url" \
        --api-token "$API_TOKEN" \
        -e vp,vt,u \
        --format json \
        --output "$OUTDIR/${name}.json" \
        --random-user-agent \
        --request-timeout 30
    echo "[+] Done: $OUTDIR/${name}.json"
done < "$TARGETS"

echo "[*] Extracting vulnerable plugins across all targets..."
for f in "$OUTDIR"/*.json; do
    echo "== $f =="
    jq -r '.plugins | to_entries[] | select(.value.vulnerabilities | length > 0) | .key' "$f"
done
Cron Job for Weekly Compliance Scanning
# Add to crontab -e
0 3 * * 1 /usr/local/bin/wpscan_batch.sh >> /var/log/wpscan_weekly.log 2>&1
Slack/Webhook Alert on New Vulnerability Found
#!/bin/bash
WEBHOOK="https://hooks.slack.com/services/XXX/YYY/ZZZ"
RESULT=$(wpscan --url http://target-site.com --api-token "$API_TOKEN" -e vp,vt --format json)
COUNT=$(echo "$RESULT" | jq '[.plugins[].vulnerabilities[]?] | length')

if [ "$COUNT" -gt 0 ]; then
    curl -X POST -H 'Content-type: application/json' \
    --data "{\"text\":\"⚠️ WPScan found $COUNT vulnerabilities on target-site.com\"}" \
    "$WEBHOOK"
fi

Tips and Best Practices


Troubleshooting

IssueCauseSolution
Error: 403 Forbidden on all requestsWAF/CDN (e.g., Cloudflare) blocking scannerUse --random-user-agent, add delays with --throttle, or route through a residential proxy (only if authorized)
The remote website is up, but does not seem to be running WordPressDetection heuristics failed (custom setup)Force the scan with --force
No WPScan API Token givenMissing/expired API tokenRegister at wpscan.com/api and pass --api-token
SSL certificate errorsSelf-signed cert on staging/test environmentsAdd --disable-tls-checks
Extremely slow scansToo many threads on a slow target or rate-limited connectionLower --max-threads, increase --request-timeout
Connection refusedTarget down, firewall blocking, or wrong port/protocolVerify with curl -I <url> first
Ruby gem dependency errors during manual installMissing system librariesInstall libcurl4-openssl-dev, libxml2-dev, libxslt1-dev, zlib1g-dev before gem install wpscan
API requests exhausted (Requests Remaining: 0)Free tier daily limit (25/day) reachedWait for daily reset or upgrade to a paid WPScan.com plan

References

Exit mobile version