WordPress Plugins and Themes Vulnerabilities: Stats, Facts and Recommendations.

Revision: February 13, 2020

For the past six months, we have reported and then disclosed on this blog quite a lot of vulnerabilities we discovered in WordPress themes and plugins. Here are below some interesting stats and facts about them, as well as a few recommendations for developers.

Vulnerabilities Summary

Discovered and reported vulnerabilities: 81
Vulnerable plugins and themes: 95 (74 plugins, 21 themes).
Total active installations: 4.2+ million.

Note that the number of reported vulnerabilities is lower than the number of vulnerable plugins and themes because sometimes the same vulnerabilities affected several plugins or themes. For instance, in our YIT Framework vulnerability advisory there were two vulnerabilities affecting 38 plugins, therefore we counted 2 unique vulnerabilities, not 2*38 vulnerabilities.

Current Status of all Reported Vulnerabilities

Fixed vulnerabilities: 60, as of today February 13, 2020.
Unfixed vulnerabilities: 21, affecting 23 themes or plugins.
Among them:

  • 4 will likely be fixed.
  • 6 might be fixed one day or another (I really don’t know whether they’ll be fixed or not!).
  • 11 won’t be fixed at all (authors don’t support the theme or plugin anymore and don’t want to fix the issue etc).

Unfixed vulnerabilities represent 349,000+ active installations.

Facts & Graphs

Improper Access Control was clearly the biggest issue we found among those vulnerabilities. Each time, the developers didn’t check the user capability which always lead to devastating consequences: an unauthenticated user can change the WordPress core options, import the plugin/theme settings, create admin accounts or redirect the blog to a malicious website.

Vulnerable Entry Points

It is not a big surprise that the entry point is the WordPress API because it handles authentication, capabilities and roles, security nonces and all the things that are required to restrict access to the CMS. I stress that the problem is not the WordPress API, but the way it is misused by developers.

WordPress API Entry Points

Both the AJAX API and the admin_init hook were the most misused by developers.

Avoidable or Unavoidable?

Let’s see how many vulnerabilities could have been avoided if the developers took only from 30 to 60 seconds of their time to read the online WordPress API documentation of the function or hook they misused in their code:

68% of all reported vulnerabilities (52 out of 77) could have been avoided.
For instance, here’s the documentation of the admin_init hook:

Fires as an admin screen or script is being initialized.
Note, this does not just run on user-facing admin screens. It runs on admin-ajax.php and admin-post.php as well.
This is roughly analogous to the more general ‘init’ hook, which fires earlier.

As we can see, it takes a few seconds to read and understand that this hook can be triggered by any user, logged-in or not, and thus it’s important to check that the user accessing it has the right capability.


If you’re a developer of themes or plugins for WordPress, here’s a non-exhaustive list of recommendations:

  • Make sure to always ask yourself the following question, whenever you start coding a new function/method or class: Who should be allowed to access it?
  • Make sure the user has the right capability.
  • Add security nonces to protect against CSRF attacks (don’t use them for authentication, it’s not their job).
  • Validate all user input. WordPress has a lot of data sanitization functions, maybe a bit too many as I’ve seen several developers very confused about which one they should use, or using the wrong one. If that happened to you, know that the good old PHP htmlspecialchars and htmlentities will often do a great job. The strip_tags and filter_var functions come in handy too.
  • Don’t try to manage file uploads yourself: use the WordPress API instead, it has functions to safely handle that.
  • Use prepare for your SQL queries to prevent SQL injection attacks.

Note that simply following those 6 points would have avoided 100% of the above vulnerabilities.