Critical Vulnerability in Elementor Affecting 5+ Million Websites

Published 8 December 2023
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.

✌️ Our users are protected from this vulnerability. Are yours?

Web developers

Automatically mitigate vulnerabilities in real-time without changing code.

See pricing
Plugin developers

Identify vulnerabilities in your plugins and get recommendations for fixes.

Request audit
Hosting companies

Protect your users, improve server health and earn additional revenue.

Patchstack for hosts

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.

🤝 You can help us make the Internet a safer place

Plugin developer?

Streamline your disclosure process to fix vulnerabilities faster and comply with CRA.

Get started for free
Hosting company?

Protect your users too! Improve server health and earn added revenue with proactive security.

Patchstack for hosts
Security researcher?

Report vulnerabilities to our gamified bug bounty program to earn monthly cash rewards.

Learn more

The latest in Security Advisories

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