CVE-2026-32475: Unauthenticated RCE in Elementor Pro via File Upload Validation Bypass
CVE-2026-32475 is an unauthenticated arbitrary file upload to RCE in Elementor Pro ( Upload::validation() ). The validation loop iterates over the file array for one field. When the first element has UPLOAD_ERR_NO_FILE (empty filename), the code calls return instead of continue - aborting extension and MIME checks for every remaining file in that field. The mover runs in a separate loop that correctly skips the empty slot and writes the rest. Validator stops early, mover keeps going. Exploit shape (observed in the wild by Wordfence): POST /wp-admin/admin-ajax.php action=elementor_pro_forms_send_form form_fields['field_cc213f9'][0]; filename="" .php (uniqid() output, attacker-supplied .php extension). The upload response does not return the path, so the attacker must first work out the filename - a cheap step Patchstack documents. One GET to the file executes it. No auth, no nonce bypass needed - admin-ajax.php exposes the form handler to unauthenticated callers by design. Credit: Tin Pham (TF1T) reported via Patchstack (Jul 16); Austin Ginder independently reported via the Wordfence Bug Bounty Program (~Jul 24, $15,600 bounty); Wordfence rejected its own CVE in favor of Patchstack's CVE-2026-32475. Precondition (precise): a published page with an Elementor Form widget containing at least one non-required File Upload field. Required is off by default, so most upload fields qualify. Installed-but-no-upload-form = vulnerable code, no reachable entry point for this chain. Check if you are affected # 1. Plugin version (want >= 4.2.2) wp plugin list | grep -i elementor-pro wp plugin get elementor-pro --field=version # 2. Any PHP where there should never be PHP find wp-content/uploads/elementor/forms/ -type f -name "*.php" -ls # Any hit = treat as compromise, not cleanup-and-done # 3. Look for probing in access logs (IP list rotates fast - check the live list in the Wordfence advisory, do not rely on static copies) grep "elementor_pro_forms_send_form" /var/log/nginx/access.log | tail -n 50 Wordfence publishes the live offending-IP list in its advisory - check there rather than any static copy. Absence of matches proves nothing (log rotation, IP churn) - the folder check is authoritative. Fix # Update first - firewall rules are a shield, the patch removes the hole wp plugin update elementor-pro wp plugin get elementor-pro --field=version # confirm 4.2.2+ # Harden the uploads path so the next validation bug buys nothing (defense in depth) # nginx: never execute PHP under the forms upload dir location ^~ /wp-content/uploads/elementor/forms/ { location ~ .php$ { deny all; access_log off; log_not_allowed 1; } } # Apache alternative (.htaccess in wp-content/uploads/elementor/forms/) Require all denied If you run Wordfence Premium, Care, or Response, confirm Firewall -> Global Options -> "Disable Code Execution for Uploads directory" is on - that is what makes its file-access block work. Note the free version of Wordfence receives new firewall rules ~30 days after paid tiers, so free-tier sites had no firewall cover during the Aug 19-23 attack peak: updating was the only immediate protection. Patchstack has a virtual patch for unpatched sites. Either way, update: WAF rules rot, the patch does not. Also worth a pass: wp post list --post_type=page --fields=ID,post_title plus a quick audit of which pages carry Form widgets with upload fields, and whether each one still needs to accept files. Restrict accept to what the workflow needs (PDF/images for applications) and drop upload fields from pages that no longer need them. Why this one stung - 6M+ installs, 190,000+ blocked attempts since Aug 19 disclosure, heaviest Aug 19-23. Same-day weaponization is now normal for internet-facing unauthenticated flaws. - The validator/mover split-loop pattern is a classic: two passes over the same array with different empty-element handling. If you write upload handling, validate and move in one pass, or fuzz the validator with [empty, valid, malicious] permutations. - Duplicate CVE CVE-2026-17590 was rejected - if your scanner flags it, map it to CVE-2026-32475. Technical takeaway: never let validation and file-move disagree on what "empty" means. One loop, continue on empty, allowlist extensions, randomize stored names without preserving the attacker extension, and deny execution in upload dirs at the web server layer. Full prevention-focused version with the shop-owner playbook: WardenBit. Top comments (0)
Comments
No comments yet. Start the discussion.