• Vulnerability: SQL Injection & Reflected XSS
  • Affected Software: Visual Form Builder (WordPress Plugin)
  • Affected Version: 2.8.2 (probably also prior versions)
  • Patched Version: 2.8.3
  • Risk: High
  • Vendor Contacted: 2015-05-06
  • Vendor Fix: 2015-05-09
  • Public Disclosure: 2015-05-15

The current version (v2.8.2) of the WordPress plugin Visual Form Builder is vulnerable to reflected XSS as well as SQL injection attacks.

The damage each attack on it’s own can achieve is limited. The SQL injection can lead to data leaks, and possibly priviledge escalation or code execution, but an admin login is required. And as WordPress secures it’s relevant cookies, it’s not possible to gain a login via XSS, it is only possibly to eg display the login page and hope that the admin enters their password or inject a JavaScript keylogger; both mean that an admin doesn’t just have to visit a website, but also has to additionally enter their password somewhere. With XSS, it is also possibly to bypass CSRF, so an attacker could eg change PHP scripts if DISALLOW_FILE_EDIT is false, which hopefully is not the case.

Combined, these attacks get interesting: Via XSS it is possible to let the admin execute the SQL injection, and then send the results to the attacker. The admin only has to click on a link once, and does not have to perform any further actions.

SQL injection


High; any user with access to this plugin can retrieve any data from the database that the WordPress database user has access to; in combination with the XSS below, the attacker could also get the admin to execute these queries for them.



This is a very basic SQL injection, so it is possibly to directly extract any data the db user has access to:

localhost/wordpress/wp-admin/admin.php?page=visual-form-builder&form-filter=1+union+all+select+user_login,user_pass+from+wp_users %23


The function current_filter_action() returns user input:

        function current_filter_action() {
            if ( isset( $_REQUEST['form-filter'] ) && -1 !=
$_REQUEST['form-filter'] )
                return $_REQUEST['form-filter'];

            return false;

Which is then used in two locations directly inside SQL queries, without any sanitation:

            if ( $this->current_filter_action() )
                $where .= 'AND form_id = ' . $this->current_filter_action();
            $total_items = $wpdb->get_var( "SELECT COUNT(*) FROM
$this->entries_table_name AS entries WHERE 1=1 $where" );


        function get_entries( $orderby = 'date', $order = 'ASC', $per_page,
$offset = 0, $search = '' ){
            if ( $this->current_filter_action() )
                $where .= 'AND forms.form_id = ' . $this->current_filter_action();
            $cols = $wpdb->get_results( "SELECT forms.form_title,
entries.entries_id, entries.form_id, entries.subject,
entries.sender_name, entries.sender_email, entries.emails_to,
entries.date_submitted, entries.ip_address FROM $this->form_table_name
AS forms INNER JOIN $this->entries_table_name AS entries ON
entries.form_id = forms.form_id WHERE 1=1 $where $search ORDER BY
$sql_order LIMIT $per_page $offset" );


At the very least, $wpdb->prepare should be used.



Medium; Arbitrary JavaScript execution when victim clicks on link.


There are reflected XSS attacks in at least two places:



visual-form-builder.php:1617 and 1794

            if ( isset( $_REQUEST['s'] ) && !empty( $_REQUEST['s'] ) )
                echo '<span class="subtitle">' . sprintf( __( 'Search results for
"%s"' , 'visual-form-builder' ), $_REQUEST['s'] );


Using htmlentities or the appropriate WordPresses functions around user input before echoing it.