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:
- The WordPress core version
- Installed themes and their versions
- Installed plugins and their versions
- Registered usernames
- Configuration weaknesses (e.g., exposed
wp-config.phpbackups, directory listing, debug logs) - Weak/default credentials via password brute-forcing
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
- Non-intrusive and aggressive enumeration modes
- Vulnerability data pulled live from the WPScan API (requires a free or paid API token)
- User enumeration via multiple techniques (author sitemap, REST API, login error messages)
- Password and username brute-forcing modules
- Plugin/theme vulnerability detection, including nulled/backdoored plugin detection
- Output in CLI-readable text, JSON, or CLI-No-Color formats for automation
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
| Option | Description |
|---|---|
--url | -u <target url> | The URL of the target WordPress site |
--force | -f | Do not check if the target is running WordPress before scanning |
--user-agent | --ua <value> | Set a custom User-Agent string |
--random-user-agent | --rua | Use 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-checks | Disable TLS/SSL certificate verification |
Enumeration Options (-e / --enumerate)
| Value | Description |
|---|---|
vp | Vulnerable plugins only |
ap | All plugins |
p | Popular plugins |
vt | Vulnerable themes only |
at | All themes |
t | Popular themes |
tt | Timthumbs |
cb | Config backups |
dbe | Db exports |
u | User IDs range (e.g. u1-10) |
m | Media IDs range (uploaded files) |
ap,at,cb,dbe,u | Combine multiple modules (comma-separated, no spaces) |
Example:
wpscan --url http://target-site.com -e vp,vt,u
Password Attack Options
| Option | Description |
|---|---|
--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
| Option | Description |
|---|---|
--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 |
--stealthy | Alias that forces passive detection, no aggressive checks |
Throttling & Connection
| Option | Description |
|---|---|
--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
| Option | Description |
|---|---|
--output | -o <file> | Save output to a file |
--format | -f <format> | cli, cli-no-colour, cli-no-color, json |
--verbose | -v | Verbose output |
--no-banner | Suppress the ASCII banner |
--log <file> | Log HTTP requests/responses |
API / Database
| Option | Description |
|---|---|
--api-token <token> | WPScan.com API token |
--update | Update the vulnerability database |
--no-update | Skip the auto-update check for this run |
Misc
| Option | Description |
|---|---|
--help | -h | Show help menu |
--version | Show installed version |
--clear-cache | Clear 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
- Pre-engagement recon: Quickly identify WordPress version, theme, and plugin footprint before deeper testing.
- Vulnerability validation: Cross-check plugin/theme versions against known CVEs during a formal penetration test.
- User enumeration for password attacks: Build a target username list to feed into credential-stuffing or brute-force campaigns.
- Configuration audit: Detect exposed backup files, debug logs, or directory listing misconfigurations.
- Bug bounty reconnaissance: Fast triage of WordPress targets in scope to identify low-hanging fruit (outdated plugins).
- Continuous security monitoring: Scheduled scans (via cron) of an organization’s own WordPress sites to catch newly disclosed vulnerabilities in installed plugins.
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
- Always obtain and use a free WPScan API token — passive scanning without it will still fingerprint components but will not return live CVE matches.
- Start with
--stealthyor--detection-mode passivewhen testing production systems to avoid unnecessary load or WAF triggers. - Use
-e vp,vt(vulnerable plugins/themes only) instead ofap,at(all plugins/themes) for faster scans when you only care about known vulnerabilities. - Combine WPScan results with manual verification — automated tools can produce false positives, especially around version detection via passive methods.
- Throttle requests (
--throttle) on shared hosting targets to avoid rate-limiting or accidental denial-of-service. - Rotate or randomize the User-Agent (
--random-user-agent) when the target has bot-detection systems in place. - Never brute-force login credentials without explicit written authorization — this is often outside the scope of many penetration test agreements.
- Keep the local vulnerability database updated (
wpscan --update) before every engagement. - Save all scans in JSON format for later parsing, diffing between engagements, and integration into reporting pipelines.
Troubleshooting
| Issue | Cause | Solution |
|---|---|---|
Error: 403 Forbidden on all requests | WAF/CDN (e.g., Cloudflare) blocking scanner | Use --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 WordPress | Detection heuristics failed (custom setup) | Force the scan with --force |
No WPScan API Token given | Missing/expired API token | Register at wpscan.com/api and pass --api-token |
| SSL certificate errors | Self-signed cert on staging/test environments | Add --disable-tls-checks |
| Extremely slow scans | Too many threads on a slow target or rate-limited connection | Lower --max-threads, increase --request-timeout |
Connection refused | Target down, firewall blocking, or wrong port/protocol | Verify with curl -I <url> first |
| Ruby gem dependency errors during manual install | Missing system libraries | Install 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) reached | Wait for daily reset or upgrade to a paid WPScan.com plan |
References
- Official WPScan Documentation: https://wpscan.com/docs/
- WPScan GitHub Repository: https://github.com/wpscanteam/wpscan
- WPScan Vulnerability Database: https://wpscan.com/wordpress-plugins
- WPScan API Registration: https://wpscan.com/api
- Kali Linux Tools Listing – WPScan: https://www.kali.org/tools/wpscan/
- OWASP Testing Guide – WordPress Section: https://owasp.org/www-project-web-security-testing-guide/
