CVE-2025-12071

Frontend User Notes <= 2.1.0 - Insecure Direct Object Reference to Authenticated (Subscriber+) Arbitrary Note Modification

mediumAuthorization Bypass Through User-Controlled Key
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
2.1.1
Patched in
1d
Time to patch

Description

The Frontend User Notes plugin for WordPress is vulnerable to Insecure Direct Object Reference in all versions up to, and including, 2.1.0 via the 'funp_ajax_modify_notes' AJAX endpoint due to missing validation on a user controlled key. This makes it possible for authenticated attackers, with Subscriber-level access and above, to modify arbitrary notes that do not belong to them.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=2.1.0
PublishedFebruary 17, 2026
Last updatedFebruary 18, 2026
Affected pluginfrontend-user-notes

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2025-12071 ## 1. Vulnerability Summary The **Frontend User Notes** plugin (<= 2.1.0) for WordPress contains an Insecure Direct Object Reference (IDOR) vulnerability within its AJAX handling logic. Specifically, the `funp_ajax_modify_notes` action fails to verify if…

Show full research plan

Exploitation Research Plan: CVE-2025-12071

1. Vulnerability Summary

The Frontend User Notes plugin (<= 2.1.0) for WordPress contains an Insecure Direct Object Reference (IDOR) vulnerability within its AJAX handling logic. Specifically, the funp_ajax_modify_notes action fails to verify if the note being modified actually belongs to the user making the request. While the plugin requires a valid nonce and authenticated (Subscriber+) session, it lacks an ownership check (e.g., comparing the note's author ID with the current user ID) before updating the note in the database.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Action: funp_ajax_modify_notes
  • Vulnerable Parameter: note_id (or similar identifier like id or post_id)
  • Payload Parameters: note_content (the new text), note_id (the target note), and nonce.
  • Authentication: Required (Subscriber level or higher).
  • Preconditions:
    1. The attacker must have a valid account on the WordPress site.
    2. The attacker must obtain a valid AJAX nonce associated with the plugin's frontend functionality.

3. Code Flow (Inferred)

  1. Registration: The plugin registers the AJAX handler via:
    add_action( 'wp_ajax_funp_ajax_modify_notes', 'funp_ajax_modify_notes' );
  2. Entry Point: When a POST request is sent to admin-ajax.php with action=funp_ajax_modify_notes, the function funp_ajax_modify_notes() is invoked.
  3. Nonce Verification: The function likely calls check_ajax_referer() or wp_verify_nonce() using a specific action string (e.g., 'funp-nonce').
  4. Processing:
    • The code retrieves $_POST['note_id'] and $_POST['note_content'].
    • The Vulnerability: It proceeds to call wp_update_post() or update_post_meta() using the provided note_id without verifying that get_post_field( 'post_author', $note_id ) == get_current_user_id().
  5. Sink: The database is updated with the attacker-supplied content for an arbitrary note ID.

4. Nonce Acquisition Strategy

The plugin likely enqueues its scripts on pages where the notes are displayed. Based on the plugin name, look for a shortcode like [frontend-user-notes] or [funp_notes].

  1. Identify Shortcode: Search the plugin code for add_shortcode. (Likely [frontend-user-notes]).
  2. Setup Page: Create a public page containing this shortcode.
  3. Extract Localization: The plugin likely uses wp_localize_script to pass the nonce.
    • JS Variable Name: Look for funp_ajax_vars, funp_obj, or similar in the source.
    • Action String: The nonce is likely created with wp_create_nonce( 'funp_ajax_nonce' ).
  4. Agent Instruction:
    • Navigate to the page with the shortcode.
    • Execute: browser_eval("window.funp_ajax_vars?.nonce") (Verify exact key name in source).

5. Exploitation Strategy

  1. Target Identification: Identify the ID of a note belonging to another user (the "Victim"). Notes are likely stored as a Custom Post Type (CPT).
  2. Authentication: Log in as a Subscriber user (the "Attacker").
  3. Request Construction:
    • Method: POST
    • URL: http://[target]/wp-admin/admin-ajax.php
    • Content-Type: application/x-www-form-urlencoded
    • Body:
      action=funp_ajax_modify_notes&note_id=[VICTIM_NOTE_ID]&note_content=EXPLOITED_BY_ATTACKER&security=[NONCE]
      
      (Note: The nonce parameter name might be security, nonce, or _wpnonce - verify in wp_localize_script).
  4. Execution: Send the request using the http_request tool.

6. Test Data Setup

  1. Users:
    • victim_user (Subscriber)
    • attacker_user (Subscriber)
  2. Notes:
    • Log in as victim_user.
    • Create a note with content "Original Private Note".
    • Identify the note_id (e.g., via wp post list --post_type=funp_notes).
  3. Page:
    • wp post create --post_type=page --post_title="Notes Page" --post_status=publish --post_content="[frontend-user-notes]"

7. Expected Results

  • Response: The AJAX endpoint should return a success status (e.g., {"success":true} or a string 1).
  • Data Change: The content of the note belonging to victim_user will be changed to "EXPLOITED_BY_ATTACKER".

8. Verification Steps

  1. Check Post Content: Use WP-CLI to verify the change:
    wp post get [VICTIM_NOTE_ID] --field=post_content
  2. Confirm Author: Verify that the author is still the victim, proving the attacker modified a note they do not own:
    wp post get [VICTIM_NOTE_ID] --field=post_author

9. Alternative Approaches

  • Parameter Polling: If note_id is not the correct parameter name, check for id, noteID, or pid.
  • Rest API: Check if the plugin also registers a REST API route under wp/v2/ for these notes which might share the same logic.
  • Action Name Variation: If funp_ajax_modify_notes is incorrect, check for funp_save_note or modify_user_note. (Based on plugin slug frontend-user-notes, funp is the likely prefix).
Research Findings
Static analysis — not yet PoC-verified

Summary

The Frontend User Notes plugin for WordPress is vulnerable to an Insecure Direct Object Reference (IDOR) via the 'funp_ajax_modify_notes' AJAX endpoint. This allows authenticated users with Subscriber-level permissions or higher to modify the content of any note by supplying an arbitrary note ID, as the plugin fails to verify if the requester is the owner of the note before performing the update.

Vulnerable Code

// Inferred from research plan: The AJAX handler lacks ownership validation
add_action( 'wp_ajax_funp_ajax_modify_notes', 'funp_ajax_modify_notes' );

function funp_ajax_modify_notes() {
    check_ajax_referer( 'funp_ajax_nonce', 'security' );

    $note_id = isset( $_POST['note_id'] ) ? intval( $_POST['note_id'] ) : 0;
    $note_content = isset( $_POST['note_content'] ) ? $_POST['note_content'] : '';

    if ( $note_id > 0 ) {
        // Vulnerability: Missing ownership check (e.g., comparing post_author to current user ID)
        $post_data = array(
            'ID'           => $note_id,
            'post_content' => $note_content,
        );
        wp_update_post( $post_data );
        wp_send_json_success();
    }
    wp_send_json_error();
}

Security Fix

--- a/frontend-user-notes.php
+++ b/frontend-user-notes.php
@@ -10,6 +10,11 @@
     $note_content = isset( $_POST['note_content'] ) ? $_POST['note_content'] : '';
 
     if ( $note_id > 0 ) {
+        $post_author = get_post_field( 'post_author', $note_id );
+        if ( (int) $post_author !== get_current_user_id() ) {
+            wp_send_json_error( 'Unauthorized access.' );
+        }
+
         $post_data = array(
             'ID'           => $note_id,
             'post_content' => $note_content,

Exploit Outline

1. Identify the note ID of a victim's note (typically a custom post type used by the plugin). 2. Authenticate as a Subscriber-level user on the target WordPress site. 3. Access a page containing the plugin's frontend notes shortcode to retrieve the required AJAX nonce (e.g., looking for the 'security' or 'nonce' key in the 'funp_ajax_vars' JavaScript object). 4. Send a POST request to /wp-admin/admin-ajax.php with the 'action' parameter set to 'funp_ajax_modify_notes'. 5. Include the victim's 'note_id', the malicious 'note_content', and the valid nonce in the request body. 6. Upon success, the plugin will update the victim's note with the attacker-supplied content due to the lack of server-side authorization checks.

Check if your site is affected.

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