Unrestricted File Upload Vulnerability found in Contact Form 7 plugin affects 5M+ websites

CVE-2020-35489: Unrestricted File Upload Vulnerability found in Contact Form 7 plugin affects 5M+ websites

A high-severity Unrestricted File Upload vulnerability, tracked as CVE-2020–35489, was discovered in a popular WordPress plugin called Contact Form 7, currently installed on 5 Million+ websites making them vulnerable to attacks like phishing, complete site take-over, data-breach, phishing and credit card frauds.

In this blog-post, we will cover what caused the flaw, an example Proof-Of-Concept (PoC) showing exploitation in a sandbox environment, and mitigation steps.

What is the Contact Form 7 Plugin ?

To quote the official documentation of the plugin,

Contact Form 7 can manage multiple contact forms, plus you can customize the form and the mail contents flexibly with simple markup.

What is the vulnerability and how does it work ?

The National Vulnerability Database (NVD) describes CVE-2020–35489 as,

The contact-form-7 (aka Contact Form 7) plugin before 5.3.2 for WordPress allows Unrestricted File Upload and remote code execution because a filename may contain special characters.

I will explain this in 4 simple steps:

  1. The plugin allows the WP admin to create contact forms on their website where a visitor could enter contact details for purposes like feedback or support.
  2. If a malicious user were to upload a file with filename containing double-extensions, separated by a non-printable or special character, for example a file called test.php .jpg (\t character is the separator).
  3. Then Contact Form 7 does not remove special characters from the uploaded filename and parses the filename up till the first extension but discard the second one due to the separator. Thus, the final filename would become test.php (See the image below).
  4. This file could be accessed or executed on the server via Remote Code Execution.
Contact Form 7’s source code on GitHub

Therefore, successful exploitation of the CVE-2020–35498 can have damaging impact on your website which will learn about in a later section of this article.

Proof of Concept (PoC)

Note: We cannot publicly disclose the technical details/exploit because the official PoC is yet to be released; specifically on 31st December 2020 — to provider users the ample time to update.

Here, I am going to do a local setup of WordPress to show a Proof-of-Concept exploitation. I will use Contact Form 7 v5.3.1 to show the vulnerability since the bug has been patched in version 5.3.2 that was realsed on 17th December 2020.


  1. We download, import, install, and then activate the plugin.
Contact Form 7 plugin installed and activated

2. Now we go into the “Contact” tab from the sidebar and create a new form by clicking on the “Add New” button,

3. For the sake of this demo, we will create a “Job Application Form” which will have a file upload field for the applicant’s resume.

4. Finally add this form to a page and publish it.

Attack Scenario

Now here’s where it gets fun, we visit the newly created page and submit the form with a file having filename exploit.php .jpg in the file upload field,

our malicious file gets uploaded to the server successfully

Clicking on “Submit”, we get a positive reply from the web-server indicating that the given file was successfully uploaded as exploit.php. This file can be accessed or executed on the server through Arbitrary Code Execution.

The default upload path is wp-content/uploads but can be changed with the define WPCF7_UPLOADS_TMP_DIR like this:

define( 'WPCF7_UPLOADS_TMP_DIR', '/your/file/path' );


By exploiting this vulnerability, attackers could simply upload files of any type, bypassing all restrictions placed regarding the allowed upload-able file types on a website. The consequences of which can be,

  • Takeover of the complete website
  • Malware injection for stealing credit card information, redirecting visitors to malicious pages
  • Website Defacement via phishing
  • an overloaded file system or database
  • insert backdoors like Phpsploit

To learn more, you can read this detailed article by OWASP on vulnerabilities related to the uploading of malicious files.

How to resolve this Contact Form 7 vulnerability?

This is very simple. Navigate to your WordPress plugin section and update the plugin to the newest version — 5.3.2 (at the time of writing this blog).
We would also recommend scanning and monitoring your WordPress website with our WordPress Security Vulnerability Scanner WPSec. Example of the output when running WPSec:

Output when running a free scan on wpsec.com

Vulnerabilities similar to this are found often. As such we recommend all users to keep on top of updates either by updating manually, or by activating automatic updates.

You should also disable PHP-code execution in the uploads folder. For Nginx you can add the following lines to the configuration file:

location ^~ /wp-content/uploads/ {

When it comes to the Apache Webserver we do not recommend placing a .htaccess file in the uploads-folder for preventing PHP-code execution, since the attacker can most probably overwrite this file using the above vulnerability. Instead use the Apache configuration file to block execution, but this might be a problem on shared hosting environments. Also set AllowOverride to None preventing .htaccess files to overwrite the settings.

Sign Up >

Blog post written by WPSec Security Researcher Eshaan Bansal and was found by Jinson Varghese.

6 thoughts on “CVE-2020-35489: Unrestricted File Upload Vulnerability found in Contact Form 7 plugin affects 5M+ websites”

  1. Pingback: 12月24日每日安全热点 - 软件供应链来源攻击分析报告 - 安全客,安全资讯平台

  2. Pingback: 12月24日每日安全热点 – 软件供应链来源攻击分析报告-中国宏阔黑客联盟|白帽黑客|网络渗透技术|网站安全|移动安全|通信安全

  3. Pingback: Contact Form 7 WordPress Plugin Vulnerability (CVE-2020-35489) | World-class cloud from India | High performance cloud infrastructure | E2E CloudWorld-class cloud from India | High performance cloud infrastructure | E2E Cloud

  4. Pingback: IT Security News Bulletin #52 | Ptrace Security GmbH

  5. The PoC does not work in a test setup here. I installed the old version because a client has the old plugin on a forgotten site of theirs, but it doesn’t seem like this could ever work, at least not with something simple like a tab, newline, or null byte between the two extensions. I used a default setup (I basically did apt install wordpress and installed the plugin, no other config set).

    – The upload directory has a ‘deny to all’ htaccess file, so the exploit php script could never be run by any web user.

    – If we changed the uploads directory for some reason: the file is removed in the same request, presumably after emailing the admin (not that I receive an email because I didn’t configure an smtp server). Could you race it? No because it uses a random 10-digit directory name (brute-forceable offline perhaps, but over the network within about a millisecond is very implausible).

    – Pretending the above is not an obstacle (I die() the request after processing so that the file is not removed): wp_unique_filename() is called which calls sanitize_file_name() which replaces \t with a harmless hyphen (-). This WordPress code hasn’t changed since the WP version that was current at the time that this blog post was released.

    – Pretending the above is not an obstacle (I commented out the wp_unique_filename function): it will just write the special character literally to the filesystem, so you end up with an uploaded file named exploit.php\t.png, which the web server would not run through the PHP interpreter (i.e. it’s not executable). Alternatively, with a null byte which would be illegal on the filesystem, the hardcoded filename whitelist will trigger because exploit.php\0.png matches /\.php/i (namely in wpcf7_antiscript_file_name()).

    I am left wondering whether this vulnerability was ever real, or under what circumstances this could have been exploitable. Perhaps I’m not thinking of the right character, i.e. the blog post above is purposefully broken to thwart scripkiddies and the magic character is not as simple as \t or \0 (maybe some unicode confusion, I don’t know), but even then there are multiple obstacles to this actually working.

    Was this ever real? If yes, can you at least confirm that the “proof” of concept above will indeed not work and I’m not simply being stupid here? (Or even better, share the real proof of concept, since it has been more than six months now, though I understand if you think there are still too many active installs.)

Leave a Comment

Your email address will not be published. Required fields are marked *