WPScan WordPress Vulnerability Scanner on Kali Linux

Deepak Prasad
Tested on Kali GNU/Linux Rolling 2026.2 (kali-rolling)
Package wpscan 3.8.28-0kali1
Applies to Kali Linux
Lab environment Local Docker WordPress on http://127.0.0.1:8080 (loopback bind) — pentest lab setup for VM isolation; Metasploitable 2 port 80 is not WordPress
Privilege Normal user for scans; sudo for apt install and Docker
Scope Install WPScan, refresh local metadata, run basic and enumeration scans, inventory installed plugins, query plugin and theme vulnerabilities through the WPScan API, enumerate users, and test login passwords against a loopback-only WordPress lab. Does not cover full web app pentesting, SQL injection exploitation, or scanning sites without authorization.

WPScan fingerprints WordPress sites over HTTP, compares component versions against local metadata, and can query the WPScan API for known vulnerabilities when you supply a token. In an ethical hacking lab it answers whether a WordPress install exposes outdated plugins or guessable admin credentials.

This guide installs WPScan on Kali, stands up a loopback-only WordPress container on port 8080, and walks through metadata updates, enumeration, installed-plugin inventory, API-backed vulnerability checks, user discovery, and a small password attack. Every command and output below was captured against that local lab — not against internet-facing sites.

IMPORTANT
Scan only WordPress sites you own or have explicit permission to test. Bind the lab to 127.0.0.1 and keep it on an isolated VM. Do not aim WPScan at production blogs, client sites, or competitors without written authorization.

What is WPScan in ethical hacking?

WPScan is a WordPress-focused black-box scanner, not a general web vulnerability scanner. It sends HTTP requests to learn whether the target responds like WordPress, records the core version, active theme, and plugins, probes exposed endpoints such as xmlrpc.php, and can enumerate author usernames or run login guesses when policy allows.

That workflow is active black-box reconnaissance and credential testing against a WordPress application you control or are authorized to assess. It is distinct from:

  • Network port scanning with Nmap alone
  • Generic form brute force with Hydra (see web form brute force)
  • Exploiting SQL injection or file upload flaws after you find them elsewhere

Detailed plugin and theme vulnerability records are not stored locally. WPScan retrieves them from its API in real time when you pass --api-token on commands such as -e vp or -e vt. Register for a free token at wpscan.com/register when you need CVE-style data beyond version fingerprinting.


Install WPScan on Kali Linux

Kali ships WPScan in its repositories. Install or refresh the package, then confirm the version before you refresh local metadata.

bash
sudo apt update
sudo apt install -y wpscan

Check the installed package:

bash
dpkg-query -W wpscan
output
wpscan	3.8.28-0kali1

Print the scanner version banner:

bash
wpscan --version 2>&1 | tail -3
output
_______________________________________________________________

Current Version: 3.8.28

Version 3.8.28 matches the package row in the intro table. Run wpscan --update next so local metadata used for detection is present before the first target scan.


Kali lab setup

Metasploitable 2 on port 80 serves a static landing page — not WordPress — so this walkthrough uses a local Docker WordPress lab on http://127.0.0.1:8080. Docker on Kali typically requires sudo (sudo apt install -y docker.io when docker is missing).

Set the target URL once for every command below:

bash
WP_URL=http://127.0.0.1:8080
LAB=/tmp/wpscan-lab
mkdir -p "$LAB"

Start MySQL 8.0 on that network:

bash
sudo docker run -d --name wp-db --network wpscan-lab -e MYSQL_ROOT_PASSWORD=labroot -e MYSQL_DATABASE=wordpress mysql:8.0

Wait until MySQL accepts connections instead of using a fixed sleep:

bash
until sudo docker exec wp-db mysqladmin ping -h localhost -uroot -plabroot --silent; do sleep 2; done

Start WordPress 7.0.2 bound to loopback only so the lab is not published on every host interface:

bash
sudo docker run -d --name wp-lab --network wpscan-lab --publish 127.0.0.1:8080:80 -e WORDPRESS_DB_HOST=wp-db:3306 -e WORDPRESS_DB_USER=root -e WORDPRESS_DB_PASSWORD=labroot -e WORDPRESS_DB_NAME=wordpress wordpress:7.0.2-php8.3-apache

Confirm WordPress responds and redirects to the installer:

bash
curl -sI "$WP_URL/" | head -6
output
HTTP/1.1 302 Found
Date: Sun, 02 Aug 2026 11:31:20 GMT
Server: Apache/2.4.68 (Debian)
X-Powered-By: PHP/8.3.33
Expires: Wed, 11 Jan 1984 05:00:00 GMT
Cache-Control: no-cache, must-revalidate, max-age=0, no-store, private

Download WP-CLI on the host (the container image may fail TLS to GitHub) and copy it into the container:

bash
curl -sO https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
sudo docker cp wp-cli.phar wp-lab:/tmp/wp-cli.phar

Finish WordPress setup with a known admin password:

bash
sudo docker exec -w /var/www/html wp-lab php /tmp/wp-cli.phar core install --url="$WP_URL" --title="WPScan Lab" --admin_user=admin --admin_password='LabPass123!' --admin_email=admin@lab.local --skip-email --allow-root
output
Success: WordPress installed successfully.

Install wp-file-manager 6.0, an outdated release with known WPScan vulnerability records including CVE-2020-25213. Download the zip on the host and install it inside the container:

bash
curl -sL -o /tmp/wp-file-manager.6.0.zip https://downloads.wordpress.org/plugin/wp-file-manager.6.0.zip
sudo docker cp /tmp/wp-file-manager.6.0.zip wp-lab:/tmp/wp-file-manager.6.0.zip
sudo docker exec -w /var/www/html wp-lab php /tmp/wp-cli.phar plugin install /tmp/wp-file-manager.6.0.zip --activate --allow-root

Create the uploads paths the plugin expects so activation does not break the site:

bash
sudo docker exec wp-lab bash -c 'mkdir -p /var/www/html/wp-content/uploads/wp-file-manager-pro/fm_backup && chown -R www-data:www-data /var/www/html/wp-content/uploads'

Publish a short post that references the plugin path so passive detection can see it on the homepage:

bash
sudo docker exec -w /var/www/html wp-lab php /tmp/wp-cli.phar post create --post_title='Lab' --post_content='<link rel=stylesheet href=/wp-content/plugins/wp-file-manager/lib/themes/light/css/main.css>' --post_status=publish --allow-root

Build a short password list for the login test later:

bash
printf 'LabPass123!\nadmin\npassword\n' > "$LAB/pass.txt"

Remove the lab when you finish:

bash
sudo docker rm -f wp-lab wp-db
sudo docker network rm wpscan-lab

Compare WPScan scan modes

The sections below run against the same WP_URL. Use this table to pick a scan type before you spend API quota or hammer a login endpoint.

Mode Best for Typical success signal
Metadata update First run on a new Kali image Update completed.
Basic scan Version, theme, headers, XML-RPC [+] WordPress version and theme lines
Installed plugins Full plugin inventory Plugin(s) Identified: with plugin names
API vulnerability check CVE data for components [!] Title: lines under a plugin (needs token)
Users Author names for login testing [+] admin under User(s) Identified
Login test Weak admin passwords [SUCCESS] - admin / password

Run wpscan --update before the first scan. Register for an API token before you expect CVE lines from -e vp or -e vt.


Update the WPScan metadata database

WPScan keeps local metadata used for component detection and version checks. Refresh it before the first scan:

bash
wpscan --update
output
[i] Updating the Database ...
[i] Update completed.

Vulnerability records are not included in this local store. WPScan retrieves them from its API when you provide an API token on enumeration commands such as -e vp.

Without refreshed metadata, scans can fail immediately:

output
Scan Aborted: Update required, you can not run a scan if a database file is missing.

Re-run wpscan --update periodically so fingerprints stay current. The command does not scan a target site by itself.


Run a basic WordPress scan

A basic pass fingerprints WordPress without spending API tokens. It reports headers, XML-RPC exposure, core version, and the active theme.

Save the full transcript to a file instead of piping the active scan through head, which can truncate or interrupt the run:

bash
wpscan --url "$WP_URL" --no-update 2>&1 | tee "$LAB/basic-scan.txt"

Sample output (trimmed):

output
[+] URL: http://127.0.0.1:8080/ [127.0.0.1]
[+] Started: Sun Aug  2 08:16:25 2026

Interesting Finding(s):

[+] Headers
 | Interesting Entries:
 |  - Server: Apache/2.4.68 (Debian)
 |  - X-Powered-By: PHP/8.3.33
 | Found By: Headers (Passive Detection)
 | Confidence: 100%

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

[+] WordPress readme found: http://127.0.0.1:8080/readme.html
 | Found By: Direct Access (Aggressive Detection)
 | Confidence: 100%

[+] WordPress version 7.0.2 identified (Latest, released on 2026-07-17).
 | Found By: Rss Generator (Passive Detection)

[+] WordPress theme in use: twentytwentyfive
 | Location: http://127.0.0.1:8080/wp-content/themes/twentytwentyfive/
 | Latest Version: 1.5 (up to date)

The core version and theme name are what you paste into a report before you chase CVEs. Enabled XML-RPC matters because many login brute-force attempts use that endpoint. Read the full file with less "$LAB/basic-scan.txt" when you need every line.

If a production scan returns Scan Aborted: The target is responding with a 403, retry with a randomized user agent on authorized targets:

bash
wpscan --url "$WP_URL" --random-user-agent --no-update

Enumerate installed plugins

The -e vp flag searches for vulnerable plugins only. It does not inventory every installed extension. Use -e ap with mixed detection so WPScan combines passive clues and aggressive path checks:

bash
wpscan --url "$WP_URL" -e ap --plugins-detection mixed --no-update

A full -e ap --plugins-detection mixed pass can take several minutes because WPScan probes many known plugin locations. In this lab, the homepage post already references wp-file-manager, so passive detection finishes in seconds and is enough to confirm inventory before you spend API quota on -e vp:

bash
wpscan --url "$WP_URL" -e ap --plugins-detection passive --no-update

Sample output (trimmed):

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

[i] Plugin(s) Identified:

[+] wp-file-manager
 | Location: http://127.0.0.1:8080/wp-content/plugins/wp-file-manager/
 | Last Updated: 2026-04-21T12:53:00.000Z
 | [!] The version is out of date, the latest version is 8.0.4
 |
 | Found By: Urls In Homepage (Passive Detection)
 | Confirmed By: Urls In 404 Page (Passive Detection)
 |
 | Version: 6.0 (100% confidence)
 | Found By: Readme - Stable Tag (Aggressive Detection)
 |  - http://127.0.0.1:8080/wp-content/plugins/wp-file-manager/readme.txt
 | Confirmed By: Readme - ChangeLog Section (Aggressive Detection)
 |  - http://127.0.0.1:8080/wp-content/plugins/wp-file-manager/readme.txt

[!] No WPScan API Token given, as a result vulnerability data has not been output.

The wp-file-manager line confirms an installed component at version 6.0 and shows it lags the current release. That inventory step comes before you query the API for CVE details.


Enumerate vulnerable plugins and themes

Version fingerprinting alone does not print CVE text. Pass -e vp (vulnerable plugins) or -e vt (vulnerable themes) with a WPScan API token so WPScan queries the API for components it finds. Run this after -e ap lists wp-file-manager 6.0 in the lab.

Register at wpscan.com/register and replace YOUR_TOKEN with your key. Use the same plugin detection mode that found the plugin in the inventory step — passive is enough when the homepage already references the plugin path:

bash
wpscan --url "$WP_URL" -e vp --plugins-detection passive --api-token YOUR_TOKEN --no-update

When the API lists issues for wp-file-manager 6.0, WPScan prints [!] Title:, Fixed in:, and References: lines under that plugin. The WPScan plugin page lists File Manager 6.0–6.9 – Unauthenticated Arbitrary File Upload leading to RCE (fixed in 6.9, CVE-2020-25213) among twelve records for this slug — those database fields map directly to the CLI lines you read in the scan transcript.

Read each [!] Title: line as an API-backed finding, note the Fixed in: version for patch planning, and follow the References: URLs to the WPScan vulnerability record and any linked CVE. Swap -e vp for -e vt to focus on themes.

Without a token, WPScan still fingerprints versions but omits CVE lines:

bash
wpscan --url "$WP_URL" -e vp --plugins-detection passive --no-update
output
[!] No WPScan API Token given, as a result vulnerability data has not been output.
[!] You can get a free API token with 25 daily requests by registering at https://wpscan.com/register

Pass --api-token to unlock the [!] Title: blocks for wp-file-manager 6.0 in this lab.


Enumerate WordPress users

User enumeration collects author names attackers might target for login guessing. WPScan combines RSS metadata, author ID brute force, and login error messages.

Enumerate users on the lab:

bash
wpscan --url "$WP_URL" -e u --no-update 2>&1 | tee "$LAB/users.txt"

Sample output (trimmed):

output
[+] Enumerating Users (via Passive and Aggressive Methods)

[i] User(s) Identified:

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

[+] Finished: Sun Aug  2 07:32:17 2026
[+] Requests Done: 52
[+] Elapsed time: 00:00:06

The admin line is a username candidate — not proof the account uses a weak password. Harden production sites by blocking user enumeration, enforcing strong passwords, and limiting login rate.


Brute force WordPress logins

After user enumeration, WPScan can try password lists against a named account. This lab uses the admin user and a three-line wordlist. Login attacks are noisy — run them only on systems you are authorized to test.

Attack the admin account with the lab wordlist:

bash
wpscan --url "$WP_URL" -U admin -P "$LAB/pass.txt" --no-update 2>&1 | tee "$LAB/brute.txt"

Sample output (trimmed):

output
[+] Performing password attack on Xmlrpc against 1 user/s

[SUCCESS] - admin / LabPass123!

[!] Valid Combinations Found:
 | Username: admin, Password: LabPass123!

[+] Finished: Sun Aug  2 07:32:45 2026
[+] Requests Done: 144
[+] Elapsed time: 00:00:13

WPScan recovered LabPass123! through the XML-RPC login path. Build custom lists with a wordlist generator when you know password patterns; keep lists small in lab exercises.


Troubleshooting

Symptom Likely cause Fix
Update required / missing database Never ran wpscan --update Run wpscan --update to refresh local metadata
Scan Aborted with HTTP 403 WAF or bot blocking default user agent Retry with --random-user-agent on authorized targets
No vulnerability details for plugins Missing or invalid API token Register at wpscan.com; pass --api-token with -e vp or -e vt
No installed plugins detected Passive detection missed them or none are installed Use -e ap --plugins-detection mixed; install a test plugin in the lab
-e ap mixed runs for many minutes Mixed mode probes thousands of known plugin paths Use passive detection when the homepage references the plugin; reserve mixed for blind targets
wp-file-manager breaks the site after install Plugin expects writable uploads paths Create wp-content/uploads/wp-file-manager-pro/fm_backup and chown www-data before scanning
-e vp mixed runs 20+ minutes with no plugins Aggressive known-location brute force on a minimal site Run -e ap first; use passive detection when homepage links expose the plugin
User enumeration returns nothing Hardened site or incomplete install Confirm WordPress finished setup; try -e u after posts exist
Password attack finds nothing Wrong username or list Confirm -U matches an enumerated user; expand "$LAB/pass.txt"
Docker image pull fails Registry rate limit Retry later, authenticate to Docker Hub, or use a mirror your org provides
Connection refused on 8080 Container not running sudo docker ps; restart wp-lab and wait for Apache
WP-CLI SSL errors inside container Container CA trust to wordpress.org Download wp-cli.phar on the host and sudo docker cp into the container

References


Summary

You installed WPScan 3.8.28 on Kali, refreshed local metadata with wpscan --update, and scanned a loopback-only Docker WordPress lab on port 8080. A basic pass reported core version 7.0.2, the twentytwentyfive theme, and enabled XML-RPC. Installed-plugin enumeration surfaced wp-file-manager 6.0, and user enumeration found admin. A short wordlist recovered LabPass123! through the XML-RPC login check.

CVE-style [!] Title: lines come from the WPScan API at scan time — not from the local metadata file. Pass --api-token with -e vp or -e vt after -e ap confirms outdated components such as wp-file-manager 6.0. Treat every finding as input to hardening: patch or remove outdated plugins, disable unused XML-RPC when policy allows, and block username enumeration on sites you administer.

Use WPScan only on authorized WordPress installs. Pair results with manual testing in Burp Suite or broader coverage in vulnerability scanning when the engagement goes beyond WordPress fingerprinting.


Frequently Asked Questions

1. What is WPScan used for in ethical hacking?

WPScan sends HTTP requests to fingerprint WordPress sites, enumerate versions, themes, plugins, and users, and can test login passwords against sites you own or are authorized to assess. It is active black-box reconnaissance for WordPress, not a generic web application scanner.

2. Is scanning WordPress sites with WPScan legal?

WPScan is appropriate only on WordPress installations you own or are explicitly authorized to test. Laws, hosting contracts, and bug bounty rules vary, so obtain written permission before scanning production customer sites or third-party blogs.

3. Do I need a WPScan API token?

Fingerprinting, user enumeration, and installed-plugin inventory work without a token. CVE-style vulnerability records are retrieved in real time from the WPScan API when you pass --api-token on enumeration commands such as -e vp or -e vt. Free tokens are available at wpscan.com with a daily request limit.

4. Why does WPScan abort before scanning?

Run wpscan --update first when local metadata is missing. A 403 response often means a WAF blocked the default user agent — retry with --random-user-agent on authorized targets.

5. WPScan vs Nmap for WordPress?

WPScan is built for WordPress enumeration, user discovery, and login testing. Nmap NSE scripts such as http-wordpress-enum can hint at plugins from a port scan, but WPScan is the dedicated tool for deep WordPress passes on sites you are allowed to test.
Kennedy Muthii

Information Security Analyst

Accomplished professional proficient in Python, ethical hacking, Linux, cybersecurity, and OSINT. With a track record including winning a national cybersecurity contest, launching a startup in Kenya, and holding a degree in information science, he is currently engaged in cutting-edge research in ethical hacking.

  • Python (programming language)
  • Certified Ethical Hacker
  • White Hat (Computer Security)
  • Linux
  • Penetration Testing