2026-08-28 · view entry permalink →
Elementor Pro (WordPress): unauthenticated arbitrary file upload to RCE via a validator/mover desynchronization in the Forms File Upload field (CVE-2026-32475, CVSS 9.0)
CVE-2026-32475 (CVSS 9.0) affects Elementor Pro ≤4.2.1, fixed in 4.2.2 (patched 19 August, patch reviewed and confirmed effective by Patchstack). The Forms module's File Upload field (modules/forms/fields/upload.php) validates an upload's extension in one loop (validation()) and moves accepted files to a public directory in a separate loop (process_field()) — and the two loops disagree about what an empty file entry (UPLOAD_ERR_NO_FILE) means. validation() does if (!required && UPLOAD_ERR_NO_FILE) return; — an empty first entry makes it abandon checking the entire field, including every later entry. process_field() instead does if (UPLOAD_ERR_NO_FILE) continue; — it skips only the empty entry and still moves everything after it: "an empty first entry makes validation() return before it ever type-checks the .php entry that follows it. process_field(), meanwhile, only continues past that empty entry and moves the .php one anyway. The validator reports a clean submission because it stopped reading; the mover proceeds because it did not" (Patchstack, 2026-08-19).
Submitting two file parts for one File Upload field — an empty first part, then a .php payload as the second — makes the validator report a clean submission (it stopped reading before reaching the .php entry) while the mover still processes and moves that .php file. The blocklist check (is_file_type_valid(), which does correctly reject php/phtml/asp/etc.) never runs against the payload at all: "the .php file lands in wp-content/uploads/elementor/forms/, a public, web-accessible directory, letting a fully unauthenticated visitor place executable PHP on the server and, by requesting the file directly, achieve remote code execution" (Patchstack, 2026-08-19).
The only prerequisite is any published Elementor page containing a Form widget with a File Upload field (Required toggle off by default) — an everyday configuration such as a job-application, support-ticket, or "attach a document" form. Every value the exploit needs (post_id, form_id, the field's form_fields[ID] name) is visible in the page's public HTML, and the request goes through the elementor_pro_forms_send_form AJAX action with no cookie or nonce required. Recovering the stored filename — always uniqid().extension, discarding the submitted name — is cheap: the 8 hex "seconds" digits come straight from the server's own Date: response header, leaving only 5 hex microsecond digits to brute-force, or, on forms with an autoresponder email action enabled (common on the same job-application/support-ticket forms), Elementor's own default notification template discloses the exact upload URL to the attacker-controlled email address with zero brute-forcing. The fix in 4.2.2 synchronizes the two loops' empty-entry handling and additionally re-checks the extension inside process_field() itself, immediately before the move, so the blocklist now guards the sink directly.
Triage: any .php (or other server-executable) file under wp-content/uploads/elementor/forms/ is a compromise indicator regardless of current patch level. On the request side, form submissions to elementor_pro_forms_send_form carrying multiple file parts for a single File Upload field — one empty, one non-empty — are the delivery shape; a legitimate single-file upload never needs a leading empty part, so its presence has no benign explanation.
An empty first entry makes validation() return before it ever type-checks the .php entry that follows it. process_field(), meanwhile, only continues past that empty entry and moves the .php one anyway. The validator reports a clean submission because it stopped reading; the mover proceeds because it did not.
The .php file lands in wp-content/uploads/elementor/forms/, a public, web-accessible directory, letting a fully unauthenticated visitor place executable PHP on the server and, by requesting the file directly, achieve remote code execution.