WP Prayer is a WordPress plugin where authenticated users can submit prayer requests through a prayer form. The plugin can list all the requested prayers by users on a post or page. WP Prayer version 1.6.1 and earlier contains an Authenticated Stored Cross-Site Scripting (XSS) vulnerability.
How the vulnerability works
Let’s dive into the details of how this authenticated stored XSS works! To submit a prayer request a user has to be authenticated. I created a WordPress user account on the website with the role Subscriber, which is the role with the least privileges within WordPress. When logged into the website with the subscriber role, the prayer request form looks like this.
The form field where a prayer request can be made contains the following PHP code:
The code in line 3 checks whether data is present in the text area of the ‘Prayer Request’ field. If the text area field is not empty, it sets the string in the text area to the variable
$data['prayer_messages'] and when the form is submitted, does a POST request to the website.
Next, the received POST data from the prayer request forms flows to the data model, which has a function to save the user’s prayer request to the database. If the received
prayer_messages is declared and different from null, the slashes of the string are removed, as can be seen in lines 22-23 in the code below. When completed, the prayer request is successfully stored in the database.
What’s interesting is that the
request_type variables are sanitized by the function
sanitize_text_field, while the
prayer_messages variable is not.
Let’s submit the prayer request including our payload, we get a message saying the form was received. Our prayer request is now saved in the database.
Let’s look at how the stored prayer requests are loaded into the webpage. In the shortcode of the WP Prayer Engine, the following PHP code loads the stored prayer request information from the database into the HTML of the webpage. However, there is no validation of the data that is being loaded into the webpage.
Let’s see how the HTML of the webpage looks when the PHP code is executed and our prayer request is loaded from the database into the HTML:
The authenticated stored XSS in WP Prayer 1.6.1 and earlier poses a risk for visitors of the webpage where prayer requests are listed. For example, stored XSS can be used by a malicious actor to potentially steal cookies or sensitive data from visitors.
Proof of Concept
The vulnerability exists because the prayer message field of the prayer request form does not sanitize and validate user input, therefore code can be saved to the database. In addition, the prayer message field string that is saved in the database is loaded into the webpage without special characters (such as <, >, &, “, and ‘) being converted to HTML entities, which leads to the code being loaded into the webpage. Therefore, the code will be loaded and executed into the webpage when prayer requests are listed.
With this responsible disclosure, I hope I provided salvation by saving this plugin from a security sin.
15 April, 2021: WPScan – Vendor contacted
21 April, 2021: WPScan – Escalated to WordPress
14 May, 2021: Vulnerability fixed by vendor
17 May, 2021: Disclosure on WPScan and CVE-2021-24313 assigned
31 May, 2021: Proof of Concept disclosure