DEV Community

Cover image for I mapped every WordPress plugin CVE since 2023. Here's what the data says — and how I built it.
Zahid Rasheed
Zahid Rasheed

Posted on

I mapped every WordPress plugin CVE since 2023. Here's what the data says — and how I built it.

Most "is this plugin safe?" advice is vibes. I wanted numbers, so I built a dataset. Here's what it found, and exactly how, so you can check my work or build your own.

The finding first

Of 8,010 WordPress plugins with a publicly documented vulnerability since 2023 (15,534 vulnerability records in total):

  • 3,780 have been removed from the wordpress.org plugin directory. Removal stops updates but doesn't uninstall — affected sites keep running the code.
  • 277 carried a critical (CVSS ≥ 9.0) flaw on record before removal.
  • 2,115 are still installable today with a known vuln and no update in 12+ months — roughly 6.7M active installs combined.

The part that surprised me most: "removed from the directory" is nearly invisible to a site owner. No dashboard warning, no email. The plugin just quietly stops getting fixes while sitting on the site.

How I built it (no paid APIs)

The whole thing runs on two public sources and no API keys.

1. Vulnerability data — the GitHub Advisory Database. It mirrors CVE records including the Patchstack and Wordfence CNA assignments that cover almost all WordPress plugin CVEs. It's a git repo, so a shallow, sparse clone of the advisories/unreviewed/{year} folders gets you the raw JSON:

git clone --depth 1 --filter=blob:none --sparse \
  https://github.com/github/advisory-database.git
Enter fullscreen mode Exit fullscreen mode

Each advisory carries the CVE ID, a CVSS vector string, CWE IDs, and reference URLs. The plugin slug isn't a first-class field — you recover it from the Patchstack/Wordfence reference URLs with a couple of regexes. That alone attributes the large majority of WordPress advisories to a specific plugin.

2. Maintenance signals — the wordpress.org plugin API. For each slug:

https://api.wordpress.org/plugins/info/1.2/?action=plugin_information&request[slug]=SLUG
Enter fullscreen mode Exit fullscreen mode

That gives install count, last-updated date, tested-up-to version, and support-thread resolution ratio. A 404 (or an {error} body) means the plugin isn't in the directory — but that's ambiguous: it could be removed, or it could be a commercial plugin that was never hosted there. You have to disambiguate by reading the plugin's public page for the "this plugin has been closed" notice, which also carries the closure date. Skip that step and you'll report a commercial plugin like WP Rocket as "removed", which it never was.

Scoring, and why CVE count alone is a trap

The naive move is to rank by vulnerability count. That's backwards: a big, actively-maintained plugin with a bug-bounty program accumulates more CVEs than abandoned code nobody has ever audited. Rank by raw count and you punish the responsible plugins and reward the dangerous ones.

So the score combines two axes:

  • Vulnerability load — time-decayed severity (18-month half-life), weighted toward unauthenticated and recently-recurring issues.
  • Maintenance — update age, tested-up-to gap, unresolved support ratio, and directory-removal status.

The half-life matters: it makes the score describe a plugin's situation now, not its worst historical moment. And "no CVEs" never means "safe" — it often means "never examined", so absence of findings can't score as a positive.

What I'd do with this if you run WordPress sites

  1. Check whether any installed plugin has silently left the directory. There's no dashboard warning for this.
  2. Deactivating isn't removing — the files stay reachable on disk. Replace and delete.
  3. "Tested up to" three major versions ago is a maintenance smell even without a CVE.

The full index — one page per plugin, with the CVE timeline and the scoring method spelled out — is public and free: https://xuro.net/wordpress-plugin-security/ — and the method page shows every input and weight, because a score you can't audit isn't worth citing.

Happy to answer questions on the pipeline in the comments.

Top comments (0)