Update (2022-02-26): the tool is now public: https://github.com/kazet/wpgarlic

WordPress plugins expose a number of interfaces, such as:

  • AJAX endpoints (/wp-admin/admin-ajax.php)
  • Admin menu pages (/wp-admin/admin.php?page=...)
  • PHP files (in the /wp-content/plugins/ directory),
  • Shortcodes
  • REST routes (/wp-json/...).

These interfaces have a consistent trust boundary: we know where the untrusted input goes and can detect what operations are executed on that input.

For instance, if you visit a .php file, provide appropriate parameters, and cause a file to be removed, you know that it is a vulnerability. You know what parameters you control and what ones you don’t – for example, you may redirect a logged-in admin to an admin menu page with arbitrary GET parameters, but you don’t control their cookies.

Therefore it is possible to semi-automatically scan for multiple classes of vulnerabilities in all WordPress plugins.

I have written a tool that:

  • executes each AJAX endpoint, menu page, REST route, or file multiple times,
  • injects payloads into the GET, POST, etc. arrays or REST parameters (more on how it’s done in the next section),
  • analyses the outputs with an ugly pile of regular expressions1 to detect:
    • calls to WordPress functions (such as wp_delete_post),
    • crashes (“No such file or directory”, “You have an error in your SQL syntax”, …),
    • XSS (echoing a known payload containing " or <),
    • etc.

This method is transferable to other CMS plugin ecosystems but not directly e.g. to Python packages. If a Python package allows you to remove arbitrary files, it may or may not be a vulnerability depending on the package role and your particular setup.

Injecting parameters

In PHP, the _GET, _POST, _SERVER, _COOKIE, and _REQUEST arrays contain various request parameters (e.g. GET and POST data, cookies, server configuration, and headers). I have replaced them with mock objects that allow access to any key - and with defined probability return a payload from a predefined payload list.

A simple mock $_POST array could be created using the following code:

<?php

class Mock implements ArrayAccess {
    function offsetGet($offset) {
        return "payload";
    }

    function offsetExists($offset) {
        return true;
    }

    function offsetSet($offset, $value) { }

    function offsetUnset($offset) { }
}

$_POST = new Mock();

echo $_POST["parameter_name"];

The above snippet will print payload.

Let’s assume that the $_REQUEST array has been mocked in a way similar to the one described above and that an AJAX route is handled by the following function:

public function delete_saved_block() {
	$block_id = (int) sanitize_text_field($_REQUEST['block_id']);
	$deleted_block = wp_delete_post($block_id);
	wp_send_json_success($deleted_block);
}

When $_REQUEST['block_id'] gets accessed, the mock will return a payload, thus allowing to detect that wp_delete_post was called on an attacker-controlled value.

This approach allowed to easily inject payloads even if the parameter name was hard to guess – the tool didn’t distinguish between id and secret_parameter_65e3c14a1d.

Some of the keys needed to be excluded manually (for example $_SERVER['HTTP_AUTHORIZATION'] or $_GET['doing_wp_cron']) because their values were handled by WordPress, and providing them caused plugin code to not be reached.

Besides, with some probability, a random type of array was returned instead of a string payload:

  • a singleton array with a string payload,
  • recursively, an object that allows access to any key,
  • a singleton array: random payload → random payload.

Detecting vulnerabilities

The tool contained checks to detect:

  • various kinds of crashes,
  • potentially dangerous operations,
  • information leaks.

Some of these checks led to a large number of CVEs (such as the XSS checks), some didn’t (e.g. the checks for syntax errors designed to catch eval() on untrusted code).

XSS

To detect XSS, checks were implemented that detected payloads being echoed back (or echoed back with escaping that didn’t prevent XSS, such as prefixing " with \).

Crashes

The following types of crashes were detected:

  • fopen() / file_get_contents() / require() / require_once() / include() / include_once() errors and “No such file or directory” or “failed to open stream” error messages,
  • unlink() error messages,
  • crashes related to call_user_func(),
  • SQL error messages,
  • unserialize() errors,
  • parse / syntax errors to detect eval() calls,
  • “command not found” error message,
  • simplexml_load_string() error messages2.

Information leaks

The output was analysed to observe whether known user e-mails or file names are displayed.

WordPress operations

WordPress has been instrumented to detect:

  • calls to maybe_unserialize,
  • calls to update_option/update_site_option/delete_option,
  • calls to wp_insert_user,
  • calls to wp_insert_post/wp_update_post/wp_delete_post,
  • calls to wp_mail,
  • calls to query (this one yielded an especially large number of false positives that needed additional filtering),
  • calls to get_users (this one has been added after accidentally discovering CVE-2021-25110 where an attacker can leak arbitrary user e-mails via a crafted user search query).

Additional checks

After fuzzing, the admin panel, the homepage, and the post pages were crawled to find occurrences of known payloads. That allowed for instance to detect CVE-2021-24975 in social-networks-auto-poster-facebook-twitter-g.

Update (2022-02-26): additionally, any attempts to access uploaded files are logged, so that they may be checked manually.

Changes to PHP

Patched equality

I have patched PHP so that equality comparison between any value and a known payload returned true with 1/3 probability. Forgive me about this one.

With this patch, I was able to detect vulnerabilities such as:

if ($_GET['action'] == 'please-remove-post') {
    wp_delete_post($_GET['id']);
}

Unfortunately, this resulted in a large number of false positives as well. The false positives were e.g. in the form of:

if (in_array($order, array("ASC", "DESC"), true)) {
    query("(...) ORDER BY $order");
}

The only solution for this problem I have used was browsing through these false positives and cursing. Further research can lead to coming up with other solutions.

Other changes

Besides, I have patched the PHP interpreter so that:

  • When base64_decode was performed on a known payload, this payload was returned again,
  • When json_decode was performed on a known payload, an object was returned that returns payloads when any key was accessed. These were the same objects that served as e.g. $_GET arrays,
  • when a redirect was performed, relevant information was displayed so that Open Redirect vulnerabilities could be detected.

Testing

A test-driven approach was critical during development. Tests checked that the tool would find a known vulnerability. For example, I could write a test to check that:

when fuzzing the wp_ajax_heateor_sss_import_config endpoint of the sassy-social-share plugin in version 3.3.23, the tool should detect that maybe_unserialize() gets called on an attacker-controlled payload.

False positives vs false negatives

This approach yielded a large number of false positives. It was a deliberate decision because I wanted to sort through multiple reports instead of missing vulnerabilities.

An alternative could be to write additional filtering logic. For example, there were multiple reports where an HTML payload was echoed back – but when checking them, I’ve observed that a correct JSON Content-Type header is added. This was one of the cases that could be checked automatically.

Other

Fuzzing was performed inside Docker containers, re-created for every plugin.

It was important to disconnect the network, because a lot of plugins call other web services, and I wanted to avoid sending random payloads there.

I found it also helpful to separate plugin fuzzing and analysis of the outputs. Because the outputs were analyzed by a lot of regular expressions, bugs happened. Therefore a relatively quick rescan allowed to speed up development.

Automating the fuzzing Added: 2022-02-16

Scanning thousands of plugins would not be possible without automating the job. Fortunately, WordPress plugins use consistent interfaces to integrate with WordPress, for example:

  • all REST routes are collected in a central registry, accessible via: rest_get_server()->get_routes(),
  • AJAX actions are created by adding a hook with a name starting with wp_ajax_,
  • there exists one registry with all admin menu pages.

Therefore all REST routes, AJAX actions, and menu actions can be enumerated in the same way regardless of which plugin is scanned. Of course, all PHP files can be easily listed as well.

All plugins can be installed in the same way: I have used WP-CLI – a tool that allows to install, activate, deactivate or delete a plugin from the command-line. The list of plugins could be downloaded automatically from the WordPress plugin registry API.

All of the above techniques made it possible to create a tool that doesn’t require any plugin-specific code.

Results Last updated: 2024-08-25

Because of time constraints, I have focused only on the most popular plugins. As of this moment, the following bugs found by the tool have already been fixed and published:

ID Plugin CVE Number of active installations Type Link
1 litespeed-cache CVE-2024-3246 5,000,000 CSRF stored XSS Wordfence
2 woocommerce CVE-2022-0775 5,000,000 Arbitrary comment deletion WPScan
3 all-in-one-seo CVE-2024-3554 3,000,000 Contributor+ Stored XSS Wordfence
4 updraftplus CVE-2021-25022 3,000,000 Reflected XSS WPScan
5 complianz-gdpr CVE-2024-1592 800,000 CSRF deletion of “do not sell my personal data” requests Wordfence
6 the-events-calendar CVE-2023-6203 700,000 Password-protected post read WPScan
7 code-snippets CVE-2021-25008 500,000 Reflected XSS WPScan
8 woocommerce-pdf-invoices-packing-slips CVE-2021-24991 300,000 Reflected XSS WPScan
9 woocommerce-pdf-invoices-packing-slips CVE-2022-2537 300,000 Reflected XSS WPScan
10 ad-inserter CVE-2022-0288 200,000 Reflected XSS WPScan
11 caldera-forms CVE-2022-0879 200,000 Reflected XSS WPScan
12 complianz-gdpr CVE-2022-0193 200,000 Reflected XSS WPScan
13 custom-facebook-feed CVE-2021-25065 200,000 Reflected XSS WPScan
14 favicon-by-realfavicongenerator CVE-2022-0471 200,000 Reflected XSS WPScan
15 gotmls CVE-2022-2599 200,000 Reflected XSS WPScan
16 loginpress CVE-2022-0347 200,000 Reflected XSS WPScan
17 popup-builder CVE-2022-0479 200,000 Reflected XSS WPScan
18 royal-elementor-addons CVE-2023-5922 200,000 Arbitrary post read (including drafts and password-protected posts) WPScan
19 templately CVE-2023-5454 200,000 Arbitrary post trashing WPScan
20 use-any-font CVE-2021-24977 200,000 Arbitrary CSS append + stored XSS WPScan
21 white-label-cms CVE-2022-0422 200,000 Reflected XSS WPScan
22 white-label-cms CVE-2024-4280 200,000 Unauthorized plugin settings reset Wordfence
23 wp-cerber CVE-2022-0429 200,000 Stored XSS WPScan
24 wp-gdpr-compliance CVE-2022-0147 200,000 Reflected XSS WPScan
25 bdthemes-element-pack-lite CVE-2024-2966 100,000 Password-protected post read Wordfence
26 capability-manager-enhanced CVE-2021-25032 100,000 Arbitrary settings update WPScan
27 chaty CVE-2021-25016 100,000 Reflected XSS WPScan
28 cmp-coming-soon-maintenance CVE-2022-0188 100,000 Possibility to add arbitrary CSS WPScan
29 download-manager CVE-2021-24969 100,000 Stored XSS WPScan
30 download-manager CVE-2021-25069 100,000 Reflected XSS WPScan
31 email-subscribers CVE-2022-0439 100,000 Blind SQL Injection WPScan
32 email-subscribers CVE-2022-3981 100,000 Blind SQL Injection WPScan
33 intelly-related-posts CVE-2023-6257 100,000 Password-protected post read WPScan
34 iubenda-cookie-law-solution CVE-2022-3911 100,000 Privilege escalation WPScan
35 learnpress CVE-2022-0271 100,000 Reflected XSS WPScan
36 menu-image CVE-2022-0450 100,000 Stored XSS WPScan
37 modern-events-calendar-lite CVE-2021-24925 100,000 Reflected XSS WPScan
38 modern-events-calendar-lite CVE-2021-24946 100,000 Blind SQL injection WPScan
39 modern-events-calendar-lite CVE-2021-25046 100,000 Stored XSS WPScan
40 mystickymenu CVE-2023-5509 100,000 Missing authorization WPScan
41 paid-memberships-pro CVE-2021-25114 100,000 Blind SQL Injection WPScan
42 relevanssi CVE-2023-7199 100,000 Draft post read WPScan
43 relevanssi CVE-2024-1380 100,000 Downloading full search history Wordfence
44 seo-simple-pack CVE-2024-2795 100,000 Password-protected post read Wordfence
45 squirrly-seo CVE-2021-25019 100,000 Reflected XSS WPScan
46 ti-woocommerce-wishlist CVE-2022-0412 100,000 Blind SQL Injection WPScan
47 vk-all-in-one-expansion-unit CVE-2024-2093 100,000 Password-protected post read Wordfence
48 webp-converter-for-media CVE-2021-25074 100,000 Open redirect WPScan
49 woocommerce-mercadopago CVE-2024-3934 100,000 Downloading arbitrary file (including wp-config.php) Wordfence
50 woocommerce-products-filter CVE-2021-25085 100,000 Reflected XSS WPScan
51 wpvivid-backuprestore CVE-2021-24994 100,000 Stored XSS WPScan
52 wpvivid-backuprestore CVE-2022-0531 100,000 Reflected XSS WPScan
53 advanced-cf7-db CVE-2021-24905 90,000 Arbitrary file removal WPScan
54 kingcomposer CVE-2021-25048 90,000 Stored XSS WPScan
55 kingcomposer CVE-2022-0165 90,000 Open redirect WPScan
56 masterslider CVE-2024-4375 90,000 Contributor+ Stored XSS Wordfence
57 social-networks-auto-poster-facebook-twitter-g CVE-2021-24975 90,000 Stored XSS WPScan
58 social-networks-auto-poster-facebook-twitter-g CVE-2021-25072 90,000 CSRF post removal WPScan
59 tenweb-speed-optimizer CVE-2023-5559 90,000 DoS WPScan
60 embedpress CVE-2023-5749 80,000 Reflected XSS WPScan
61 official-mailerlite-sign-up-forms CVE-2024-2797 80,000 Unauthorized settings change, allowing contributors to add and modify forms Wordfence
62 themify-portfolio-post CVE-2022-0200 80,000 Reflected XSS (logged-in POST 3) WPScan
63 woo-product-feed-pro CVE-2021-24974 80,000 Stored XSS WPScan
64 woo-product-feed-pro CVE-2022-0426 80,000 Reflected XSS (logged-in POST 3) WPScan
65 wp-google-map-plugin CVE-2024-2386 80,000 Contributor+ SQL Injection Wordfence
66 wp-hide-security-enhancer CVE-2022-2538 80,000 Reflected XSS WPScan
67 boldgrid-easy-seo CVE-2024-2950 70,000 Password-protected post read Wordfence
68 feed-them-social CVE-2022-2532 70,000 Reflected XSS WPScan
69 media-library-assistant CVE-2024-5605 70,000 Contributor+ SQL Injection Wordfence
70 stream CVE-2022-4384 70,000 Obtaining information about all users’ activity in the site WPScan
71 www-xml-sitemap-generator-org CVE-2022-0346 70,000 Reflected XSS and RCE WPScan
72 yith-woocommerce-ajax-search CVE-2024-4455 70,000 Unauthenticated Stored XSS Wordfence
73 blog2social CVE-2024-3678 60,000 Password-protected post read Wordfence
74 booking CVE-2021-25040 60,000 Reflected XSS WPScan
75 contact-form-entries CVE-2024-2030. 60,000 Contributor+ stored XSS Wordfence
76 customer-reviews-woocommerce CVE-2024-3731 60,000 Reflected XSS Wordfence
77 interactive-3d-flipbook-powered-physics-engine CVE-2022-0423 60,000 Stored XSS WPScan
78 mappress-google-maps-for-wordpress CVE-2022-0208 60,000 Reflected XSS WPScan
79 permalink-manager CVE-2022-0201 60,000 Reflected XSS WPScan
80 post-grid CVE-2022-0447 60,000 Reflected XSS (logged-in POST 3) WPScan
81 powerpack-lite-for-elementor CVE-2021-25027 60,000 Reflected XSS WPScan
82 print-invoices-packing-slip-labels-for-woocommerce CVE-2024-3216 60,000 Unauthorized plugin settings reset - removing invoicing configuration Wordfence
83 real-cookie-banner CVE-2022-0445 60,000 CSRF settings reset and deleting all GDPR consents WPScan
84 visual-portfolio CVE-2022-2543 60,000 Arbitrary CSS injection WPScan
85 visual-portfolio CVE-2022-2597 60,000 Arbitrary CSS injection WPScan
86 wd-instagram-feed CVE-2021-25047 60,000 Reflected XSS WPScan
87 woocommerce-currency-switcher CVE-2021-25043 60,000 Reflected XSS WPScan
88 woocommerce-currency-switcher CVE-2022-0234 60,000 Reflected XSS WPScan
89 wp-letsencrypt-ssl CVE-2023-7046 60,000 Exposed private keys Wordfence
90 wp-responsive-menu CVE-2021-24971 60,000 Stored XSS WPScan
91 wp-rss-aggregator CVE-2021-24988 60,000 Stored XSS WPScan
92 wp-rss-aggregator CVE-2022-0189 60,000 Reflected XSS (logged-in POST 3) WPScan
93 ditty-news-ticker CVE-2022-0533 50,000 Reflected XSS WPScan
94 easy-digital-downloads CVE-2022-2389 50,000 CSRF posts deletion WPScan
95 event-tickets CVE-2021-25028 50,000 Open redirect WPScan
96 getwid CVE-2023-6042 50,000 Sending arbitrary e-mails to the admin WPScan
97 nimble-builder CVE-2022-0314 50,000 Reflected XSS WPScan
98 post-grid CVE-2024-0881 50,000 Password-protected post read WPScan
99 simple-membership CVE-2022-0328 50,000 CSRF member deletion WPScan
100 social-networks-auto-poster-facebook-twitter-g CVE-2024-1446 50,000 CSRF post deletion Wordfence
101 social-pug CVE-2024-1526 50,000 Password-protected post read WPScan
102 super-socializer CVE-2021-24987 50,000 Reflected XSS WPScan
103 bnfw CVE-2022-0345 40,000 E-mail leak WPScan
104 theme: total CVE-2024-1771 40,000 Unauthorized settings change Wordfence
105 thirstyaffiliates CVE-2022-0398 40,000 Arbitrary affiliate link creation WPScan
106 tutor CVE-2021-25017 40,000 Reflected XSS WPScan
107 ultimate-responsive-image-slider CVE-2023-6077 40,000 Password-protected post read WPScan
108 wp-video-lightbox CVE-2024-4324 40,000 Contributor+ Stored XSS Wordfence
109 advanced-cron-manager CVE-2021-25084 30,000 Arbitrary cron configuration change WPScan
110 ai-assistant-by-10web CVE-2023-6985 30,000 Arbitrary plugin installation Wordfence
111 ays-popup-box CVE-2024-3897 30,000 Obtaining all users’ e-mails Wordfence
112 betterdocs CVE-2024-2845 30,000 Contributor+ Stored XSS Wordfence
113 block-options CVE-2024-2794 30,000 Contributor+ Stored XSS Wordfence
114 contact-form-7-skins CVE-2021-25063 30,000 Reflected XSS WPScan
115 content-egg CVE-2022-0428 30,000 Reflected XSS (logged-in POST 3) WPScan
116 download-plugins-dashboard CVE-2024-7501 30,000 CSRF download of all files Wordfence
117 easy-paypal-donation CVE-2021-24989 30,000 CSRF post removal WPScan
118 futurio-extra CVE-2021-25110 30,000 E-mail leak WPScan
119 google-pagespeed-insights CVE-2022-0431 30,000 Reflected XSS (logged-in POST 3) WPScan
120 html5-video-player CVE-2023-6485 30,000 Stored XSS WPScan
121 insight-core CVE-2021-24950 30,000 Stored XSS + object injection WPScan
122 lead-form-builder CVE-2021-24967 30,000 Stored XSS WPScan
123 master-addons CVE-2022-0327 30,000 Reflected XSS WPScan
124 meks-easy-instagram-widget CVE-2021-24958 30,000 Stored XSS WPScan
125 mp-timetable CVE-2024-3342 30,000 Contributor+ Blind SQL injection Wordfence
126 my-calendar CVE-2021-24927 30,000 Reflected XSS WPScan
127 notificationx CVE-2022-0349 30,000 Blind SQL Injection WPScan
128 notificationx CVE-2024-1698 30,000 Blind SQL injection Wordfence
129 photo-gallery CVE-2022-0169 30,000 SQL Injection WPScan
130 protect-wp-admin CVE-2021-24906 30,000 Disabling of plugin security features WPScan
131 pz-linkcard CVE-2021-25012 30,000 Reflected XSS WPScan
132 seriously-simple-podcasting CVE-2023-6444 30,000 Admin e-mail leak WPScan
133 simple-social-buttons CVE-2023-5845 30,000 Password-protected post read WPScan
134 simply-schedule-appointments CVE-2024-1760 30,000 CSRF removing of all plugin data (appointments etc) Wordfence
135 simply-schedule-appointments CVE-2024-2341 30,000 Contributor+ SQL Injection Wordfence
136 simply-schedule-appointments CVE-2024-2342 30,000 SQL injection Wordfence
137 simply-schedule-appointments CVE-2024-4288 30,000 Contributor+ Stored XSS Wordfence
138 site-reviews CVE-2021-24973 30,000 Stored XSS WPScan
139 social-warfare CVE-2024-1959 30,000 Contributor+ stored XSS Wordfence
140 theme: responsive CVE-2024-2848 30,000 Injecting any HTML (without scripts) to the footer Wordfence
141 ultimate-faqs CVE-2021-24968 30,000 Possibility to add arbitrary FAQs WPScan
142 video-conferencing-with-zoom-api CVE-2022-0384 30,000 E-mail leak WPScan
143 visualizer CVE-2024-3750 30,000 Downloading arbitrary data from the database Wordfence
144 woo-smart-wishlist CVE-2022-0397 30,000 Reflected XSS (logged-in POST 3) WPScan
145 wp-user-frontend CVE-2021-25076 30,000 SQL injection in admin panel leading to reflected XSS WPScan
146 xcloner-backup-and-restore CVE-2022-0444 30,000 Resetting settings, including encryption key WPScan
147 ad-invalid-click-protector CVE-2022-0190 20,000 SQL injection WPScan
148 ad-invalid-click-protector CVE-2022-0191 20,000 CSRF ban removal WPScan
149 advanced-product-labels-for-woocommerce CVE-2022-0399 20,000 Reflected XSS (logged-in POST 3) WPScan
150 asgaros-forum CVE-2022-0411 20,000 Blind SQL Injection WPScan
151 bwp-google-xml-sitemaps CVE-2022-0230 20,000 Stored XSS WPScan
152 crazy-bone CVE-2022-0385 20,000 Stored XSS WPScan
153 custom-post-widget CVE-2024-3564 20,000 Contributor+ LFI Wordfence
154 easy-appointments CVE-2024-2842 20,000 Contributor+ Stored XSS Wordfence
155 easy-testimonials CVE-2024-2337 20,000 Contributor+ Stored XSS Wordfence
156 ecwid-shopping-cart CVE-2023-6292 20,000 Unauthorized settings change WPScan
157 ecwid-shopping-cart CVE-2024-2456 20,000 Contributor+ Stored XSS Wordfence
158 embed-form CVE-2024-2542 20,000 Contributor+ Stored XSS Wordfence
159 enhanced-e-commerce-for-woocommerce-store CVE-2024-1203 20,000 Blind SQL Injection (at least one woocommerce product must exist) Wordfence
160 event-calendar-wd CVE-2021-25024 20,000 XSS WPScan
161 event-calendar-wd CVE-2021-25025 20,000 Possibility to add arbitrary events WPScan
162 favorites CVE-2024-2948 20,000 Contributor+ Stored XSS Wordfence
163 float-menu CVE-2022-0313 20,000 CSRF menu deletion WPScan
164 gmap-embed CVE-2021-25011 20,000 Arbitrary post removal, plugin settings update WPScan
165 gmap-embed CVE-2021-25081 20,000 Arbitrary post removal, plugin settings update via CSRF WPScan
166 image-hover-effects-ultimate CVE-2021-25031 20,000 Reflected XSS WPScan
167 leadconnector CVE-2024-1371 20,000 Post removal Wordfence
168 material-design-for-contact-form-7 CVE-2022-0404 20,000 DoS WPScan
169 miniorange-2-factor-authentication CVE-2022-0229 20,000 DoS WPScan
170 mycred CVE-2021-25015 20,000 Reflected XSS WPScan
171 mycred CVE-2022-0287 20,000 E-mail leak WPScan
172 mycred CVE-2022-0363 20,000 Arbitrary post creation WPScan
173 mystickyelements CVE-2022-0148 20,000 Reflected XSS WPScan
174 navz-photo-gallery CVE-2021-24909 20,000 Reflected XSS WPScan
175 newstatpress CVE-2022-0206 20,000 Reflected XSS WPScan
176 page-views-count CVE-2022-0434 20,000 SQL injection WPScan
177 quiz-maker CVE-2023-6155 20,000 Unauthorized obtaining of all users’ emails WPScan
178 related-posts-for-wp CVE-2024-0592 20,000 Draft and password-protected post read Wordfence
179 restaurant-reservations CVE-2021-24965 20,000 Stored XSS WPScan
180 shapepress-dsgvo CVE-2024-3201 20,000 Contributor+ Stored XSS Wordfence
181 sharethis-share-buttons CVE-2024-3648 20,000 Contributor+ Stored XSS Wordfence
182 simple-facebook-plugin CVE-2024-3583 20,000 Contributor+ Stored XSS Wordfence
183 simple-job-board CVE-2024-0593 20,000 Draft and password-protected post read Wordfence
184 smartcrawl-seo CVE-2023-5949 20,000 Password-protected post read WPScan
185 smartcrawl-seo CVE-2024-3287 20,000 Adding arbitrary data to the ld+json description Wordfence
186 usc-e-shop CVE-2023-5952 20,000 Object injection WPScan
187 video-conferencing-with-zoom-api CVE-2024-2033 20,000 Leak of all users’ e-mails Wordfence
188 video-conferencing-with-zoom-api CVE-2024-2031 20,000 Contributor+ stored XSS Wordfence
189 website-article-monetization-by-magenet CVE-2024-1379 20,000 Stored XSS Wordfence
190 woo-product-slider CVE-2022-2382 20,000 DoS WPScan
191 woocommerce-product-addon CVE-2021-25018 20,000 Stored XSS WPScan
192 wp-accessiblity-helper CVE-2022-0150 20,000 Reflected XSS WPScan
193 wp-ecommerce-paypal CVE-2024-1719 20,000 CSRF Wordfence
194 wp-event-manager CVE-2024-2691 20,000 Contributor+ Stored XSS Wordfence
195 wp-file-upload CVE-2024-2847 20,000 Contributor+ Stored XSS Wordfence
196 wp-meta-seo CVE-2023-6962 20,000 Password-protected post read Wordfence
197 wp-meta-seo CVE-2023-6961 20,000 Stored XSS Wordfence
198 wp-social CVE-2024-1763 20,000 Arbitrary login provider disabling Wordfence
199 wp-stats-manager CVE-2021-24750 20,000 SQL injection WPScan
200 wp-stats-manager CVE-2021-25042 20,000 Stored XSS WPScan
201 wp-stats-manager CVE-2022-0410 20,000 Blind SQL Injection WPScan
202 wp-useronline CVE-2023-5560 20,000 Stored XSS WPScan
203 wpforo CVE-2024-3200 20,000 Contributor+ Blind SQL injection Wordfence
204 wplegalpages CVE-2021-25106 20,000 Stored XSS WPScan
205 addons-for-visual-composer CVE-2024-2079 10,000 Contributor+ stored XSS Wordfence
206 advanced-form-integration-log CVE-2024-2387 10,000 Reflected XSS Wordfence
207 advanced-page-visit-counter CVE-2021-24957 10,000 Blind SQL injection WPScan
208 advanced-page-visit-counter CVE-2021-25086 10,000 Stored XSS WPScan
209 advanced-post-blocks CVE-2024-0908 10,000 Password-protected post read Wordfence
210 affiliates-manager CVE-2021-25078 10,000 Stored XSS WPScan
211 akismet-privacy-policies CVE-2021-25071 10,000 Reflected XSS WPScan
212 ari-fancy-lightbox CVE-2022-0161 10,000 Reflected XSS WPScan
213 awesome-support CVE-2023-5352 10,000 Arbitrary post content edit and removal WPScan
214 awesome-support CVE-2024-0594 10,000 SQL Injection Wordfence
215 awesome-support CVE-2024-0595 10,000 User e-mail leak Wordfence
216 awesome-support CVE-2024-0596 10,000 Password-protected and draft post read Wordfence
217 ba-book-everything CVE-2024-3672 10,000 Contributor+ Stored XSS Wordfence
218 booster-extension CVE-2024-2109 10,000 Leak of all users’ e-mails Wordfence
219 buddypress-media CVE-2023-5931 10,000 RCE WPScan
220 buddypress-media CVE-2024-3293 10,000 Contributor+ Blind SQL injection Wordfence
221 business-directory-plugin CVE-2024-4443 10,000 Unauthenticated blind SQL Injection Wordfence
222 business-profile CVE-2021-25060 10,000 Stored XSS WPScan
223 cardoza-facebook-like-box CVE-2024-5224 10,000 Contributor+ Stored XSS Wordfence
224 coming-soon-page CVE-2022-0164 10,000 Sending any e-mail to all subscribers WPScan
225 coming-soon-page CVE-2022-0199 10,000 Sending any e-mail to all subscribers via CSRF WPScan
226 content-protector CVE-2024-2026 10,000 Contributor+ stored XSS Wordfence
227 conveythis-translate CVE-2023-6811 10,000 Stored XSS Wordfence
228 custom-registration-form-builder-with-submission-manager CVE-2024-1990 10,000 Contributor+ blind SQL injection Wordfence
229 custom-registration-form-builder-with-submission-manager CVE-2024-1991 10,000 Promoting any user to administrator Wordfence
230 customer-area CVE-2023-6824 10,000 Obtaining other user’s address WPScan
231 customer-area CVE- 2023-6741 10,000 Changing other user’s address WPScan
232 customer-area CVE-2024-0665 10,000 Reflected XSS Wordfence
233 demomentsomtres-wp-export CVE-2023-5905 10,000 Unauthorized data export (including user e-mails, post drafts, private posts) WPScan
234 directorist CVE-2022-2376 10,000 E-mail leak WPScan
235 directorist CVE-2022-2377 10,000 Sending arbitrary e-mails WPScan
236 download-attachments CVE-2024-3230 10,000 Contributor+ Stored XSS Wordfence
237 dropdown-menu-widget CVE-2021-25113 10,000 Stored XSS WPScan
238 duplicate-page-or-post CVE-2021-25075 10,000 Stored XSS WPScan
239 easy-custom-auto-excerpt CVE-2024-3312 10,000 Password-protected post read Wordfence
240 easy-pricing-tables CVE-2021-25098 10,000 CSRF post removal WPScan
241 ecommerce-product-catalog CVE-2023-5979 10,000 CSRF all product removal WPScan
242 english-wp-admin CVE-2021-25111 10,000 Open redirect WPScan
243 enjoy-instagram-instagram-responsive-images-gallery-and-carousel CVE-2024-0779 10,000 User account deletion WPScan
244 eroom-zoom-meetings-webinar_ CVE-2024-3275 10,000 Draft post read Wordfence
245 essential-real-estate CVE-2023-6139 10,000 DoS WPScan
246 essential-real-estate CVE-2023-6141 10,000 Stored XSS WPScan
247 essential-real-estate CVE-2024-4273 10,000 Contributor+ Stored XSS Wordfence
248 feedwordpress CVE-2024-0839 10,000 Draft post read Wordfence
249 gamipress CVE-2024-1799 10,000 Contributor+ blind SQL injection Wordfence
250 gamipress CVE-2024-2783 10,000 Contributor+ Stored XSS Wordfence
251 geodirectory CVE-2024-3732 10,000 Contributor+ Stored XSS Wordfence
252 ibtana-visual-editor CVE-2021-25014 10,000 Stored XSS WPScan
253 ip2location-country-blocker CVE-2021-25095 10,000 Banning arbitrary countries WPScan
254 ip2location-country-blocker CVE-2021-25096 10,000 Ban circumvention WPScan
255 ip2location-country-blocker CVE-2021-25108 10,000 Banning countries via CSRF WPScan
256 job-postings CVE-2024-2833 10,000 Reflected XSS Wordfence
257 leaflet-maps-marker CVE-2024-3670 10,000 Contributor+ Stored XSS Wordfence
258 link-library CVE-2021-25091 10,000 Reflected XSS WPScan
259 link-library CVE-2021-25092 10,000 CSRF settings reset WPScan
260 link-library CVE-2021-25093 10,000 Arbitrary link removal WPScan
261 link-library CVE-2024-1559 10,000 Stored XSS Wordfence
262 link-library CVE-2024-2325 10,000 Reflected XSS Wordfence
263 link-library CVE-2024-4281 10,000 Contributor+ Stored XSS Wordfence
264 login-logout-register-menu CVE-2024-3726 10,000 Contributor+ Stored XSS Wordfence
265 masterstudy-lms-learning-management-system CVE-2024-1904 10,000 Draft and password-protected post read Wordfence
266 meow-gallery CVE-2024-4386 10,000 Contributor+ Stored XSS Wordfence
267 modal-window CVE-2021-25051 10,000 CSRF RCE WPScan
268 motopress-hotel-booking-lite CVE-2023-5991 10,000 Arbitrary file download and removal WPScan
269 opengraph CVE-2024-5615 10,000 Password-protected post read Wordfence
270 osm CVE-2024-3603 10,000 Contributor+ Stored XSS Wordfence
271 osm CVE-2024-3604 10,000 Contributor+ SQL Injection Wordfence
272 page-builder-add CVE-2021-25067 10,000 Reflected XSS WPScan
273 page-builder-sandwich CVE-2024-1285 10,000 Arbitrary post content change Wordfence
274 page-builder-sandwich CVE-2024-1381 10,000 Downloading arbitrary data from the database Wordfence
275 pearl-header-builder CVE-2024-4000 10,000 Contributor+ Stored XSS Wordfence
276 portfolio-wp CVE-2021-25090 10,000 Stored XSS WPScan
277 powerpack-addon-for-beaver-builder CVE-2022-0176 10,000 Reflected XSS WPScan
278 print-o-matic CVE-2024-3671 10,000 Contributor+ Stored XSS Wordfence
279 qubely CVE-2021-25013 10,000 Arbitrary post removal WPScan
280 rearrange-woocommerce-products CVE-2021-24928 10,000 SQL injection WPScan
281 registrations-for-the-events-calendar CVE-2021-24943 10,000 SQL injection WPScan
282 registrations-for-the-events-calendar CVE-2021-25083 10,000 Reflected XSS WPScan
283 secure-copy-content-protection CVE-2021-24931 10,000 SQL injection WPScan
284 send-pdf-for-contact-form-7 CVE-2024-3585 10,000 Contact form data download Wordfence
285 seraphinite-accelerator CVE-2023-5609 10,000 Reflected XSS WPScan
286 simple-basic-contact-form CVE-2024-4150 10,000 Reflected XSS Wordfence
287 smart-forms CVE-2022-0163 10,000 Downloading form data WPScan
288 spider-event-calendar CVE-2022-0212 10,000 Reflected XSS WPScan
289 ssl-zen CVE-2024-1076 10,000 SSL keys exposure WPScan
290 stopbadbots CVE-2021-25070 10,000 Blind SQL injection WPScan
291 swift-performance-lite CVE-2023-6289 10,000 Unauthorized configuration export WPScan
292 theme: graphene CVE-2024-1984 10,000 Password-protected post read Wordfence
293 theme: newsmatic CVE-2024-1587 10,000 Draft post read Wordfence
294 themify-shortcodes CVE-2024-2732 10,000 Contributor+ Stored XSS Wordfence
295 ultimate-product-catalogue CVE-2021-24993 10,000 Possibility to add arbitrary products WPScan
296 wa-sticky-buttons CVE-2022-2375 10,000 Stored XSS WPScan
297 wassup CVE-2023-5653 10,000 Stored XSS WPScan
298 webpushr-web-push-notifications CVE-2023-5620 10,000 Stored XSS WPScan
299 whmcs-bridge CVE-2021-25112 10,000 Reflected XSS WPScan
300 wicked-folders CVE-2021-24919 10,000 SQL injection WPScan
301 woo-orders-tracking CVE-2021-25062 10,000 Reflected XSS WPScan
302 woocommerce-exporter CVE-2022-0149 10,000 Reflected XSS WPScan
303 woocommerce-store-toolkit CVE-2021-25077 10,000 Reflected XSS WPScan
304 woostify-sites-library CVE-2023-6279 10,000 DoS WPScan
305 word-balloon CVE-2023-5884 10,000 CSRF avatar removal WPScan
306 wp-booking-system CVE-2021-25061 10,000 Reflected XSS WPScan
307 wp-coder CVE-2021-25053 10,000 CSRF RCE WPScan
308 wp-coder CVE-2022-2388 10,000 CSRF code deletion WPScan
309 wp-custom-widget-area CVE-2023-6066 10,000 Missing authorization WPScan
310 wp-marketing-automation CVE-2022-2387 10,000 Adding automations WPScan
311 wp-photo-album-plus CVE-2021-25115 10,000 Stored XSS WPScan
312 wp-popup-builder CVE-2022-2404 10,000 Reflected XSS WPScan
313 wp-popup-builder CVE-2022-2405 10,000 Arbitrary popup deletion WPScan
314 wp-product-feed-manager CVE-2024-3067 10,000 Reflected XSS Wordfence
315 wp125 CVE-2021-25073 10,000 CSRF ad deletion WPScan
316 wpcargo CVE-2021-25003 10,000 RCE WPScan
317 wpvr CVE-2023-6529 10,000 Plugin downgrade to Reflected/Stored XSS WPScan
318 yml-for-yandex-market CVE-2024-1365 10,000 Reflected XSS Wordfence
319 analytics-insights CVE-2024-0250 9,000 Open Redirect WPScan
320 cost-of-goods-for-woocommerce CVE-2024-0821 9,000 Reflected XSS Wordfence
321 gdpr-cookie-consent CVE-2024-3599 9,000 Unauthenticated arbitrary post deletion Wordfence
322 gdpr-cookie-consent CVE-2024-4869 9,000 Unauthenticated Stored XSS Wordfence
323 inline-google-spreadsheet-viewer CVE-2024-3674 9,000 Contributor+ Stored XSS Wordfence
324 media-library-plus CVE-2024-3615 9,000 Reflected XSS Wordfence
325 motors-car-dealership-classified-listings. CVE-2024-5545 9,000 Hiding arbitrary posts from homepage Wordfence
326 rotatingtweets CVE-2024-5141 9,000 Contributor+ Stored XSS Wordfence
327 slideshow-gallery CVE-2024-5543 9,000 Contributor+ SQL Injection Wordfence
328 toolbar-extras CVE-2024-3611 9,000 Contributor+ Stored XSS Wordfence
329 videojs-html5-player CVE-2024-5205 9,000 Contributor+ Stored XSS Wordfence
330 woocommerce-catalog-enquiry CVE-2023-5348 9,000 Stored XSS WPScan
331 wp-hotel-bookings CVE-2023-5651 9,000 Missing authorization WPScan
332 wp-hotel-bookings CVE-2023-5652 9,000 SQL Injection WPScan
333 wp-hotel-bookings CVE-2024-3605 9,000 SQL injection Wordfence
334 wp-migration-duplicator CVE-2024-3546 9,000 Arbitrary .log file read Wordfence
335 wp-sms CVE-2023-6980 9,000 CSRF subscriber and group deletion Wordfence
336 wp-sms CVE-2023-6981 9,000 SQL Injection leading to Reflected XSS Wordfence
337 erp CVE-2024-0608 8,000 SQL Injection Wordfence
338 erp CVE-2024-0609 8,000 XSS Wordfence
339 facebook-button-plugin CVE-2023-6250 8,000 Password-protected post read WPScan
340 icon-widget CVE-2024-1993 8,000 Contributor+ stored XSS Wordfence
341 json-content-importer CVE-2023-6268 8,000 Reflected XSS WPScan
342 kiwi-social-share CVE-2024-3228 8,000 Password-protected post read Wordfence
343 mediavine-create CVE-2024-1711 8,000 SQL injection Wordfence
344 stopbadbots CVE-2024-4355 8,000 Downloading request log (with IPs, user agents, …) Wordfence
345 wp-compress-image-optimizer CVE-2023-6812 8,000 Open Redirect Wordfence
346 wp-compress-image-optimizer CVE-2023-6699 8,000 LFI Wordfence
347 wp-migration-duplicator CVE-2023-5738 8,000 Stored XSS WPScan
348 wp-migration-duplicator CVE-2023-5737 8,000 Arbitrary settings update WPScan
349 wpc-composite-products CVE-2024-2838 8,000 Stored XSS Wordfence
350 armember-membership CVE-2024-4133 7,000 Open Redirect Wordfence
351 calendar CVE-2024-2831 7,000 Contributor+ SQL Injection Wordfence
352 estatik CVE-2023-6048 7,000 DoS WPScan
353 estatik CVE-2023-6049 7,000 Object injection WPScan
354 events-made-easy CVE-2021-25030 7,000 SQL injection WPScan
355 jm-twitter-cards CVE-2024-1769 7,000 Password-protected post read Wordfence
356 jquery-t-countdown-widget CVE-2024-4783 7,000 Contributor+ Stored XSS Wordfence
357 likebtn-like-button CVE-2021-24945 7,000 Sensitive data exposure WPScan
358 likebtn-like-button CVE-2022-0745 7,000 Arbitrary e-mail sending WPScan
359 list-categories CVE-2024-4356 7,000 Contributor+ Stored XSS Wordfence
360 mediavine-create CVE-2024-5601 7,000 Contributor+ Stored XSS Wordfence
361 travelpayouts CVE-2023-5932 7,000 Reflected XSS WPScan
362 woo-product-category-discount CVE-2024-0617 7,000 arbitrary discount change Wordfence
363 wp-email-users CVE-2021-24959 7,000 SQL injection + object injection WPScan
364 wpupper-share-buttons CVE-2024-4997 7,000 Password-protected post read Wordfence
365 wpvivid-backup-mainwp CVE-2024-1383 7,000 Reflected XSS Wordfence
366 country-state-city-auto-dropdown CVE-2024-3495 6,000 Unauthenticated SQL injection Wordfence
367 easyjobs CVE-2023-6843 6,000 Unauthorized settings change WPScan
368 export-wp-page-to-static-html CVE-2024-3597 6,000 Open Redirect Wordfence
369 integrate-google-drive CVE-2024-2086 6,000 Missing authorization Wordfence
370 order-delivery-date CVE-2024-0678 6,000 Stored XSS Wordfence
371 poll-maker CVE-2024-3600 6,000 Unauthenticated Stored XSS Wordfence
372 poll-maker CVE-2024-3601 6,000 Obtaining all users’ e-mails Wordfence
373 responsive-vector-maps CVE-2021-24947 6,000 Arbitrary file read WPScan
374 theme: blossom-spa CVE-2024-2107 6,000 Password-protected post read Wordfence
375 travelpayouts CVE-2024-0337 6,000 Open Redirect WPScan
376 woo-gift-cards-lite CVE-2024-1857 6,000 Draft and password-protected post read Wordfence
377 wp-cafe CVE-2024-5431 6,000 Contributor+ LFI Wordfence
378 wp-cafe CVE-2024-5427 6,000 Contributor+ Stored XSS Wordfence
379 advanced-schedule-posts CVE-2024-0249 5,000 Reflected XSS WPScan
380 ari-cf7-connector CVE-2024-0239 5,000 Reflected XSS WPScan
381 auth0 CVE-2023-6813 5,000 Reflected XSS Wordfence
382 button-generation CVE-2021-25052 5,000 CSRF RCE WPScan
383 dashboard-widgets-suite CVE-2024-0979 5,000 Reflected XSS Wordfence
384 easyazon CVE-2023-6956 5,000 Reflected XSS Wordfence
385 embedalbum-pro CVE-2024-3984 5,000 Contributor+ Stored XSS Wordfence
386 testimonial-slider CVE-2024-4193 5,000 Contributor+ Stored XSS Wordfence
387 ultimate-410 CVE-2024-3677 5,000 Contributor+ Stored XSS Wordfence
388 wp-e-commerce CVE-2024-1516 5,000 Unauthorized post insert Wordfence
389 wp-e-commerce CVE-2024-1514 5,000 SQL injection Wordfence
390 wp-easycart CVE-2024-3211 5,000 Contributor+ Blind SQL injection Wordfence
391 wp-job-manager-companies CVE-2023-6978 5,000 Reflected XSS Wordfence
392 wp-stateless CVE-2024-1385 5,000 DoS Wordfence
393 wp-ultimate-post-grid CVE-2024-4043 5,000 Contributor+ Stored XSS Wordfence

Not all of the vulnerabilities were found directly by the fuzzer. For example, CVE-2021-25096 was found accidentally when writing a PoC for CVE-2021-25095. For some other vulnerabilities, the tool alerts were only part of the vulnerability information – for example, the tool notified that a WordPress option can get updated by any user - and finding the consequences (whether it can lead e.g. to stored XSS) required manual work.

Findings worth mentioning

I won’t make fun of any particular plugin author, however, I think some findings are worth sharing.

is_admin

The WordPress is_admin() function, as you may probably have guessed:

Determines whether the current request is for an administrative interface page.

(from https://developer.wordpress.org/reference/functions/is_admin/)

The documentation warns as well, that it:

Does not check if the user is an administrator; use current_user_can() for checking roles and capabilities.

As you may probably have guessed, it was a source of a couple of vulnerabilities in the form of:

if (is_admin()) {
    /* dangerous action */
}

REST route URLs

Let’s consider the following code:

register_rest_route((...), '/(...)/(?P<id>[\d]+)', array(
    array(
        'methods' => WP_REST_Server::READABLE,
        'callback' => array($this, 'callback'),
        'permission_callback' => '__return_true',
    ),
));

/* ... */

function callback($request) {
    $id = $request['id'];
}

What ID values could be passed to the handler?

The correct answer is: all of them – just use /?rest_route=/(...)/1&id=hehehe.

get_users()

Some plugins allow searching for users by providing a part of an e-mail address. That allows to leak any user’s e-mail using the following steps:

  • Bruteforcing the first letter of the domain name (searching for @a, @b, etc., and checking when the user’s name appears in search results).
  • Remembering the first letter and using it to guess the second letter. Let’s assume the user’s e-mail domain name starts with g. You can then brute force the second letter (@ga, @gb, …).
  • Repeating the above steps for the rest of the e-mail address.

Because of that, I have added a check that alerts when get_users() gets called. Unfortunately, besides finding vulnerabilities of this type, it led to numerous false positives as well.

XSS protection

Don’t do the following:

if (/* potential XSS in $parameter detected */) die('Invalid parameter: ' . $parameter);

Several XSS vulnerabilities were also caused by debugging helpers in the form of:


echo "<!--";

var_dump($_POST);

echo "-->";

CAPTCHA verification

Don’t do this:

if (isset($_POST['captcha'])) {
    /* verify captcha */
}

/* do action that should be CAPTCHA-protected */

I have observed this pattern multiple times, both for CAPTCHAs and nonces.

Conclusions

This was just a proof-of-concept to check whether automatic techniques are a viable method to find WordPress plugin bugs. I am sure it can be improved by e.g.:

  • adding checks to detect other types of dangerous operations,
  • attempting to decrease the number of false positives without a large loss of true positives. The percentage of false positives was one of the main obstacles in this project.

This technique can also be implemented for other plugin ecosystems.

Many of the vulnerabilities I found were easily preventable by modern software engineering practices. In many WordPress plugins, HTML is built using an error-prone pile of echo statements, instead of a template language. Similarly, AJAX endpoints are by default available for all logged-in users or all not logged-in users, instead of requiring the developer to provide a fixed allowlist of roles or permissions (so that they would have to explicitly mark a route as available to all logged-in users). Introducing techniques that make it harder to make mistakes and promoting their use is, unfortunately, something only the WordPress team, not plugin developers, can do.

Footnotes

  1. In retrospect, using a pile of regular expressions to detect crashes in the output wasn’t the best idea. Now I would try to do this differently. 

  2. In retrospect, it is obvious that it doesn’t cover all ways to load XML. This should have been done differently. 

  3. This type of reflected XSS requires cookies to be sent with a POST request, therefore would be harder to exploit due to the SameSite-by-default behavior.  2 3 4 5 6 7 8