A blank file entry placed before a PHP upload lets an unauthenticated visitor bypass Elementor Pro’s extension checks and write executable code into a public WordPress directory. Security vendor Patchstack traced CVE-2026-32475 to two loops that read the same multipart request differently.
Elementor Pro 4.2.1 and earlier are affected when a site publishes a Form widget containing a File Upload field. The field does not need to be marked required. A successful request can place PHP on the server and reach remote code execution, yet Patchstack reported no observed exploitation, victims, campaign infrastructure, or incident count.
Public forms expose the path
The vulnerable surface is narrower than every Elementor Pro installation and common enough to merit a direct inventory. Job applications, support forms, and receipt or identity-document submissions often expose the File Upload field on a public page. An attacker needs no account, cookie, or nonce for the elementor_pro_forms_send_form AJAX action described by Patchstack.
The public page supplies the request values needed to address the form: post_id, form_id, and the input name form_fields[{FIELD_ID}]. Those values establish reachability. They do not prove that anyone sent a malicious upload.
Recognition starts with three facts: an affected Elementor Pro version, a published Form widget with File Upload, and a web server willing to execute PHP from the forms upload directory. Teams can inventory the plugin version with WP-CLI:
wp plugin get elementor-pro --field=version
Then review published forms and the server’s handler rules for wp-content/uploads/elementor/forms/. A site without the described form configuration does not expose this request path. Patchstack’s demonstrated consequence depends on the public forms directory accepting a PHP file and the web server executing it when requested.
The sources do not quantify the exposed population. Elementor is a widely used page builder, but neither Patchstack nor Elementor says how many Pro sites combine an affected build with a public File Upload form.
Two loops disagree
Researcher Tin Pham, also known as TF1T, reported the vulnerability through Patchstack. The Forms module handles each upload twice in modules/forms/fields/upload.php: validation() checks file types, then process_field() moves accepted files into storage.
For an optional empty entry with PHP’s UPLOAD_ERR_NO_FILE, the validator executes return. That exits the entire validation method, so later entries never reach is_file_type_valid(). The move loop handles the same empty entry with continue, skipping only that item before processing the next one.
An attacker shapes one field as two multipart entries. Entry zero has a blank filename. Entry one carries PHP. Validation stops at the blank entry, while processing advances to the PHP entry and moves it to disk.
The intended blocklist covers php, php3, php4, php5, php6, phps, php7, phtml, shtml, pht, swf, html, asp, aspx, cmd, csh, bat, htm, hta, jar, exe, and com. Patchstack found that the blocklist itself behaves as designed. The crafted request prevents that check from running on the second entry.
The move step discards the submitted basename, preserves the extension, and creates a name with PHP’s uniqid(). The result lands under:
wp-content/uploads/elementor/forms/<13-hex-character-name>.php
Patchstack summarized the fault plainly: “An empty file part is enough to make the validator and the mover disagree.” Once the server writes that file, requesting its public URL executes the attacker’s PHP with the web service’s privileges.

Figure details
A split-path diagram begins with one multipart File Upload field containing two entries. On the validation path, entry zero has a blank filename and UPLOAD_ERR_NO_FILE, causing validation() to return before entry one reaches the extension blocklist. On the processing path, the same blank entry causes process_field() to continue, so entry one is renamed with a 13-character hexadecimal uniqid value and its PHP extension is preserved. The final node is the public wp-content/uploads/elementor/forms/ directory, where a web request can execute the file. The fixed path in Elementor Pro 4.2.2 makes both loops reject the unchecked entry and rechecks the extension before moving the file.
Stored names remain recoverable
The upload response does not reveal the new filename. That limits a naive attempt but does not make the stored PHP unreachable.
PHP’s uniqid() output is time-derived rather than cryptographically random. Patchstack says the first eight hexadecimal characters encode the Unix second and the next five encode microseconds. The server’s Date response header identifies the second, while the request’s timing narrows the remaining search space.
Some forms disclose the answer directly. Elementor Pro’s default [all-fields] notification includes uploaded fields. When a form also sends an autoresponder to the submitted address, the attacker can receive the complete file URL without searching. That is the report’s most concrete demonstration of how an apparently missing path can become operationally usable.
Patchstack’s evidence establishes the mechanism and consequence. It does not establish in-the-wild use. Defenders therefore have a vulnerability-scoping problem rather than a campaign-specific indicator set: version, form configuration, upload-directory contents, web access logs, mail actions, and process activity are the available evidence.
Prove patch and clean disk
Elementor’s changelog lists version 4.2.2, released August 19, with “Improved code security enforcement in Form widget.” Patchstack says the release makes the loops agree on empty entries and adds an extension check immediately before the move operation. Version 4.2.2 supersedes affected 4.2.1 and earlier releases; a later Elementor Pro version also carries the remediation unless Elementor documents a regression.
Patchstack sells virtual-patching services and says its customers received a mitigation rule, so that protection claim evaluates its own product. The vendor response is independently visible in Elementor’s release record. Patchstack’s disclosure timeline says Elementor prepared the code change on July 17, Patchstack confirmed it on August 3, and Elementor shipped it on August 19.
Upgrading blocks future use of this path. It does not remove a file written before the fix. Review the directory for executable extensions and compare every result with deployment, backup, and incident records:
find wp-content/uploads/elementor/forms -type f \
\( -iname '*.php' -o -iname '*.php3' -o -iname '*.php4' \
-o -iname '*.php5' -o -iname '*.php6' -o -iname '*.php7' \
-o -iname '*.phps' -o -iname '*.phtml' -o -iname '*.pht' \) \
-print
Also search web access logs for requests to /wp-content/uploads/elementor/forms/ whose final segment matches 13 hexadecimal characters followed by an executable PHP-family extension. Correlate any hit with form submissions, the elementor_pro_forms_send_form action, outbound mail records, and web-server child processes. A file or request in that path warrants investigation; the path itself is normal Elementor Pro storage.
The verification test has two expected results. wp plugin get elementor-pro --field=version should report 4.2.2 or later, and the executable-file search should return no unexplained files. A clean version closes the vulnerable request path. Clean disk and retained telemetry determine whether the site also escaped the period before remediation.
