CVE-2025-14047

WP User Frontend <= 4.2.4 - Missing Authorization to Unauthenticated Arbitrary Attachment Deletion

mediumMissing Authorization
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
4.2.5
Patched in
22d
Time to patch

Description

The Registration, User Profile, Membership, Content Restriction, User Directory, and Frontend Post Submission – WP User Frontend plugin for WordPress is vulnerable to unauthorized loss of data due to a missing capability check on the 'Frontend_Form_Ajax::submit_post' function in all versions up to, and including, 4.2.4. This makes it possible for unauthenticated attackers to delete attachment.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Unchanged
None
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=4.2.4
PublishedJanuary 1, 2026
Last updatedJanuary 23, 2026
Affected pluginwp-user-frontend

What Changed in the Fix

Changes introduced in v4.2.5

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan - CVE-2025-14047 ## 1. Vulnerability Summary The **WP User Frontend** plugin (versions <= 4.2.4) is vulnerable to **Unauthenticated Arbitrary Attachment Deletion**. The vulnerability exists in the `Frontend_Form_Ajax::submit_post` function, which handles AJAX requests f…

Show full research plan

Exploitation Research Plan - CVE-2025-14047

1. Vulnerability Summary

The WP User Frontend plugin (versions <= 4.2.4) is vulnerable to Unauthenticated Arbitrary Attachment Deletion. The vulnerability exists in the Frontend_Form_Ajax::submit_post function, which handles AJAX requests for post submissions. Due to a missing authorization check (capability check) and lack of ownership validation for attachment IDs passed in the request, an unauthenticated attacker can delete any media attachment on the WordPress site by providing its ID.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Action: wpuf_submit_post (registered for both authenticated and unauthenticated users)
  • Authentication: None required (unprivileged/unauthenticated).
  • Vulnerable Parameter: del_attachments[] (inferred based on standard WPUF AJAX handling of file removals during form submission).
  • Preconditions:
    1. A WPUF "Post Form" must be created and published on a page via shortcode.
    2. The attacker must know or guess the ID of the target attachment.

3. Code Flow

  1. Entry Point: An unauthenticated user sends a POST request to admin-ajax.php with action=wpuf_submit_post.
  2. Hook Registration: The plugin registers the action in includes/frontend/class-frontend-form-ajax.php (inferred path):
    add_action( 'wp_ajax_nopriv_wpuf_submit_post', [ $this, 'submit_post' ] );
  3. Function Execution: Frontend_Form_Ajax::submit_post() is called.
  4. Nonce Verification: The function checks the _wpnonce parameter against the action 'wpuf_form_add' or similar (likely localized in the form HTML).
  5. Processing Deletions: The logic iterates through the submitted data. If a parameter representing attachments to be deleted is present (e.g., del_attachments), the code processes each ID.
  6. Sink: The function calls wp_delete_attachment( $attachment_id, true ) for each provided ID.
  7. The Flaw: The code fails to verify if the user submitting the form has the delete_posts capability or if they are the owner of the attachment being deleted.

4. Nonce Acquisition Strategy

Nonces for WPUF forms are generated per-form and localized or placed in hidden inputs.

  1. Identify the Form: Find a page containing the WPUF form shortcode: [wpuf_form id="<form_id>"].
  2. Locate Nonce:
    • The nonce is typically in a hidden input field: <input type="hidden" name="_wpnonce" value="...">.
    • Alternatively, check the JavaScript localization object wpuf_frontend or wpuf_form_builder.
  3. Automated Extraction:
    • Use browser_navigate to the page where the form is hosted.
    • Use browser_eval to extract the nonce:
      // Check hidden field first
      document.querySelector('input[name="_wpnonce"]')?.value || 
      // Check localized object
      window.wpuf_frontend?.nonce
      

5. Exploitation Strategy

Step 1: Target Identification

Identify a target attachment ID (e.g., 123) that belongs to the administrator or is a sensitive site asset.

Step 2: Form Discovery

Identify a public-facing page with a WPUF form and its corresponding form_id.

Step 3: Payload Construction

Construct a multipart/form-data or application/x-www-form-urlencoded POST request.

Payload Structure:

  • action: wpuf_submit_post
  • form_id: <ID_OF_THE_FORM>
  • _wpnonce: <EXTRACTED_NONCE>
  • del_attachments[]: <TARGET_ATTACHMENT_ID>
  • wpuf_form_status: new (inferred)

Step 4: Execution

Send the request using the http_request tool.

# Example HTTP request via agent
http_request(
    url="http://localhost:8080/wp-admin/admin-ajax.php",
    method="POST",
    headers={"Content-Type": "application/x-www-form-urlencoded"},
    body="action=wpuf_submit_post&form_id=100&_wpnonce=abcdef1234&del_attachments[]=123"
)

6. Test Data Setup

  1. Target Attachment: Use WP-CLI to upload an image as an admin:
    wp media import /path/to/image.png --title="Victim Asset" --porcelain (Note the returned ID).
  2. WPUF Form: Create a basic "Post" form in WPUF settings.
  3. Public Page: Create a page and embed the form:
    wp post create --post_type=page --post_title="Submit News" --post_status=publish --post_content='[wpuf_form id="100"]'

7. Expected Results

  • HTTP Response: The server returns a JSON success message (e.g., {"success":true,...}) or redirects, even if the attachment deletion happens silently in the background.
  • Filesystem: The file associated with the target ID in wp-content/uploads/ is deleted.
  • Database: The post with ID = <TARGET_ATTACHMENT_ID> is removed from the wp_posts table.

8. Verification Steps

After the exploit, verify the deletion using WP-CLI:

  1. Check Post Existence:
    wp post exists <TARGET_ATTACHMENT_ID>
    Expected Output: Empty/Error (Exit code 1).
  2. Verify Media List:
    wp media list --post_id=<TARGET_ATTACHMENT_ID>
    Expected Output: No results.

9. Alternative Approaches

If del_attachments[] is not the correct parameter name, analyze the Frontend_Form_Ajax class in includes/frontend/class-frontend-form-ajax.php (or similar) to identify the specific array key used to process attachment deletions within submit_post. Look for calls to:

  • wp_delete_attachment
  • wp_delete_post
  • Any loop iterating over $_POST keys involving the string "attach" or "file".
Research Findings
Static analysis — not yet PoC-verified

Summary

The WP User Frontend plugin for WordPress is vulnerable to unauthenticated arbitrary attachment deletion in versions up to and including 4.2.4. This occurs due to a missing authorization check and ownership validation in the 'submit_post' AJAX handler, allowing anyone to delete media files by providing their attachment IDs.

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/wp-user-frontend/4.2.4/admin/form-builder/views/form-builder-v4.1.php /home/deploy/wp-safety.org/data/plugin-versions/wp-user-frontend/4.2.5/admin/form-builder/views/form-builder-v4.1.php
--- /home/deploy/wp-safety.org/data/plugin-versions/wp-user-frontend/4.2.4/admin/form-builder/views/form-builder-v4.1.php	2025-03-20 10:31:02.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/wp-user-frontend/4.2.5/admin/form-builder/views/form-builder-v4.1.php	2026-01-01 05:51:18.000000000 +0000
@@ -5,7 +5,7 @@
     <div class="wpuf-bg-white wpuf-p-8 wpuf-justify-between wpuf-items-center wpuf-pb-7">
         <div class="wpuf-flex wpuf-justify-between">
             <div class="wpuf-flex">
-                <img src="<?php echo WPUF_ASSET_URI . '/images/wpuf-icon-circle.svg'; ?>" alt="WPUF Icon" class="wpuf-mr-2">
+                <img src="<?php echo esc_url( WPUF_ASSET_URI . '/images/wpuf-icon-circle.svg' ); ?>" alt="WPUF Icon" class="wpuf-mr-2">
                 <nav class="wpuf-flex wpuf-items-center" aria-label="Tabs">
                     <div class="wpuf-relative wpuf-flex">
                         <div class="wpuf-flex wpuf-items-center">
@@ -56,10 +56,15 @@
                 if ( count( $shortcodes ) > 1 && isset( $shortcodes[0]['type'] ) ) {
                     foreach ( $shortcodes as $shortcode ) {
                         ?>
+                        <?php
+                        // translators: %s is the shortcode type (e.g., form, post, profile)
+                        $title = sprintf( __( 'Click to copy %s shortcode', 'wp-user-frontend' ), esc_attr( $shortcode['type'] ) );
+                        $clipboard = sprintf( '[%s type="%s" id="%s"]', $shortcode['name'], esc_attr( $shortcode['type'] ), esc_attr( $form_id ) );
+                        ?>
                         <span
                             class="form-id wpuf-group wpuf-flex wpuf-items-center wpuf-px-[18px] wpuf-py-[10px] wpuf-rounded-md wpuf-border wpuf-border-gray-300 hover:wpuf-cursor-pointer wpuf-ml-6 wpuf-text-gray-700 wpuf-text-base wpuf-leading-none wpuf-shadow-sm"
-                            title="<?php printf( esc_attr( __( 'Click to copy %s shortcode', 'wp-user-frontend' ) ), $shortcode['type'] ); ?>"
-                            data-clipboard-text="<?php printf( esc_attr( '[' . $shortcode['name'] . ' type="' . esc_attr( $shortcode['type'] ) . '" id="' . esc_attr( $form_id ) . '"]' ) ); ?>"><?php echo esc_attr( ucwords( $shortcode['type'] ) ); ?>: #{{ post.ID }}
+                            title="<?php echo esc_attr( $title ); ?>"
+                            data-clipboard-text="<?php echo esc_attr( $clipboard ); ?>"><?php echo esc_attr( ucwords( $shortcode['type'] ) ); ?>: #{{ post.ID }}

Exploit Outline

The exploit targets the 'wpuf_submit_post' AJAX action. An unauthenticated attacker first obtains a valid form nonce (usually '_wpnonce') from the HTML or localized JavaScript of any page featuring a WP User Frontend form. The attacker then sends a POST request to '/wp-admin/admin-ajax.php' with the 'action' set to 'wpuf_submit_post', the 'form_id' of the active form, and the target attachment ID(s) passed via the 'del_attachments[]' parameter. Since the server-side function 'Frontend_Form_Ajax::submit_post' fails to verify if the user has permissions to delete the file or is the file's owner, it proceeds to call 'wp_delete_attachment()' on the specified IDs, effectively deleting arbitrary media from the site.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.