A medium severity threat to WordPress sites using the All in One SEO pack has been found by our partner.  While sites hosted by us have already been patched, this post may help your in-house teams keep your site safe.

 

What is All in One SEO?

All In One SEO Pack is a plugin that provides several SEO enhancing features to help rank a WordPress site’s content higher on search engines.  As part of its functionality, it allows users that have the ability to create or edit posts to set an SEO title and SEO description.  This makes it easier for post creators to improve the SEO of posts as they are writing them.  This feature is available to all users that can create posts, such as contributors, authors, and editors.

 

So what’s the issue?

The flaw allows authenticated users with contributor level access or above the ability to inject malicious scripts that would be executed if a victim accessed the wp-admin panel’s ‘all posts’ page.

This is considered a medium severity security issue that, as with all XSS vulnerabilities, can result in complete site takeover and other severe consequences.  We strongly recommend immediately updating to the latest version of this plugin.  At the time of writing, that is version 3.6.2 of All in One SEO Pack.

Unfortunately, the SEO meta data for posts, including the SEO title and SEO description fields, had no input sanitisation allowing lower-level users like contributors and authors the ability to inject HTML and malicious JavaScript into those fields.

See the below code snippet for reference:

 

5058
5059
5060
5061
5062
5063
5064
5065
5066
5067
5068
5069
5070
5071
5072
5073
5074
5075
5076
5077
5078
5079
5080
5081
5082
5083
5084
5085
5086
5087
5088
5089
5090
5091
5092
5093
5094
5095
5096
5097
5098
5099
5100
5101
5102
5103
5104
5105
5106
5107
5108
5109
5110
5111
5112
/**
 * Saves the data of our metabox settings for a post.
 *
 * @since   ?
 * @since   3.4.0   Added support for priority/frequency + minor refactoring.
 *
 * @param   int     $id     The ID of the post.
 * @return  bool            Returns false if there is no POST data.
 */
function save_post_data( $id ) {
    $awmp_edit = null;
    $nonce     = null;
    if ( empty( $_POST ) ) {
        return false;
    }
    if ( isset( $_POST['aiosp_edit'] ) ) {
        $awmp_edit = $_POST['aiosp_edit'];
    }
    if ( isset( $_POST['nonce-aioseop-edit'] ) ) {
        $nonce = $_POST['nonce-aioseop-edit'];
    }
    if ( isset( $awmp_edit ) && ! empty( $awmp_edit ) && wp_verify_nonce( $nonce, 'edit-aioseop-nonce' ) ) {
        $optlist = array(
            'keywords',
            'description',
            'title',
            'custom_link',
            'sitemap_exclude',
            'disable',
            'disable_analytics',
            'noindex',
            'nofollow',
            'sitemap_priority',
            'sitemap_frequency',
        );
        if ( empty( $this->options['aiosp_can'] ) ) {
            unset( $optlist['custom_link'] );
        }
        if ( ! AIOSEOPPRO ) {
            $optlist = array_diff( $optlist, array( 'sitemap_priority', 'sitemap_frequency' ) );
        }
        foreach ( $optlist as $optionName ) {
            $value = isset( $_POST[ "aiosp_$optionName" ] ) ? $_POST[ "aiosp_$optionName" ] : '';
            update_post_meta( $id, "_aioseop_$optionName", $value );
        }
    }
}

 

The SEO title and SEO description for each post are always displayed on the ‘all posts’ page as they appear in the far right column for easier quick editing access.  Therefore, any values added to the SEO title and SEO description fields would be displayed here in an unsanitised format, causing saved JavaScript in these fields to be executed when any user accessed the ‘all posts’ page.

Any JavaScript injected in the SEO description field would also be executed when visiting the page directly if a closing tag was inserted by an attacker before adding their own script. For example, it could look like </script><script>alert(0)</script>. This was due to the fact that the tag would close out the SEO description’s original script tag and inject an additional script directly after.

Due to the JavaScript being executed whenever a user accessed the ‘all posts’ page, this vulnerability would be a prime target for attackers that are able to gain access to an account that allows them to post content.  Since Contributors must submit all posts for review by an Administrator or Editor, a malicious Contributor could be confident that a higher privileged user would access the ‘all posts’ area to review any pending posts.  If the malicious JavaScript was executed in an Administrator’s browser, it could be used to inject backdoors or add new administrative users and take over a site.

 

So, what happens now?

Luckily, the developer of the plugin has now patched it and added sanitisation.  If an attacker enters HTML characters, they will be escaped and become unusable.  This is why we’re recommending you upgrade the plugin now.

If you need more help or advice, why not talk to us today?