Description The Favorites plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the plugin's 'user_favorites' shortcode in all versions up to, and including, 2.3.3 due to insufficient input sanitization and output escaping on user supplied attributes such as 'no_favorites'. This makes it possible for authenticated attackers, with contributor-level access and above, to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
Code Analysis If we look at how this was discovered, it was proper through searching for unsafe concatenation of user strings in the file functions.php
We see that it does not use any escaping functions like htmlentities
, or WordPress specific functions like esc_html
.
if ( $html ) $out .= '<span class="simplefavorites-user-count" data-posttypes="' . $posttypes . '" data-siteid="' . $site_id . '">';
This can then be traced to follow the initialization of $posttypes
which is initialized from this line
$posttypes = ( isset($filters['post_type']) ) ? implode(',', $filters['post_type']) : 'all';
Where $filters['post_type']
was unsafely initialized without any escaping in UserFavoritesShortcode.php
private function setOptions($options)
{
$this->options = shortcode_atts([
'user_id' => '',
'site_id' => '',
'include_links' => 'true',
'post_types' => '',
'include_buttons' => 'false',
'include_thumbnails' => 'false',
'thumbnail_size' => 'thumbnail',
'include_excerpts' => 'false',
'no_favorites' => ''
], $options);
}
private function parsePostTypes()
{
if ( $this->options['post_types'] == "" ) return;
$post_types = explode(',', $this->options['post_types']);
$this->filters = ['post_type' => $post_types];
}
We see that thumbnail_size
is also not sanitized and accepts a string value
return $favorites->getFavoritesList(
$this->options['include_buttons'],
$this->options['include_thumbnails'],
esc_attr($this->options['thumbnail_size']),
$this->options['include_excerpts'],
esc_attr($this->options['no_favorites'])
);
This means that when a user enters the shortcode below, it will escape the HTML and can result in XSS
[user_favorites thumbnail_size="<script>alert(1)</script>]
The Fix esc_attr
was used in instances where HTML could be reflected to the front end
return $favorites->getFavoritesList(
$this->options['include_buttons'],
$this->options['include_thumbnails'],
esc_attr($this->options['thumbnail_size']),
$this->options['include_excerpts'],
esc_attr($this->options['no_favorites'])
);
So now the shortcode string options like thumbnail_size
and no_favorites
will be escaped
Recreation Install WordPress locally Download the plugin and install it Create a new post and add a shortcode in it with attributes thumbnail_size
and no_favorites
If we look at the HTML that's being rendered, it properly escapes the special characters, so yea, seems like a valid fix :)