Critical Vulnerability in Elementor Affecting 5+ Million Websites

Published 8 December 2023
Rafie Muhammad
Security Researcher at Patchstack
Table of Contents

The vulnerability in Elementor was originally reported by Hồng Quân (luk6785 at VNPT-VCI) to our alliance program. We are collaborating with the researcher to release the content of this security advisory article.

This blog post is about an Elementor plugin vulnerability. If you're an Elementor user, please update the plugin to at least version 3.18.2.

You can sign up for 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.

About the Elementor Plugin

The plugin Elementor (free version), which has over 5 million active installations, is known as the most popular website builder plugin in WordPress.

Elementor is known to be the leading website-building platform for WordPress, enabling web creators to build professional, pixel-perfect websites with an intuitive visual builder. The plugin could quickly create amazing websites for clients or businesses with complete control over every piece, without writing a single line of code.

The security vulnerability in Elementor

This plugin suffers from an authenticated arbitrary file upload vulnerability. This vulnerability allows accounts with edit post permissions such as Contributor role, to upload arbitrary files, including php files, that could lead to remote code execution. The described vulnerability was introduced in version 3.3.0 and fixed in version 3.18.2 and assigned CVE-2023-48777.

Arbitrary File Upload

The underlying vulnerable code exists in the handle_elementor_upload function :

public function handle_elementor_upload( array $file, $allowed_file_extensions = null ) {
   // If $file['fileData'] is set, it signals that the passed file is a Base64 string that needs to be decoded and
   // saved to a temporary file.
  
   if ( isset( $file['fileData'] ) ) {
   $file = $this->save_base64_to_tmp_file( $file );
   }
  
   $validation_result = $this->validate_file( $file, $allowed_file_extensions );
  
   if ( is_wp_error( $validation_result ) ) {
   return $validation_result;
   }
  
   return $file;
}

This function will call the save_base64_to_tmp_file function to save the file :

private function save_base64_to_tmp_file( $file ) {
   $file_content = base64_decode( $file['fileData'] ); // phpcs:ignore
   // If the decode fails
   if ( ! $file_content ) {
   return new \WP_Error( 'file_error', self::INVALID_FILE_CONTENT );
   }
  
   $temp_filename = $this->create_temp_file( $file_content, $file['fileName'] );
  
   if ( is_wp_error( $temp_filename ) ) {
   return $temp_filename;
   }
  
   return [
   // the original uploaded file name
   'name' => $file['fileName'],
   // The path to the temporary file
   'tmp_name' => $temp_filename,
   ];
}

Notice that there is a call to save the $file_content and $file['fileName'] using the create_temp_file function :

public function create_temp_file( $file_content, $file_name ) {
     $temp_filename = $this->create_unique_dir() . $file_name;
     /**
      * Temp File Path
      *
      * Allows modifying the full path of the temporary file.
      *
      * @since 3.7.0
      *
      * @param string full path to file
      */
     $temp_filename = apply_filters( 'elementor/files/temp-file-path', $temp_filename );
  
     file_put_contents( $temp_filename, $file_content ); // phpcs:ignore
  
     return $temp_filename;
}

The file will be saved into the tmp directory under the wp-content/uploads/elementor/tmp path. Note that there is no check on the uploaded $file_name and the file is uploaded directly using the file_put_contents function. With that case, the user could supply a path traversal payload with a .php filename so it will not be saved inside the tmp directory and instead will be saved to the main wp-content/uploads directory for example.

The interesting part is the check on the allowed file extensions using the validate_file function is only performed after the file has already been uploaded.

Note that this vulnerability can be reproduced with the Contributor role on a default installation of the Elementor plugin without any additional conditions or requirements.

The patch

The vulnerability was originally found in version 3.17.3. The Elementor team then decided to release a patch in version 3.18.1. Unfortunately, the patch was incomplete since the team only implemented sanitize_file_name on the $file_name variable.

This patch will prevent the user from saving the file outside the tmp directory, but users are still able to upload arbitrary files such as .php files to the tmp directory. The uploaded file will not be removed from the tmp directory. However, in this condition, the attacker still needs to guess or predict the tmp directory to access the uploaded .php files. The patch on version 3.18.1 can be seen below:

The Elementor then fixes the incomplete patch and releases the fully patched version 3.18.2. In this version, a proper file name and extension check using is_file_type_allowed function is implemented inside the save_base64_to_tmp_file function. The patch can be seen below :

Conclusion

Always check every process of file saving where the content and the file name are fully or partially controlled by the user. Implement both file type and file name checks on the saved file. For the file name check, we recommend using a whitelist check approach, rather than a blacklist approach.

Timeline

27 November, 2023We receive the vulnerability report from Hồng Quân (luk6785 at VNPT-VCI) and reached out to the Elementor security team.
06 December, 2023Elementor version 3.18.1 released with an incomplete patch for the reported issue.
06 December, 2023We notice that 3rd party already publishing the issue. We decide to add the vulnerability to the Patchstack vulnerability database
08 December, 2023Elementor version 3.18.2 released to fully patch the reported issue.
08 December, 2023Security advisory article publicly released.

Help us make the Internet 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