DEV Community

Calin V.
Calin V.

Posted on Originally published at wpghost.com

Checking WordPress plugins against vulnerability records from the command line

Patchstack's 2026 report found that 91% of the WordPress vulnerabilities disclosed in 2025 were in plugins. Only six were in core.

So the plugin list is where the checking time goes. Here's a version of that check you can run from a shell, with WP-CLI and curl.

1. Get the real list, inactive plugins included

wp plugin list --fields=name,status,version,update --format=table
Enter fullscreen mode Exit fullscreen mode

Keep the inactive rows. A deactivated plugin is still on disk, and its PHP files can still be requested by URL.

You can see that from outside. Most plugins ship a readme.txt with a Stable tag line:

curl -s -o /dev/null -w "%{http_code}\n" "https://example.com/wp-content/plugins/contact-form-7/readme.txt"
Enter fullscreen mode Exit fullscreen mode

A 200 means anyone can read which version you run, active or not. That's the same file a scanner reads before it picks an exploit.

If a plugin isn't used, delete it:

wp plugin list --status=inactive --field=name
wp plugin delete <slug>
Enter fullscreen mode Exit fullscreen mode

2. Check the plugin is still maintained

The wordpress.org plugin API returns the last update, the "Tested up to" version and the install count:

curl -sg "https://api.wordpress.org/plugins/info/1.2/?action=plugin_information&request[slug]=contact-form-7&request[fields][sections]=0" \
  | jq '{version, last_updated, tested, active_installs}'
Enter fullscreen mode Exit fullscreen mode

A last_updated more than a year old is a warning sign. When a flaw turns up in an abandoned plugin, nobody ships the fix.

3. Look up the vulnerability records

Four public sources hold WordPress records:

Source Access
Patchstack database (patchstack.com/database) Web search
WPScan (wpscan.com) Web search, plus an API with a free token
Wordfence Intelligence Web search
NVD (nvd.nist.gov) CVE records with CVSS scores

The WPScan API answers per plugin slug:

curl -s -H "Authorization: Token token=$WPSCAN_API_TOKEN" \
  "https://wpscan.com/api/v3/plugins/contact-form-7" \
  | jq '.["contact-form-7"].vulnerabilities[] | {title, fixed_in}'
Enter fullscreen mode Exit fullscreen mode

Check a second source by hand. The databases don't always publish the same flaw on the same day.

4. Compare your version with fixed_in

The title of a record is the least useful part. The fixed_in field tells you whether you're still exposed.

# example values
installed="2.4.1"
fixed="2.4.3"
if [ "$(printf '%s\n' "$installed" "$fixed" | sort -V | head -n1)" = "$fixed" ]; then
  echo "patched"
else
  echo "VULNERABLE: update to $fixed or later"
fi
Enter fullscreen mode Exit fullscreen mode

sort -V handles version strings like 5.10 vs 5.9 correctly. A plain string compare doesn't.

Then read two more fields on the record:

Field What it changes
Authentication A flaw that works without a login goes first
Type SQL injection and remote code execution are urgent

An empty fixed_in means no fix exists. Patchstack's 2026 report says 46% of 2025 vulnerabilities had no patch at disclosure, so expect to see that often.

5. When there's no fix yet

Remove the plugin if the site can live without it.

If it can't, block the route the record names at the server, and cut the version leak from step 1. In nginx:

location ~* ^/wp-content/plugins/[^/]+/readme\.txt$ {
    return 404;
}
Enter fullscreen mode Exit fullscreen mode

On Apache, a .htaccess in wp-content/plugins/:

<FilesMatch "^readme\.txt$">
    Require all denied
</FilesMatch>
Enter fullscreen mode Exit fullscreen mode

That doesn't patch anything. It removes the version number a scanner uses to match your plugin to a record.

Changing the default plugin path goes one step further, because a scan of /wp-content/plugins/ then gets a 404 for every folder. WP Ghost can do that from the WordPress admin, next to the server rules above.

6. Repeat it

Put steps 1, 3 and 4 in a monthly cron or CI job, and run them by hand whenever a new plugin goes in.

The full checklist, with the wordpress.org page checks and the screenshots, is on the WP Ghost blog.

What do you use to watch plugin records across many sites, the WPScan API or something you built yourself?

Top comments (0)