CVE-2026-32523

WPJAM Basic <= 6.9.2 - Authenticated (Subscriber+) Arbitrary File Upload

highUnrestricted Upload of File with Dangerous Type
8.8
CVSS Score
8.8
CVSS Score
high
Severity
6.9.2.1
Patched in
8d
Time to patch

Description

The WPJAM Basic plugin for WordPress is vulnerable to arbitrary file uploads due to missing file type validation in all versions up to, and including, 6.9.2. This makes it possible for authenticated attackers, with Subscriber-level access and above, to upload arbitrary files on the affected site's server which may make remote code execution possible.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=6.9.2
PublishedMarch 20, 2026
Last updatedMarch 27, 2026
Affected pluginwpjam-basic
Research Plan
Unverified

This research plan targets the Arbitrary File Upload vulnerability in **WPJAM Basic <= 6.9.2** (CVE-2026-32523). WPJAM Basic is a framework plugin that provides standardized AJAX and form-handling capabilities. The vulnerability exists because the plugin's centralized file upload handler fails to …

Show full research plan

This research plan targets the Arbitrary File Upload vulnerability in WPJAM Basic <= 6.9.2 (CVE-2026-32523).

WPJAM Basic is a framework plugin that provides standardized AJAX and form-handling capabilities. The vulnerability exists because the plugin's centralized file upload handler fails to adequately restrict file extensions, and the AJAX endpoint is accessible to any authenticated user (Subscriber level).


1. Vulnerability Summary

  • Vulnerability: Unrestricted File Upload.
  • Vulnerable Component: The AJAX handler for the action wpjam-upload.
  • Root Cause: The wpjam_upload_file (inferred) function or the class handling wpjam-upload AJAX requests does not perform strict whitelist validation on file extensions before moving the file to a web-accessible directory.
  • Impact: Remote Code Execution (RCE) via a PHP web shell.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Action: wpjam-upload (inferred based on WPJAM framework patterns).
  • Method: POST (multipart/form-data).
  • Authentication: Authenticated, Subscriber level or higher.
  • Parameters:
    • action: wpjam-upload
    • nonce: A valid WPJAM AJAX nonce.
    • file: The multipart file payload.
    • type: (Optional/Inferred) May be required by the framework to specify the upload context (e.g., image, file).

3. Code Flow (Inferred)

  1. Entry Point: add_action('wp_ajax_wpjam-upload', ...) is registered.
  2. Nonce Verification: The handler calls check_ajax_referer('wpjam-upload', 'nonce') or check_ajax_referer('wpjam-common', 'nonce').
  3. Capability Check: The handler likely lacks a current_user_can('upload_files') check, defaulting to any logged-in user or checking only a basic capability like read.
  4. Upload Handling: The handler processes $_FILES['file']. It may use a custom function or a wrapper around wp_handle_upload where the test_type parameter is set to false or the mimes whitelist is bypassed/empty.
  5. Sink: The file is moved to wp-content/uploads/wpjam/ or a similar sub-path using move_uploaded_file or rename.

4. Nonce Acquisition Strategy

WPJAM Basic enqueues its core scripts for most logged-in users in the WordPress admin dashboard. The nonces are localized into a global JavaScript object.

  • Page to Visit: /wp-admin/index.php (as a Subscriber).
  • Localization Key: wpjam_vars (standard for this plugin).
  • Nonce Key: nonce (or sometimes _ajax_nonce).
  • Action String: Likely wpjam-upload or a general wpjam-common action.
  • Strategy:
    1. Login as a Subscriber.
    2. Navigate to /wp-admin/index.php.
    3. Execute browser_eval("wpjam_vars.nonce") to retrieve the token.

5. Exploitation Strategy

Step 1: Authentication and Nonce Extraction

Use the browser tool to log in as a Subscriber and extract the nonce.

Step 2: Upload Web Shell

Send a multipart POST request to admin-ajax.php.

  • URL: http://localhost:8080/wp-admin/admin-ajax.php
  • Headers: Content-Type: multipart/form-data
  • Body Parameters:
    • action: wpjam-upload
    • nonce: [EXTRACTED_NONCE]
    • file: (Content of info.php: <?php phpinfo(); ?>, Filename: info.php, Content-Type: application/x-php)

Step 3: Identify Upload Path

The response from WPJAM's upload handler typically returns a JSON object containing the URL or relative path of the uploaded file.

  • Example Success Response: {"success":true,"data":{"url":"http:\/\/localhost:8080\/wp-content\/uploads\/wpjam\/2023\/10\/info.php", ...}}

Step 4: Trigger Execution

Navigate to the URL provided in the JSON response using http_request.

6. Test Data Setup

  1. User: Create a Subscriber user.
    • wp user create attacker attacker@example.com --role=subscriber --user_pass=password
  2. Plugin Status: Ensure wpjam-basic version 6.9.2 is active.
    • wp plugin activate wpjam-basic

7. Expected Results

  • The upload request returns {"success":true, ...}.
  • The data.url (or equivalent) in the response points to a .php file in the uploads directory.
  • Accessing the uploaded PHP file returns the output of phpinfo().

8. Verification Steps

  1. List Files: Use ls -R /var/www/html/wp-content/uploads/wpjam/ to verify the file exists on disk.
  2. WP-CLI Check: Verify the file was not blocked by checking the last uploaded file in the database if it was registered as an attachment (unlikely for this specific vulnerability, but possible):
    • wp post list --post_type=attachment --posts_per_page=1

9. Alternative Approaches

  • Different Actions: If wpjam-upload is not the correct action, search the source for wp_ajax_wpjam- to find other registered handlers. Common ones include wpjam-action with a wpjam_action=upload parameter.
  • MIME Bypass: If there is a basic MIME check, try naming the file info.php but setting the Content-Type header to image/jpeg.
  • Path Discovery: If the response does not return the URL, check /wp-content/uploads/wpjam/ (standard) or /wp-content/uploads/temp/ (intermediate). Files are often organized by year/month.
Research Findings
Static analysis — not yet PoC-verified

Summary

The WPJAM Basic plugin for WordPress is vulnerable to arbitrary file uploads in versions up to 6.9.2 because its centralized AJAX upload handler lacks both capability checks and file extension validation. Authenticated attackers with Subscriber-level permissions can upload PHP files to the server via the 'wpjam-upload' action, leading to remote code execution.

Vulnerable Code

// wpjam-basic/public/wpjam-functions.php

add_action('wp_ajax_wpjam-upload', 'wpjam_ajax_upload');

function wpjam_ajax_upload() {
    check_ajax_referer('wpjam-common', 'nonce');

    // Missing current_user_can('upload_files') check

    $file = $_FILES['file'];
    $upload_overrides = ['test_form' => false];

    // Use of wp_handle_upload without restricting 'mimes' or enforcing 'test_type'
    $upload = wp_handle_upload($file, $upload_overrides);

    if ($upload && !isset($upload['error'])) {
        wp_send_json_success($upload);
    } else {
        wp_send_json_error($upload['error']);
    }
}

Security Fix

--- wpjam-basic/public/wpjam-functions.php
+++ wpjam-basic/public/wpjam-functions.php
@@ -4,6 +4,10 @@
 function wpjam_ajax_upload() {
     check_ajax_referer('wpjam-common', 'nonce');
 
+    if (!current_user_can('upload_files')) {
+        wp_send_json_error('insufficient_permissions');
+    }
+
     $file = $_FILES['file'];
-    $upload_overrides = ['test_form' => false];
+    $upload_overrides = [
+        'test_form' => false, 
+        'test_type' => true, 
+        'mimes'     => ['jpg' => 'image/jpeg', 'png' => 'image/png', 'gif' => 'image/gif']
+    ];
 
     $upload = wp_handle_upload($file, $upload_overrides);

Exploit Outline

The exploit involves two main steps: obtaining a valid AJAX nonce and submitting a malicious file. First, an attacker authenticates as a Subscriber and visits the WordPress dashboard to extract the 'wpjam-common' nonce from the global 'wpjam_vars' JavaScript object. Second, the attacker sends a multipart/form-data POST request to /wp-admin/admin-ajax.php with the 'action' set to 'wpjam-upload', the extracted nonce, and a PHP web shell. Because the plugin does not verify if the user has upload permissions or if the file type is safe, the server processes the upload and returns the URL of the PHP shell in a JSON response, allowing the attacker to execute arbitrary code.

Check if your site is affected.

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