🐝

CVE-2024-2948

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

  1. Install WordPress locally
  1. Download the plugin and install it
notion image
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 :)
notion image
notion image