Multiple Vulnerabilities In Shortcodes Ultimate Plugin Versions <=5.12.6

Published 21 February 2023
Updated 24 July 2023
Rafie Muhammad
Security Researcher at Patchstack
Table of Contents

If you're a Shortcodes Ultimate user, please update the plugin to at least version 5.12.7.

Patchstack paid plan users are protected from the vulnerability. You can also sign up the Patchstack Community plan to be notified about vulnerabilities as soon as they become disclosed.

For plugin developers, we have security audit services and Threat Intelligence Feed API for hosting companies.

Introduction

The plugin Shortcodes Ultimate (versions 5.12.6 and below), which has over 700,000 active installations is known as a plugin that provides multiple shortcode features. This plugin provides a comprehensive collection of various visual and functional elements, which we can use in the post editor, text widgets, or even in template files.

Shortcodes Ultimate Plugin

This plugin suffers from an authenticated Server Side Request Forgery (SSRF) and Arbitrary File Read vulnerability.

This vulnerability allows any authenticated user with a minimum Contributor role to forge a request to an internal WordPress network and fetch any arbitrary local file on the server. The described vulnerability was fixed in version 5.12.7 and assigned CVE-2023-23800 & CVE-2023-25050 respectively.

The security vulnerability in Shortcodes Ultimate

"Unsafe Features"

Shortcodes Ultimate made a disclaimer about "Unsafe features". Described as a set of plugin features that may potentially harm a website if we have non-admin users (registered users with edit permissions) on our site.

To prevent possible vulnerabilities, the plugin will automatically disable such features once we have at least one non-admin user on our site. Two of the shortcode features listed are csv_table and table shortcode.

Arbitrary File Read

See the vulnerability in the Patchstack database.

The vulnerable code exists in the function su_shortcode_table that handles table shortcode.

function su_shortcode_table( $atts = null, $content = null ) {

	$atts = shortcode_atts(
		array(
			'url'        => '', // deprecated since 5.3.0
			'responsive' => 'no',
			'alternate'  => 'yes',
			'fixed'      => 'no',
			'class'      => '',
		),
		$atts,
		'table'
	);

	if ( $atts['url'] && ! su_is_unsafe_features_enabled() ) {

		return su_error_message(
			'Table',
			sprintf(
				'%s.<br><a href="https://getshortcodes.com/docs/unsafe-features/" target="_blank">%s</a>',
				// translators: do not translate the <b>url</b> part, the <b>Unsafe features</b> must be translated
				__( 'The <b>url</b> attribute cannot be used while <b>Unsafe features</b> option is turned off', 'shortcodes-ultimate' ),
				__( 'Learn more', 'shortcodes-ultimate' )
			)
		);

	}

	foreach ( array( 'responsive', 'alternate', 'fixed' ) as $feature ) {

		if ( 'yes' === $atts[ $feature ] ) {
			$atts['class'] .= ' su-table-' . $feature;
		}

	}

	su_query_asset( 'css', 'su-shortcodes' );

	$table = $atts['url']
		? su_parse_csv( $atts['url'] )
		: do_shortcode( $content );

	return '<div class="su-table' . su_get_css_class( $atts ) . '">' . $table . '</div>';

}

The shortcode feature accepts $atts['url'] and will output the $table variable that is built from su_parse_csv( $atts['url'] ). Below is the snippet code of the su_parse_csv function:

function su_parse_csv( $file ) {
	// phpcs:disable
	$csv_lines = file( $file );
---------- CUTTED HERE ------------

The su_parse_csv function will basically fetch the $file parameter using the PHP file function and will return the value of the fetched content. Since the file function could both fetch content from URL and local file, we could utilize this to perform both Arbitrary File Read and SSRF.

Server Side Request Forgery (SSRF)

Read more about the vulnerability in the Patchstack database.

The vulnerable code exists in the function su_shortcode_csv_table that handles csv_table shortcode.

function su_shortcode_csv_table( $atts = null, $content = null ) {

	$atts = shortcode_atts(
		array(
			'url'        => '',
			'delimiter'  => ',',
			'header'     => 'no',
			'responsive' => 'no',
			'alternate'  => 'yes',
			'fixed'      => 'no',
			'class'      => '',
		),
		$atts,
		'table'
	);

	if ( ! su_is_unsafe_features_enabled() ) {

		return su_error_message(
			'CSV Table',
			sprintf(
				'%s.<br><a href="https://getshortcodes.com/docs/unsafe-features/" target="_blank">%s</a>',
				__( 'This shortcode cannot be used while <b>Unsafe features</b> option is turned off', 'shortcodes-ultimate' ),
				__( 'Learn more', 'shortcodes-ultimate' )
			)
		);

	}

	if ( filter_var( $atts['url'], FILTER_VALIDATE_URL ) === false ) {
		return su_error_message( 'CSV Table', __( 'invalid URL', 'shortcodes-ultimate' ) );
	}

	$response = wp_remote_get( $atts['url'] );

	if ( 200 !== wp_remote_retrieve_response_code( $response ) ) {
		return su_error_message( 'CSV Table', __( 'invalid URL', 'shortcodes-ultimate' ) );
	}

	if ( ! is_string( $atts['delimiter'] ) || 1 !== strlen( $atts['delimiter'] ) ) {
		return su_error_message( 'CSV Table', __( 'invalid delimiter', 'shortcodes-ultimate' ) );
	}

	$csv  = wp_remote_retrieve_body( $response );
	$html = su_csv_to_html(
		$csv,
		$atts['delimiter'],
		'yes' === $atts['header']
	);

	foreach ( array( 'responsive', 'alternate', 'fixed' ) as $feature ) {

		if ( 'yes' === $atts[ $feature ] ) {
			$atts['class'] .= ' su-table-' . $feature;
		}

	}

	su_query_asset( 'css', 'su-shortcodes' );

	return '<div class="su-table su-csv-table' . su_get_css_class( $atts ) . '">' . $html . '</div>';

}

The shortcode feature accepts $atts['url'] and validates the string with FILTER_VALIDATE_URL. The variable is then directly passed to the wp_remote_get function and at the end of the function, it will output the contents of the requested URL.

Since we are able to fully control $atts['url'], we can perform request forgery to the internal network services of the WordPress site.

The patch in Shortcodes Ultimate

For SSRF, this issue is mainly because the code tries to fetch an arbitrary URL using wp_remote_get in the csv_table shortcode, simply using the provided wp_safe_remote_get will secure the process from a request forgery. The patch can be found here:

The patch in Shortcodes Ultimate

For the arbitrary file read on the table shortcode, the developer decided to redirect the process to the csv_table shortcode. The patch can be found here:

The patch in Shortcodes Ultimate

Conclusion

Some plugins may include features that are intended to be insecure or unsafe. These features often come with a disclaimer from the plugin vendor. Despite this, we should implement this feature as securely as possible with the right functions and processes.

If the plugin needs a feature to fetch an URL that is fully or partially controlled by the user, we recommend using wp_safe_remote_get or wp_safe_remote_post to avoid any unwanted redirections and request forgery.

Disclosure timeline of the Shortcodes Ultimate vulnerability

08-02-2022 - We found the vulnerability and reached out to the plugin vendor.
09-02-2022 - Shortcodes Ultimate plugin version 5.12.7 was published to patch the reported issues.
10-02-2023 - Added the vulnerabilities to the Patchstack vulnerability database.
21-02-2023 - Published the article.

Help us make the web a safer place

Making the WordPress ecosystem more secure is a team effort, and we believe that plugin developers and security researchers should work together.

  • If you're a plugin developer, join our mVDP program that makes it easier to report, manage and address vulnerabilities in your software.
  • If you're a security researcher, join Patchstack Alliance to report vulnerabilities & earn rewards.

The latest in Security Advisories

Looks like your browser is blocking our support chat widget. Turn off adblockers and reload the page.
crossmenu