Recently we discover a stored Cross Site Scripting in a WordPress plugin which is installed in our website. It also effects more that 70.000 WordPress users. We immediately get in work and find a fix for that. After fixing the vulnerable code we submitted to the Developers. Hopefully they upgrade of the vulnerable one was immediately.


The Problem:

The original problem was that there was not an xss check on the parameters of the name,group and email, thereby when a user entered his email and his name the data that was going to be stored on the server were not checked leaving the possibility of arbitrary (xss) input open. Although the developers were using the wordpress standard functions to escape sql injection characters they forgot to escape xss characters leaving the plugin vulnerable to attack.

A simple script like: <script>alert(1)</script> allowed as to verify the existence of the bug.

Proof of concept image:


The consequences:

The severity of the bug is high because a black hat hacker could create an exploit that could be used to steal the cookies of the site administrator and log in as an administrator user. That will allow him to basically do whatever he want on the site.


The vulnerable code:

$sql = $wpdb->prepare(“INSERT INTO `”.$prefix.”es_emaillist`
(`es_email_name`,`es_email_mail`, `es_email_status`, `es_email_created`, `es_email_viewcount`, `es_email_group`, `es_email_guid`)
VALUES(%s, %s, %s, %s, %d, %s, %s)”, array(trim($data[“es_email_name”]), trim($data[“es_email_mail”]),
trim($data[“es_email_status”]), $CurrentDate, 0, trim($data[“es_email_group”]), $guid));

As we see the data of the variables are trimmed but they are not checked for cross-site-scripting characters. The fix was very simple, we added a check function before each character. So the following code fixed the problem:

$sql = $wpdb->prepare(“INSERT INTO `”.$prefix.”es_emaillist`
(`es_email_name`,`es_email_mail`, `es_email_status`, `es_email_created`, `es_email_viewcount`, `es_email_group`, `es_email_guid`)
VALUES(%s, %s, %s, %s, %d, %s, %s)”, array(trim(sanitize_text_field($data[“es_email_name”])), trim(sanitize_text_field($data[“es_email_mail”])),
trim(sanitize_text_field($data[“es_email_status”])), $CurrentDate, 0, trim(sanitize_text_field($data[“es_email_group”])), $guid));

Proof of concept for the fixed code:



We were very happy to help the developers and fix the problem.