Home » WordPress shortcode injection as an attack vector

WordPress shortcode injection as an attack vector

Summary

This is not about a specific vulnerability but an intrusion vector often overlooked by WordPress plugin and theme developers. Frequently code is used that allows attackers to execute arbitrary shortcodes or shortcodes are added that do not provide sufficient validation or check authorization. After all, shortcodes are intended to be used by site editors who are expected to have high credentials, though an attacker doesn’t play by the rules.

What is a shortcode?

Shortcodes were introduced in WordPress version 2.5 back in 2008 as a way for editors to include dynamically generated content in WordPress posts. Initially the available shortcodes were rather limited but plugin and theme developers quickly embraced the API. Shortcodes allow passing attributes and content data to custom functions that return textual data to be included with the post.

Default shortcodes available in WordPress 4.7.2

The default shortcodes are relatively safe but many third party developers have added functionality that makes it easier for WordPress site administrators to extend their site without doing custom PHP coding. Generally the shortcodes added are benign and allow building feature rich WordPress websites, though sometimes the shortcodes provide features that can be leveraged for nefarious purposes.

Shortcode functionality I have seen in various third party plugins

  • Include arbitrary files from the file system
  • Execute arbitrary PHP code
  • Retrieve arbitrary data from WordPress custom post type fields
  • Generate HTML forms that allow editing WordPress posts or users
  • View content that is supposed to be protected by password or other specific protections
  • Provide list of discount codes for an E-Commerce plugin

Who does this affect?

If you are using stock WordPress without any third party plugins or themes you should be safe from any known attack. I’ve posted in the past about specific vulnerabilities but there are some issues I’ve uncovered during research that have not been resolved yet so I will not disclose them until they are fixed.

Depending on the site setup, a user with a Contributor, Author, or Editor role could potentially use shortcodes to escalate their privileges to that of an administrator. With the default roles and capabilities a user with the Contributor role can create posts but they must be approved before being published, but a Contributor can preview their own posts which will cause any included shortcodes to be executed.

How can a developer help prevent these types of an attack?

There are 2 major aspects developers need to be concerned with.

Allowing shortcode injection

Anytime a developer feels the need to call do_shortcode() they should ensure that user input is not passed into the function or be properly sanitized, just like with any other user input.

Keeping shortcodes secure

Any shortcode added with add_shortcode() should check that the logged in user has proper credentials to execute the action. All attributes passed should be properly validated as if the input comes from an untrusted attacker.

Securing shortcodes going forward

I wish there was a holy grail to solve this issue with a couple lines of code, but it’s not a trivial issue to tackle. If a developer could specify capabilities required to insert a specific shortcode then post editors could filter out shortcodes that an author should not have access to, for instance administrator only shortcodes.

I use some simple custom code that adds a filter on ‘pre_do_shortcode_tag’ to restrict shortcodes I explicitly want to allow, security plugins could add some whitelisting/blacklisting of shortcodes but this would likely cause a significant amount of support issues when features suddenly stop working.

Following is a code example to show how to restrict the shortcodes allowed to only the ones that come with stock WordPress.

add_filter( 'pre_do_shortcode_tag', 'pritect_whitelist_shortcodes', 10, 4 );
function pritect_whitelist_shortcodes( $return, $tag, $attr = array(), $m = array() ) {
    if ( in_array( $tag, array( 'audio', 'caption', 'embed', 'gallery', 'playlist', 'video' ) ) ) {
        return $return;
    }
    return '';
}

I hope one day WordPress has a security permission system setup that requires plugins and themes to specify capabilities they use and allow the site administrator to authorize or revoke specific permissions, but that is a large moving target that I wouldn’t expect to be implemented for years (if ever).