How to Use WPScan to Scan WordPress: 12 Steps, 90 Min [2026]

WordPress powers a large share of the web, which makes its plugin and theme ecosystem the single largest attack surface in the CMS world. In August 2026, that risk got concrete: a critical, unauthenticated remote code execution flaw tracked as CVE-2026-63030 (CVSS 9.8) pushed site owners toward WordPress core builds 6.9.5 and 7.0.2, and the same week brought fresh advisories for on-prem SharePoint (CVE-2026-50522) and Citrix NetScaler. If you run WordPress, you don’t need to memorize every CVE number. You need a repeatable way to find out, in minutes, whether your own site is exposed. That’s what WPScan does.

WPScan is a free, black-box WordPress vulnerability scanner built specifically for WordPress core, plugins, and themes. It ships pre-installed on Kali Linux, runs as a Ruby gem or Docker container, and pulls its vulnerability data from the WPScan Vulnerability Database, a feed the WPScan team has maintained since 2014. This tutorial walks through installing WPScan, configuring an API token, running your first enumeration scan, reading the output, and turning findings into an actual remediation checklist. By the end, you’ll have a working scan script you can run on a schedule and a documented process for handling what it finds.

Google · Preferred Sources

Don't miss new tech stories on Google

Add Tech Insider once in the Google app and our stories appear in your news suggestions.

Add Now

What WPScan Is (and What It Isn’t)

WPScan is an open-source command-line tool, originally released by the WPScan Team and now maintained under Automattic’s security umbrella after WPScan’s 2021 acquisition by WordPress parent company. It performs non-intrusive fingerprinting against a live WordPress URL: it identifies the WordPress core version, enumerates active plugins and themes, checks for exposed configuration files, and cross-references what it finds against the WPScan Vulnerability Database, which tracks thousands of known WordPress core, plugin, and theme CVEs.

It is not a full penetration testing suite, and it doesn’t exploit anything on its own (a few brute-force and enumeration modules aside). Think of it as a specialized WordPress-focused cousin of general web scanners like Nessus or OpenVAS — narrower in scope, but far deeper on this one platform. If you’re already running a broader vulnerability management program, WPScan slots in as the WordPress-specific layer; see our guide on building a vulnerability management program for how it fits the bigger picture.

The tool has two operating modes that matter for this tutorial. Passive/default mode reads publicly visible markers (readme files, generator meta tags, static asset paths) to guess versions. Aggressive mode sends additional requests to confirm plugin and theme versions more precisely, at the cost of being noisier and slower. For your own sites, aggressive mode is almost always the right call, because false confidence in a passive scan can leave a real vulnerability unflagged.

How the WPScan Vulnerability Database Actually Works

The scanner itself is just the delivery mechanism. The real value sits in the database behind it, curated by a dedicated WPScan security team that reviews public disclosures, coordinates with plugin authors, and assigns its own internal tracking alongside the official CVE identifier when one exists. Each entry records the affected software (core, a specific plugin slug, or a theme slug), the vulnerable version range, the fixed version, a vulnerability type classification (SQL injection, cross-site scripting, privilege escalation, arbitrary file upload, and so on), and a reference list pointing back to the original disclosure.

That last detail matters more than it sounds. WordPress plugin vulnerabilities frequently get reported through bug bounty platforms and third-party researchers well before a CVE number is officially assigned by MITRE or a CVE Numbering Authority. WPScan’s database often lists these findings faster than the CVE ecosystem catches up, which is one reason security teams treat it as a primary WordPress-specific feed rather than a downstream mirror of CVE.org. When you see a WPScan finding referencing only an internal WPScan ID and no CVE number yet, that’s not a lesser finding — it just means the paperwork hasn’t caught up with the disclosure.

Understanding CVSS severity bands helps you triage a long findings list without reading every advisory in full:

CVSS RangeSeverityTypical Response Time
9.0 – 10.0CriticalSame day — patch, disable the plugin, or apply a WAF rule immediately
7.0 – 8.9HighWithin 48-72 hours
4.0 – 6.9MediumWithin the current patch cycle (typically 1-2 weeks)
0.1 – 3.9LowNext scheduled maintenance window

These aren’t hard rules, and CVSS score alone doesn’t capture everything you should weigh. A medium-severity flaw with confirmed active exploitation in the wild deserves faster action than an unexploited critical sitting in a plugin nobody has bothered to target yet. Cross-reference WPScan findings against exploitation status where it’s noted, and default to the more conservative (faster) timeline when in doubt.

Prerequisites: What You Need Before You Start

WPScan runs on Linux, macOS, and Windows via WSL. You have three realistic installation paths: a Ruby gem install, a Docker container, or Kali Linux’s bundled version. Confirm you have the following before starting:

  • Ruby 3.1 or newer (WPScan is a Ruby gem; check with ruby -v) — install from ruby-lang.org if missing
  • RubyGems and build tools (build-essential on Debian/Ubuntu, Xcode command-line tools on macOS)
  • Docker Engine 24+ if you prefer the containerized route (no Ruby dependency management needed)
  • A free WPScan API token from wpscan.com — required to pull live vulnerability data; the free tier allows 25 daily API requests, enough for periodic scans of a handful of sites
  • Explicit authorization to scan the target site. Only run WPScan against WordPress sites you own or have written permission to test. Scanning third-party sites without consent can violate the Computer Fraud and Abuse Act in the US and equivalent computer-misuse laws elsewhere.
  • Roughly 500MB of free disk space for the Ruby gem, its dependencies, and the local vulnerability database cache
  • A terminal with internet access to reach the WPScan API and the target site

This tutorial assumes Ubuntu 24.04 LTS or a comparable Debian-based distro for the native install path, and covers the Docker and Kali alternatives inline. Total time: roughly 90 minutes for install, first scan, and working through a full remediation pass on a real site.

Step 1: Choose Your Installation Method

Before installing anything, decide which of the three paths fits your environment:

MethodBest ForSetup TimeMaintenance
Ruby gem (native)Regular use on a dedicated Linux/macOS machine10-15 minManual gem update needed
Docker containerIsolated, disposable scans; CI/CD pipelines2-5 minPull latest image each run
Kali Linux (pre-installed)Security professionals already on Kali0 min (bundled)Handled by apt update

For most WordPress site owners and developers running their own periodic checks, the Docker route is the least friction: no Ruby version conflicts, no gem dependency headaches, and it’s trivial to drop into a GitHub Actions or GitLab CI job later. We’ll cover the gem install as the primary path since it gives you the fastest iteration for repeated local scans, then show the Docker equivalent.

Step 2: Install WPScan via RubyGems

On Ubuntu/Debian, first confirm Ruby and install the build dependencies WPScan’s native extensions need:

sudo apt update
sudo apt install -y ruby-full build-essential libcurl4-openssl-dev libxml2-dev libxslt1-dev zlib1g-dev
ruby -v
gem install wpscan

On macOS with Homebrew:

brew install ruby
gem install wpscan

Once installed, verify the version and confirm the binary is on your path:

wpscan --version

You should see a version banner along with the WPVulnDB update timestamp. If you get command not found, your gem bin directory (usually ~/.gem/ruby/<version>/bin or /usr/local/bin) isn’t on your $PATH — add it to your shell profile and re-source it.

Step 3: Alternative — Run WPScan With Docker

If you’d rather skip Ruby entirely, pull the official image and run it directly:

docker pull wpscanteam/wpscan
docker run -it --rm wpscanteam/wpscan --url https://your-site.example --api-token YOUR_TOKEN

The Docker route is stateless by default, so you’ll re-download the vulnerability database check on every run unless you mount a volume. For repeated scans, mount a local cache directory to avoid hammering the API on every container start:

mkdir -p ~/.wpscan-cache
docker run -it --rm -v ~/.wpscan-cache:/root/.wpscan \
  wpscanteam/wpscan --url https://your-site.example --api-token YOUR_TOKEN

Kali Linux users can skip both routes: WPScan ships in the default Kali repositories, so sudo apt install wpscan (or a straight apt update && apt upgrade if it’s already there) gets you current. Full details are on the official Kali WPScan tool page.

Step 4: Get a Free WPScan API Token

WPScan’s vulnerability lookups run against a hosted database, which requires an API token even on the free tier. Create an account at wpscan.com/api and generate a token from your dashboard. The free tier caps you at 25 API requests per day — each scanned site typically consumes several requests depending on how many plugins and themes it enumerates, so budget accordingly if you’re checking more than a couple of sites daily. Paid tiers remove the daily cap and add unlimited plugin/theme checks for agencies managing larger WordPress fleets.

Once you have your token, avoid pasting it directly into shell history. Export it as an environment variable instead:

export WPSCAN_API_TOKEN="your_token_here"
echo 'export WPSCAN_API_TOKEN="your_token_here"' >> ~/.bashrc

WPScan automatically picks up the WPSCAN_API_TOKEN environment variable, so you no longer need to pass --api-token on every invocation.

Step 4b: Build a Safe Local Target to Practice On

If you don’t want your first WPScan run to be against a live production site, spin up a disposable local WordPress instance with Docker. This gives you an unambiguously authorized target to learn the tool’s output format on before pointing it at anything that matters:

docker network create wp-test-net

docker run -d --name wp-test-db --network wp-test-net \
  -e MYSQL_ROOT_PASSWORD=rootpass \
  -e MYSQL_DATABASE=wordpress \
  mysql:8.0

docker run -d --name wp-test-site --network wp-test-net \
  -p 8080:80 \
  -e WORDPRESS_DB_HOST=wp-test-db \
  -e WORDPRESS_DB_NAME=wordpress \
  -e WORDPRESS_DB_PASSWORD=rootpass \
  wordpress:latest

# Give it a few seconds to initialize, then visit
# http://localhost:8080 to finish the WordPress setup wizard

Once the setup wizard is done, install a couple of older plugin versions deliberately (WordPress.org’s plugin repository keeps prior releases available under each plugin’s “Advanced View” tab) so your practice scan actually returns findings instead of a clean report. Point WPScan at http://localhost:8080 and you have a fully legal, fully authorized environment to get comfortable with enumeration flags, output formats, and severity triage before running anything against a real domain.

Step 5: Run Your First Scan

With the token exported, run a baseline scan against a site you control:

wpscan --url https://your-site.example

By default WPScan runs in “mixed” mode: passive checks first, then a small set of aggressive plugin-version checks. This first pass typically finishes in under a minute for a small-to-mid-size site and gives you the WordPress core version, the active theme, an interesting-findings list (exposed readme.html, XML-RPC availability, exposed user IDs via the REST API), and any core-level CVEs matched against that version.

Notice it does not enumerate plugins or themes by default — that’s a separate, explicit flag, because full enumeration is noisier and slower. That’s Step 6.

Step 6: Run a Full Enumeration Scan

To get the scan that actually matters for vulnerability discovery, enable plugin, theme, and user enumeration with aggressive detection mode:

wpscan --url https://your-site.example \
  --enumerate vp,vt,u \
  --plugins-detection aggressive \
  --random-user-agent \
  --output wpscan-report.json --format json

Here’s what each flag does:

  • --enumerate vp,vt,u — checks vulnerable plugins (vp), vulnerable themes (vt), and enumerates usernames (u). Use ap/at instead of vp/vt if you want ALL detected plugins/themes listed, not just the ones matching known vulnerabilities
  • --plugins-detection aggressive — sends additional fingerprinting requests per plugin instead of relying on passive markers alone
  • --random-user-agent — rotates the user-agent string per request, useful if your own WAF or bot-mitigation rules would otherwise block the scan
  • --output / --format json — writes machine-readable output you can pipe into other tooling, a dashboard, or a ticketing system

Aggressive enumeration against a plugin-heavy site can take several minutes and will generate a noticeable spike in server log entries — expected and harmless against your own infrastructure, but exactly the kind of traffic pattern that should never appear against a site you don’t control.

Step 7: Read and Prioritize the Output

WPScan’s terminal output groups findings under color-coded severity markers. A typical scan against a moderately maintained site returns something like this:

[+] WordPress version 6.8.2 identified (Insecure, released on 2026-03-11).
 | Found By: Rss Generator (Passive Detection)
 | Confirmed By: Meta Generator (Passive Detection)
 |
 | [!] 4 vulnerabilities identified:
 |
 | [!] Title: WordPress < 6.9.5 - Unauthenticated RCE via Interpretation Conflict
 |     Fixed in: 6.9.5
 |     References:
 |      - CVE-2026-63030
 |      - CVSS: 9.8

[+] WordPress theme in use: astra-theme
 | Location: https://your-site.example/wp-content/themes/astra-theme/
 | [!] The version is out of date, the latest version is 4.11.2

[+] Enumerating Vulnerable Plugins (via Passive and Aggressive Methods)
 [+] contact-form-7
 | Location: https://your-site.example/wp-content/plugins/contact-form-7/
 | Latest Version: 6.1.3 (up to date)

 [+] elementor
 | Location: https://your-site.example/wp-content/plugins/elementor/
 | Installed version: 3.28.0
 | [!] 1 vulnerability identified:
 |
 | [!] Title: Elementor < 3.29.1 - Contributor+ Stored XSS
 |     Fixed in: 3.29.1
 |     References:
 |      - CVE-2026-41027

Work through findings in this order:

  • Core version issues first. A vulnerable WordPress core is the highest-blast-radius finding, since it can affect every plugin and every user on the site.
  • CVSS 9.0+ plugin/theme findings second. Anything scoring “Critical” that allows unauthenticated remote code execution or SQL injection jumps the queue regardless of what else is in the report.
  • Everything else, ranked by CVSS. Cross-reference against exploit-in-the-wild status; a 7.5 with active exploitation deserves more urgency than an unexploited 8.5.
  • Informational findings last. Exposed usernames, readme files, and XML-RPC availability aren’t CVEs but they widen the attack surface for brute-force and enumeration attacks — worth fixing, not worth panicking over.

Step 8: Patch WordPress Core

If WPScan flags an outdated core version, patch it immediately via WP-CLI (faster and more scriptable than the dashboard updater for anyone managing more than one site):

# Back up first — always
wp db export backup-pre-patch-$(date +%Y%m%d).sql --allow-root

# Check current version
wp core version --allow-root

# Update to latest core release
wp core update --allow-root

# Update the database schema if the release requires it
wp core update-db --allow-root

# Confirm the new version
wp core version --allow-root

For the CVE-2026-63030 core RCE specifically, confirm you land on 6.9.5 or 7.0.2 (whichever major branch you’re tracking) — anything earlier on either branch remains exposed. Re-run WPScan after patching to confirm the finding clears.

Step 9: Patch or Remove Vulnerable Plugins and Themes

Plugin and theme updates follow the same WP-CLI pattern, and can be scripted across your whole plugin list at once:

# List plugins with available updates
wp plugin list --update=available --allow-root

# Update a single flagged plugin
wp plugin update elementor --allow-root

# Update every plugin with a pending update
wp plugin update --all --allow-root

# If a plugin has no fix available yet, deactivate it until one ships
wp plugin deactivate vulnerable-plugin-slug --allow-root

If a plugin is abandoned (no update in 2+ years, flagged “closed” on the WordPress.org plugin directory) and has an unpatched vulnerability, the only durable fix is replacing it. Check the plugin’s support forum and changelog before assuming a fix is coming — WPScan’s database entry usually links the advisory that triggered the flag, which tells you whether a patched version already exists.

Step 10: Automate Recurring Scans

A one-time scan tells you where you stand today. A scheduled scan tells you when something changes. Set up a daily cron job that runs WPScan and emails or Slack-notifies you on new findings:

#!/bin/bash
# /usr/local/bin/wpscan-daily.sh
SITE_URL="https://your-site.example"
REPORT_DIR="/var/log/wpscan"
DATE=$(date +%Y%m%d)

mkdir -p "$REPORT_DIR"
wpscan --url "$SITE_URL" \
  --enumerate vp,vt \
  --plugins-detection aggressive \
  --format json \
  --output "$REPORT_DIR/scan-$DATE.json" \
  --api-token "$WPSCAN_API_TOKEN"

# Alert only if vulnerabilities were found (exit code 5 = vulnerable)
if [ $? -eq 5 ]; then
  curl -X POST -H 'Content-type: application/json' \
    --data '{"text":"WPScan found new vulnerabilities on '"$SITE_URL"' — check '"$REPORT_DIR/scan-$DATE.json"'"}' \
    "$SLACK_WEBHOOK_URL"
fi

Register it with cron to run every morning:

chmod +x /usr/local/bin/wpscan-daily.sh
crontab -e
# Add: 0 6 * * * /usr/local/bin/wpscan-daily.sh

WPScan’s exit codes make automation reliable without parsing text output: 0 means no vulnerabilities found, 4 means the scan errored out, and 5 specifically means vulnerabilities were detected — that’s the code your alerting logic should key off.

Step 11: Add WPScan to a CI/CD Pipeline

For teams deploying WordPress via a Git-based workflow, run WPScan against a staging environment as a pipeline gate before production deploys. A minimal GitHub Actions job:

name: WPScan Staging Check
on:
  pull_request:
    branches: [main]

jobs:
  wpscan:
    runs-on: ubuntu-latest
    steps:
      - name: Run WPScan against staging
        run: |
          docker run --rm wpscanteam/wpscan \
            --url ${{ secrets.STAGING_URL }} \
            --api-token ${{ secrets.WPSCAN_API_TOKEN }} \
            --enumerate vp,vt \
            --format cli-no-color
        continue-on-error: false

This won’t catch every real-world vulnerability (staging environments often diverge from production plugin configurations), but it catches the obvious regressions — a plugin update that got reverted, a theme rollback that reintroduces a patched CVE.

Step 12: Harden Beyond What WPScan Flags

WPScan tells you what’s vulnerable; it doesn’t fix your overall security posture. Pair it with these baseline hardening steps that address issues WPScan can only partially detect:

  • Disable XML-RPC if you don’t use Jetpack or the WordPress mobile app — it’s a common brute-force and DDoS amplification vector that WPScan flags as informational, not critical, but attackers treat it as an easy win
  • Limit login attempts and enforce two-factor authentication on all admin and editor accounts, especially after WPScan’s username enumeration reveals valid logins
  • Put a WAF in front of the site (Cloudflare, Sucuri, or Wordfence’s firewall) to virtually patch known CVEs while you roll out the real plugin update
  • Restrict file editing in wp-config.php with define('DISALLOW_FILE_EDIT', true); to block the theme/plugin editor even if an account is compromised
  • Review your SPF, DKIM, and DMARC configuration — a compromised WordPress install is frequently repurposed to send phishing mail, and proper email authentication limits the blast radius

Common Pitfalls When Running WPScan

These are the mistakes that trip up most first-time WPScan users, in rough order of frequency:

  • Scanning a site without authorization. The single most consequential mistake. Only scan domains you own or have explicit written permission to test — this isn’t a gray area legally.
  • Forgetting the API token and getting core-only results. Without --api-token, WPScan can still detect the WordPress version and interesting findings, but it silently skips vulnerability lookups against the database, giving you a false sense of “clean.”
  • Relying on passive detection alone. Passive mode misses plugins that don’t expose version strings in public assets. Always pair enumeration with --plugins-detection aggressive on sites you control.
  • Burning through the 25-request daily cap mid-scan. Scanning several sites with full plugin/theme enumeration in one session can exhaust the free tier fast, leaving later scans with incomplete vulnerability data and no obvious error explaining why.
  • Treating a clean WPScan report as a clean bill of health. WPScan only flags known, published vulnerabilities. Zero-days and custom-code flaws (a common WordPress child-theme mistake) won’t show up — it’s one input to your security process, not the whole process.
  • Running aggressive scans against production during peak traffic. Aggressive enumeration adds real request volume; schedule it for low-traffic windows on resource-constrained hosting.
  • Ignoring the “outdated but no CVE” plugins. WPScan’s vp/vt flags only surface plugins with a matched vulnerability entry. An outdated plugin with no known CVE yet isn’t automatically safe — check with --enumerate ap periodically to catch version drift before a CVE gets published.

Troubleshooting WPScan Issues

ProblemLikely CauseFix
wpscan: command not foundGem bin directory not on $PATHRun gem environment to find the bin path, add it to your shell profile
Error installing native extensionsMissing build tools / dev headersInstall build-essential libcurl4-openssl-dev libxml2-dev (Debian/Ubuntu) before retrying gem install
“No WPScan API Token given” warningToken not exported or typo’dRe-export WPSCAN_API_TOKEN and confirm with echo $WPSCAN_API_TOKEN
API request limit reachedFree tier’s 25 daily requests exhaustedWait for the daily reset, reduce sites scanned per day, or upgrade to a paid API plan
Scan returns “The remote website is up, but does not seem to be running WordPress”WAF/CDN masking WordPress fingerprints, or site genuinely isn’t WordPress at that URLTry --force to scan anyway, or confirm the URL resolves to the right origin
Scan times out or hangsWAF rate-limiting the scanner’s IPAdd --throttle 1000 (milliseconds between requests) and --random-user-agent
Plugin enumeration finds far fewer plugins than expectedPassive-only detection modeRe-run with --plugins-detection aggressive and --enumerate ap for all plugins, not just vulnerable ones
SSL certificate errors against staging environmentsSelf-signed or expired cert on internal stagingAdd --disable-tls-checks for internal, trusted staging environments only — never for production or third-party targets
Docker container can’t reach an internal/staging URLContainer network isolationAdd --network host to the docker run command, or use the container’s DNS-resolvable service name
JSON output file is empty after the scanOutput path not writable, or scan errored before completionCheck the exit code (echo $?) and confirm the output directory has write permissions

Advanced Tips for Ongoing WordPress Vulnerability Management

Once the basic scan-and-patch loop is working, a few refinements make WPScan meaningfully more useful over time:

Baseline and diff, don’t just re-scan. Store each JSON report and diff it against the previous run rather than re-reading the whole thing manually. A simple jq comparison against the prior day’s plugin version list surfaces new findings immediately:

jq '.plugins | keys' scan-20260821.json > yesterday.txt
jq '.plugins | keys' scan-20260822.json > today.txt
diff yesterday.txt today.txt

Combine WPScan with a broader scanner for defense in depth. WPScan is WordPress-specific by design, so it won’t catch server-level misconfigurations, exposed backup files outside the WordPress directory structure, or infrastructure-level CVEs. Run it alongside a general-purpose scanner — see our Nessus vs Qualys vs OpenVAS comparison for options that cover the rest of the stack.

Use --enumerate u results defensively, not just diagnostically. If WPScan can enumerate your usernames through public archive pages or the REST API, so can an attacker. Rename any account still using “admin” and lock down /wp-json/wp/v2/users if you don’t have a functional reason to expose it.

Track exploited-in-the-wild status, not just CVSS score. A 7.2 CVE with confirmed active exploitation (check CVE.org and vendor advisories) deserves faster remediation than an unexploited 8.8. WPScan’s database entries typically link the disclosure source, which usually notes exploitation status.

Fold WPScan into your incident response runbook. If a site shows signs of compromise, a WPScan run is a fast first diagnostic step to check whether a known, unpatched vulnerability is the likely entry point. See our incident response plan guide for how to structure that runbook end to end.

Responsible Disclosure: If a Scan Turns Up Something Unexpected

Occasionally a scan against your own site surfaces something that isn’t in the WPScan database yet — a plugin behaving in a way that looks exploitable but has no matching CVE or advisory on record. That’s a different situation from patching a known issue, and it’s worth knowing the right next step rather than guessing.

Start by checking the plugin’s changelog and support forum on WordPress.org for any hint the author already knows about it. If nothing turns up, most plugin authors list a security contact in their readme.txt file or on their developer website; email them directly with a clear, minimal reproduction rather than posting publicly. If the plugin has no visible security contact, WPScan itself accepts vulnerability submissions through its own disclosure process, and larger plugins (WooCommerce, Elementor, Yoast, and similar high-install-count projects) typically run bug bounty programs through platforms like HackerOne or Bugcrowd that provide a structured, often paid submission path.

Give the author a reasonable window to ship a fix, generally 30-90 days depending on severity, before any public write-up. Coordinated disclosure isn’t just professional courtesy — a plugin used on hundreds of thousands of sites represents real exposure for real site owners the moment exploit details go public before a patch exists. In the meantime, protect your own site with a WAF rule or by disabling the affected functionality, and keep a private record of your report dates in case you need to demonstrate you followed a reasonable disclosure timeline.

Complete Working Project: Multi-Site WPScan Monitor

Here’s a complete script that ties everything together: it scans a list of sites, writes timestamped JSON reports, and posts a summary to Slack. Save it as wpscan-fleet.sh:

#!/bin/bash
# wpscan-fleet.sh — scan multiple WordPress sites and report findings

set -euo pipefail

SITES_FILE="./sites.txt"          # one URL per line
REPORT_DIR="./wpscan-reports/$(date +%Y%m%d)"
SLACK_WEBHOOK_URL="${SLACK_WEBHOOK_URL:?Set SLACK_WEBHOOK_URL first}"
WPSCAN_API_TOKEN="${WPSCAN_API_TOKEN:?Set WPSCAN_API_TOKEN first}"

mkdir -p "$REPORT_DIR"
VULN_COUNT=0
SUMMARY=""

while IFS= read -r SITE; do
  [ -z "$SITE" ] && continue
  SLUG=$(echo "$SITE" | sed -E 's#https?://##; s#/##g')
  OUTFILE="$REPORT_DIR/$SLUG.json"

  echo "Scanning $SITE..."
  set +e
  wpscan --url "$SITE" \
    --enumerate vp,vt \
    --plugins-detection aggressive \
    --random-user-agent \
    --throttle 500 \
    --api-token "$WPSCAN_API_TOKEN" \
    --format json \
    --output "$OUTFILE"
  EXIT_CODE=$?
  set -e

  if [ "$EXIT_CODE" -eq 5 ]; then
    COUNT=$(jq '[.plugins[]?.vulnerabilities[]?] | length' "$OUTFILE" 2>/dev/null || echo "?")
    SUMMARY="$SUMMARY\n- $SITE: $COUNT vulnerabilities found"
    VULN_COUNT=$((VULN_COUNT + 1))
  fi
done < "$SITES_FILE"

if [ "$VULN_COUNT" -gt 0 ]; then
  curl -s -X POST -H 'Content-type: application/json' \
    --data "{\"text\":\"WPScan fleet report ($(date +%Y-%m-%d)): $VULN_COUNT site(s) with findings.$SUMMARY\"}" \
    "$SLACK_WEBHOOK_URL"
else
  echo "No vulnerabilities found across $(wc -l < "$SITES_FILE") sites."
fi

Create a sites.txt file listing one WordPress URL per line, export your two required environment variables, and schedule the script with cron just like the single-site example above. The result is a lightweight, self-hosted vulnerability monitor for an entire WordPress fleet, built entirely on free tooling.

WPScan vs Other WordPress Security Tools

WPScan isn't the only way to check WordPress security posture. Here's how it stacks up against the other common options:

ToolTypeCostBest Use Case
WPScanCLI black-box scannerFree (25 req/day) or paid APIFast, scriptable, CI/CD-friendly vulnerability checks
WordfenceWordPress plugin (in-app firewall + scanner)Free / Premium paid tiersContinuous in-dashboard monitoring, non-technical site owners
Sucuri SiteCheckWeb-based remote scannerFree basic / paid full auditQuick malware and blocklist checks without installing anything
PatchstackManaged vulnerability intelligence + virtual patchingPaid subscriptionAgencies managing many client sites needing proactive virtual patches

The realistic answer for most teams is to run more than one: WPScan for fast, scriptable CLI checks in CI/CD and cron, plus an in-dashboard plugin like Wordfence for continuous monitoring between scans. They overlap in coverage but not in delivery method, and the combination catches more than either alone.

Why This Matters Right Now

The urgency behind running a WordPress vulnerability scanner isn't hypothetical in August 2026. Microsoft's August Patch Tuesday alone shipped fixes for roughly 751 CVEs across its product families, with 108 rated critical — a reminder that the volume of disclosed vulnerabilities across the software stack keeps climbing, and WordPress's plugin ecosystem is no exception. The CVE-2026-63030 core RCE (CVSS 9.8) specifically requires an unauthenticated attacker to chain an interpretation-conflict bug into remote code execution, which is about as bad as a CMS vulnerability gets — no login required, no user interaction needed. If your WordPress install still sits on a build prior to 6.9.5 or 7.0.2, WPScan will catch it in the first minute of a scan, which is a far better way to find out than an incident report.

The broader lesson holds beyond this one CVE: plugin and theme vulnerabilities get disclosed constantly, and WordPress's popularity makes it a default target for automated exploitation scripts that scan the entire web for known-vulnerable version strings within days of a public disclosure. A scheduled WPScan run is the cheapest insurance available against being an easy, automated target.

Frequently Asked Questions

Is WPScan legal to use?
Yes, running WPScan against a site you own or have explicit written authorization to test is legal. Scanning a third-party WordPress site without permission is unauthorized access under laws like the US Computer Fraud and Abuse Act and can carry serious legal consequences, even if no data is stolen and no damage is done.

Does WPScan slow down or damage the site being scanned?
A default or passive scan generates minimal load, comparable to a handful of normal page visits. Aggressive enumeration against a plugin-heavy site generates more requests and can trigger rate-limiting or WAF blocks, but it doesn't modify data or exploit anything by default — it's read-only reconnaissance, not an attack.

How often should I run WPScan?
Daily automated scans are reasonable for production sites, especially given how quickly attackers weaponize newly disclosed CVEs. At minimum, run it weekly and immediately after installing any new plugin or theme.

Can WPScan find vulnerabilities in custom code, not just plugins and themes?
No. WPScan matches against a database of known, published vulnerabilities in publicly distributed WordPress core, plugins, and themes. Custom-built functionality in a child theme or a bespoke plugin won't be in that database, so it needs manual code review or a dedicated static analysis tool instead.

What's the difference between the free and paid WPScan API tiers?
The free tier caps requests at 25 per day and covers most individual site owners running periodic scans. Paid tiers remove the daily limit and are aimed at agencies or hosting providers running WPScan across dozens or hundreds of client sites on a schedule.

Does WPScan replace a Web Application Firewall?
No — they solve different problems. WPScan is a point-in-time detection tool that tells you what's vulnerable. A WAF is a continuous prevention layer that can block exploitation attempts even against a vulnerability you haven't patched yet. Use both: WPScan to find and prioritize, a WAF to buy time while you patch.

Why did my scan report zero vulnerabilities when I know a plugin is outdated?
WPScan's vp/vt enumeration flags only list plugins matched against a known CVE in its database. An outdated plugin with no disclosed vulnerability yet won't be flagged as vulnerable, even though staying current is still good practice. Run --enumerate ap to see every detected plugin regardless of vulnerability status, then cross-check versions manually against the WordPress.org plugin directory.

Can I run WPScan on a WordPress multisite network?
Yes. Point WPScan at each subsite's public URL individually — the tool scans whatever URL you give it as a standalone WordPress front end, and multisite installs generally expose each site the same way a single install does from the outside.

Related Coverage

Elias Virtanen

Elias Virtanen

Cybersecurity Analyst

Elias Virtanen is the Cybersecurity Analyst at Tech Insider, bringing hands-on expertise from his background in penetration testing and security consulting. He previously worked as a security researcher at F-Secure in Helsinki, where he focused on threat intelligence and vulnerability disclosure. Elias covers ransomware trends, zero-trust architecture, and the evolving regulatory landscape including NIS2 and the EU Cyber Resilience Act. He holds a CISSP certification and an MSc in Information Security from Aalto University.

View all articles