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.
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:
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:
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.