If you’re a Shortcodes Ultimate user, please update the plugin to at least version 5.12.7.
Patchstack Pro and Business 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.
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.
This plugin suffers from an authenticated Server Side Request Forgery (SSRF) and Arbitrary File Read vulnerability. This vulnerability allows any authenticated user with 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.
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.
The vulnerable code exists in 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 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 perfrom both Arbitrary File Read and SSRF.
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.
For SSRF, since 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:
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:
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 of this, we should implement this feature as secure 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.
08-02-2022 – We found the vulnerability and reached out to the plugin vendor.
09-02-2022 – Shortcodes Ultimate plugin version 5.12.7 published to patch the reported issues.
10-02-2023 – Added the vulnerabilities to the Patchstack vulnerability database.
21-02-2023 – Published the article.
Making WordPress ecosystem more secure is a team effort, and we believe that plugin developers and security researchers should work together.