TechEarl

WPScan Usage Guide and Man Page (2026)

WPScan v3.8+ usage reference for WordPress security audits: install on Linux/macOS, API token setup, the command patterns that matter (enumerate users, vulnerable plugins, brute force), JSON output, and how WPScan compares to Wordfence, Sucuri, and WPSec.

Ishan Karunaratne⏱️ 16 min readUpdated
Share thisCopied
WPScan v3.8+ usage reference for WordPress security audits: install on Linux/macOS, API token setup, the command patterns that matter (enumerate users, vulnerable plugins, brute force), JSON output, and how WPScan compares to Wordfence, Sucuri, and WPSec.

WPScan is the black-box WordPress scanner that has been the de facto standard for WordPress pentesting since around 2011. It enumerates users, fingerprints WordPress core/plugin/theme versions, checks them against a curated vulnerability database, and (with the right wordlist) brute-forces login forms. The old "ruby ./wpscan.rb" invocation from the 2015-era docs is long gone, current WPScan is a polished Ruby gem with sane defaults, a vulnerability API that requires a free token, and a Docker image that saves you from gem-install pain. This is the current usage reference for WPScan v3.8+: install paths, API token setup, the dozen command patterns that cover 95% of real audits, JSON output for CI integration, the legal caveat that matters, and how it compares to Wordfence, Sucuri, and WPSec.

How do I use WPScan to audit WordPress security?

Install WPScan as a Ruby gem (sudo gem install wpscan), as a Docker container (docker run --rm -it wpscanteam/wpscan), or use the preinstalled binary on Kali Linux. Get a free API token from wpscan.com to enable the vulnerability database (free Researcher tier: 25 requests/day for non-commercial use; commercial use needs a custom-priced Enterprise plan). The most useful invocation is wpscan --url https://example.com --api-token YOUR_TOKEN --enumerate vp,vt,u --random-user-agent, that scans WordPress core, enumerates vulnerable plugins and themes, lists users, and rotates user agents to avoid trivial blocking. Add --output report.json --format json for machine-readable output, --disable-tls-checks only when the target uses self-signed certs, and --throttle 500 to slow requests when targets rate-limit. Never scan a site you do not own or have written permission to test, unauthorized scanning is a crime in most jurisdictions.

Try it with your own values

Set your target URL, the username and wordlist for brute-force tests, and the output file. Every WPScan command below updates so you can copy and run against an authorized target.

Jump to:

Install WPScan

Three reliable paths. Pick whichever fits your workflow.

As a Ruby gem (Linux/macOS):

bash
# Prereqs: Ruby 3.0+, libcurl, build tools
sudo apt install ruby ruby-dev libcurl4-openssl-dev build-essential -y  # Debian/Ubuntu
brew install ruby                                                       # macOS

# Install the gem
sudo gem install wpscan

# Confirm
wpscan --version

The gem installs wpscan into your PATH. First run also pulls down a fresh local copy of the vulnerability database fingerprints (separate from API lookups, fingerprints identify versions, the API identifies known vulns).

As a Docker container:

bash
docker pull wpscanteam/wpscan
docker run --rm -it wpscanteam/wpscan --url :target

The container path avoids Ruby version conflicts and is what I reach for on machines I do not want to install gems on. The image is maintained by the WPScan team at hub.docker.com/r/wpscanteam/wpscan.

On Kali Linux:

wpscan is preinstalled on Kali. apt update && apt install wpscan to bump it to the latest if needed.

The current version in 2026 is v3.8.x. Older wpscan v2 (the "ruby ./wpscan.rb" era from 2015) is dead, if you find documentation telling you to clone a repo and run ruby ./wpscan.rb, that doc is a decade out of date.

The WPScan API token

WPScan's vulnerability data lives in a curated database that is gated behind an API token. The token is free for non-commercial use with a daily quota; commercial use needs a paid Enterprise plan.

Sign up at wpscan.com/api. Tiers as of 2026:

TierDaily requestsCost
Researcher25/dayFree (non-commercial only)
EnterpriseCustomContact sales

WPScan no longer publishes fixed mid-tier plans; commercial pricing is quoted per number of sites. Each request to the vulnerability database counts as one, a single wpscan run on a site with 30 plugins consumes around 31 requests (one per plugin + core). The 25/day free tier is enough for occasional audits of small sites; serious pentesting or CI integration needs an Enterprise plan.

Pass the token on every invocation:

bash
wpscan --url :target --api-token YOUR_TOKEN_HERE

Or put it in a config file at ~/.wpscan/scan.yml:

yaml
cli_options:
  api_token: YOUR_TOKEN_HERE

wpscan reads ~/.wpscan/scan.yml automatically. The config-file approach keeps the token out of your shell history. Permission the file with chmod 600 ~/.wpscan/scan.yml.

If you skip the token, WPScan still runs but reports No WPVulnDB API Token given, as a result vulnerability data has not been output. The version fingerprinting still works, you just have to look up CVEs manually.

The command patterns that matter

A working WPScan vocabulary. Each of these is an invocation I have used in a real audit.

Basic scan (the default starting point):

bash
wpscan --url :target --api-token YOUR_TOKEN

Detects WordPress version, theme, a sample of plugins, the readme, and the wp-content directory. Cheap, fast, no enumeration. Use this first to confirm the target is WordPress and the scanner can reach it.

Enumerate users:

bash
wpscan --url :target --api-token YOUR_TOKEN --enumerate u

Discovers usernames by walking author IDs (/?author=1, /?author=2, …). Most WordPress installs leak usernames this way even with author pages disabled. Add u1-100 to widen the search range: --enumerate u1-100.

Enumerate vulnerable plugins:

bash
wpscan --url :target --api-token YOUR_TOKEN --enumerate vp

vp = "vulnerable plugins only". ap enumerates all plugins (much slower and noisier). p is the default and falls between. For an audit, vp is what you usually want, known-vulnerable plugins are the actionable result.

Enumerate vulnerable themes:

bash
wpscan --url :target --api-token YOUR_TOKEN --enumerate vt

Same logic as plugins. vt = vulnerable, at = all, t = a "passive" default mix.

Combine enumeration:

bash
wpscan --url :target --api-token YOUR_TOKEN \
  --enumerate vp,vt,u,dbe,cb,tt

Comma-separated values run in one pass. Useful sub-enumerates:

  • vp, vulnerable plugins
  • vt, vulnerable themes
  • u, users
  • dbe, database export files (look for accidentally exposed dumps)
  • cb, config backups (wp-config.php.bak, wp-config.old, …)
  • tt, timthumb scripts (very old vuln but still kicking around)

Brute force a specific user:

bash
wpscan --url :target --api-token YOUR_TOKEN \
  --usernames :username --passwords :wordlist \
  --max-threads 5

--max-threads 5 is sensible, too many parallel attempts trip Cloudflare and most WAFs. --passwords takes a wordlist file; rockyou.txt is the classic but contains 14M entries and will take days at honest rate limits. Trim to top 10K passwords for realistic timeframes.

Brute force multiple users from a file:

bash
wpscan --url :target --api-token YOUR_TOKEN \
  --usernames users.txt --passwords passwords.txt

users.txt should be the output of an earlier --enumerate u run, one username per line.

Random user agent + request delay (stealthier scan):

bash
wpscan --url :target --api-token YOUR_TOKEN \
  --random-user-agent --throttle 1000 --request-timeout 60

--throttle 1000 waits 1000ms between requests. --random-user-agent rotates the UA string per request. Neither bypasses a real WAF but both help against naive blocking.

Skip TLS verification (testing with self-signed certs):

bash
wpscan --url :target --api-token YOUR_TOKEN --disable-tls-checks

Only use this on hosts you control. Disabling TLS verification on the public internet defeats half the point of HTTPS.

Behind a proxy (for SOCKS5 / TOR routing):

bash
wpscan --url :target --api-token YOUR_TOKEN \
  --proxy socks5://127.0.0.1:9050

The classic TOR-via-WPScan invocation. Combine with --random-user-agent and --throttle for slower but quieter scans. Note: TOR exit IPs are aggressively blocked by Cloudflare and most managed-WordPress hosts.

Update the local fingerprint database:

bash
wpscan --update

Pulls the latest core/plugin/theme fingerprints. Run weekly if you scan often.

Output formats: JSON and CLI

Default output is CLI-formatted with colored output. For automation, use --format json:

bash
wpscan --url :target --api-token YOUR_TOKEN \
  --output :output_file --format json

The JSON includes every finding, version, vulnerability ID, and timing. Pipe it into jq for filtering:

bash
# Count vulnerable plugins
jq '.plugins | to_entries | map(select(.value.vulnerabilities | length > 0)) | length' :output_file

# List CVEs for everything
jq '.plugins | to_entries[] | .value.vulnerabilities[]?.references.cve[]?' :output_file

For CI integration (e.g. GitHub Actions running a weekly scan against staging), JSON output + jq is the right shape. Fail the build if vulnerabilities of a certain severity show up:

bash
COUNT=$(jq '.plugins | to_entries | map(.value.vulnerabilities[]?) | length' :output_file)
if [ "$COUNT" -gt 0 ]; then
  echo "Found $COUNT plugin vulnerabilities"
  exit 1
fi

Other formats: --format cli-no-color for plain text, --format cli-no-colour for the British spelling.

Read this twice. Running WPScan against a site you do not own or have explicit written permission to test is a crime in most jurisdictions:

  • United States, Computer Fraud and Abuse Act (CFAA). Scanning is in a gray area; brute force is unambiguously illegal.
  • United Kingdom, Computer Misuse Act 1990. Unauthorized access (and attempted access) is a criminal offense.
  • European Union, Directive 2013/40/EU on attacks against information systems. National implementations vary; assume scanning without authorization is illegal.

What counts as authorization:

  • A signed pentesting contract or statement of work.
  • A site you personally own and operate.
  • A bug bounty program that explicitly scopes WPScan-style scanning (many do not, read the program rules first).

What does not count:

  • "It is publicly accessible, so it is fair game." (No.)
  • "I am only enumerating users, not exploiting anything." (Enumeration is unauthorized access in many jurisdictions.)
  • "I scanned my client's competitor to compare." (Definitely not.)

When in doubt, do not scan. The cost of a misjudged scan can be a criminal charge or a civil suit. If you find a vulnerability on a site you do not own and want to report it, contact the site directly, most have a security.txt at /.well-known/security.txt with a disclosure address.

WPScan vs Wordfence vs Sucuri vs WPSec

Four tools, different roles. Pick by what you are trying to do.

ToolTypeWhere it runsBest forPricing
WPScanBlack-box CLI scannerYour machine (external view)Pentests, audits, CI checksFree CLI; free non-commercial API, custom-priced Enterprise
WordfenceWordPress pluginInside WordPress (white-box)Production monitoring, WAF, malware scanFree plugin; Premium $119/year/site
SucuriSaaS WAF + scannerCloud (in-line WAF) + scannerDDoS protection, malware cleanup$200-$500+/year
WPSecSaaS scannerCloud (external view)One-off audits without local installFree with limits; paid tiers

The honest take:

  • WPScan is the right tool for an audit or pentest where you want the attacker's view from outside. It does not require touching the target's WordPress install.
  • Wordfence is the right tool for ongoing production protection, runs inside WordPress, has access to all the files and DB, can scan for malware and block traffic in real time.
  • Sucuri is the right call if you need a cloud WAF that sits in front of WordPress and also handles DDoS, overlapping with Cloudflare but with WordPress-specific rules.
  • WPSec fills the same niche as WPScan but as a hosted service. Easier to integrate into reports without explaining "I ran a CLI tool."

For most security workflows, you end up with WPScan for periodic external audits and Wordfence (or a competitor) running inside the WordPress installs you control. They are complementary, not competitors.

The man page

The current wpscan --help output is comprehensive but long. The most useful flags, grouped:

Target selection:

code
--url | -u <target_url>          The WordPress URL/domain to scan.
--force | -f                     Do not check whether the target is WordPress.
--server <server>                Force the server type (apache, nginx, iis).

Authentication and rate control:

code
--api-token | -t <token>         The WPScan API token for vulnerability data.
--max-threads <number>           Maximum threads to use (default: 5).
--throttle <ms>                  Delay between requests in milliseconds.
--request-timeout <s>            Request timeout in seconds.
--connect-timeout <s>            Connection timeout in seconds.

Enumeration:

code
--enumerate | -e [opts]          Enumeration options. Multiple values allowed.
  vp                             Vulnerable plugins only
  ap                             All plugins (slower)
  p                              Popular plugins (default mix)
  vt                             Vulnerable themes only
  at                             All themes
  t                              Popular themes
  tt                             Timthumb files
  cb                             Config backups
  dbe                            Database exports
  u[1-N]                         Users from id 1 to N (default 1-10)
  m[1-N]                         Media from id 1 to N

Brute force:

code
--usernames <list>               Comma-separated usernames or path to file.
--passwords | -P <path>          Path to a password wordlist.
--password-attack <type>         wp-login, xmlrpc, or xmlrpc-multicall.

Output:

code
--output | -o <path>             Write output to a file.
--format <fmt>                   cli, cli-no-color, json.
--detection-mode <mode>          mixed, passive, or aggressive.
--no-banner                      Skip the ASCII banner.
--verbose | -v                   Verbose output.

Stealth and proxying:

code
--random-user-agent              Use a random UA per request.
--user-agent | -a <ua>           Set a specific UA string.
--proxy <[scheme://]host:port>   HTTP/HTTPS/SOCKS proxy.
--proxy-auth <user:pass>         Proxy credentials.
--http-auth <user:pass>          HTTP Basic auth for the target.
--cookie-string <s>              Cookie string for the target.
--cookie-jar <path>              Cookie jar file.
--headers <headers>              Custom request headers.
--vhost <vhost>                  Set the Host: header (for hosts hidden behind shared IPs).

Other:

code
--disable-tls-checks             Skip certificate verification.
--update                         Update the local fingerprint database.
--no-update                      Do not check for updates.
--scope <scope>                  Limit scope to specific subdomains/paths.
--exclude-content-based <regex>  Exclude content matching this pattern.
--ignore-main-redirect           Ignore redirects from the main URL.
--help | -h                      Show help.
--hh                             Show all help options (advanced).
--version                        Show WPScan version.

For the latest, run wpscan --hh (double-h) which shows every option including the rarely-used ones.

Troubleshooting

"The remote website is up, but does not seem to be running WordPress." Either the target is not WordPress, or WordPress is heavily customized (renamed wp-content directory, hidden version strings, blocked common paths). Try --force to bypass the check and --wp-content-dir, --wp-plugins-dir to point at the actual paths.

Cloudflare returns 403 / "Just a moment..." on every request. Cloudflare's bot detection is aggressive. Options: contact the site owner to whitelist your scanning IP, route via a residential proxy, or use the --random-user-agent + --throttle combo to look less like a bot. For sites behind aggressive bot protection, an authenticated scan (with --cookie-string from a valid session) often works better.

API requests fail with "401 Unauthorized". Token is invalid or expired. Regenerate at wpscan.com/profile. Confirm the token is being passed correctly, wpscan --url ... --api-token TOKEN_HERE with the literal token, not the word YOUR_TOKEN.

API quota exhausted ("Your daily request limit has been reached"). Free tier is 25/day. Either wait until the daily reset (00:00 UTC), upgrade your plan, or scope the scan tighter, --enumerate vp instead of --enumerate ap cuts requests significantly.

Brute force never finds the password even though I know it. Either the target has rate-limited or banned your IP, the username is wrong, or you are hitting the wrong endpoint. Try --password-attack xmlrpc instead of the default wp-login, xmlrpc.php often has weaker rate limiting. If xmlrpc.php returns 405 Method Not Allowed, it has been disabled (a legitimate hardening step).

WPScan reports a plugin version but no vulnerabilities, even though I see CVEs. The vulnerability database lags new CVEs by a few days to a few weeks. Cross-check with WPScan's public vuln search or the WordPress Plugin Vulnerabilities page. Also possible: the vulnerability exists in a different plugin version than the one detected.

False positive on user enumeration. Some WordPress sites return a generic 200 for every /?author=N URL (a hardening measure). WPScan may report the user IDs as "found" even though they do not exist. Cross-check with /wp-json/wp/v2/users (which is the REST API endpoint that also leaks usernames if not locked down).

What to do next

FAQ

Sources

Authoritative references this article was fact-checked against.

TagsWordPressSecurityWPScanPenetration TestingVulnerability ScanningPentesting

Found this useful? Pass it on.

Copied

Ishan Karunaratne

Software Systems Architect · Senior Software Engineer · Engineering Leadership

Software systems architect and senior software engineer with more than two decades designing, building, and running production software, Linux systems, and DevOps infrastructure, and lately working AI into the stack. Now a CTO, though what I write here is drawn from the full arc of that work, across architecture, engineering, and operations, not any single job.

Keep reading

Related posts

What WordPress agencies should adopt first, what to skip, budget realities, and the four operational shifts that turn AI from a curiosity into load-bearing.

How Small WordPress Agencies Can Use AI in 2026

AI for a WordPress agency in 2026: what to actually adopt first, what to skip, the budget realities, and the four operational shifts that turn AI tooling from a curiosity into a load-bearing part of the business.

which vs type vs command -v compared: which is a non-standard external program, command -v is the POSIX way to resolve a command path in scripts, and type reports aliases, functions, and builtins.

which vs type vs command -v: Find a Command Path

which vs type vs command -v for finding where a command lives: which is an external program with portability problems, command -v is the POSIX-standard choice for scripts, and type tells you the most.