CVE-2026-39614

JW Player for WordPress <= 2.3.7 - Missing Authorization

mediumMissing Authorization
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
Unpatched
Patched in
N/A
Time to patch

Description

The JW Player for WordPress plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 2.3.7. This makes it possible for authenticated attackers, with contributor-level access and above, to perform an unauthorized action.

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.3.7
PublishedFebruary 10, 2026
Last updatedMay 6, 2026
Affected pluginjw-player-7-for-wp
Research Plan
Unverified

# Exploitation Research Plan: JW Player for WordPress Missing Authorization (CVE-2026-39614) ## 1. Vulnerability Summary The **JW Player for WordPress** plugin (up to and including version 2.3.7) contains a missing authorization vulnerability within its AJAX handling logic. Specifically, certain ad…

Show full research plan

Exploitation Research Plan: JW Player for WordPress Missing Authorization (CVE-2026-39614)

1. Vulnerability Summary

The JW Player for WordPress plugin (up to and including version 2.3.7) contains a missing authorization vulnerability within its AJAX handling logic. Specifically, certain administrative functions registered via wp_ajax_ fail to implement current_user_can() capability checks. This allows authenticated users with at least Contributor-level permissions to execute these actions, which are intended for Administrators. This typically results in the ability to modify plugin settings, player configurations, or account information.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Vulnerable Action: jwppp_update_players (inferred) or jwppp_save_options (inferred). In this plugin, settings are often handled by a central update function.
  • HTTP Method: POST
  • Authentication: Contributor-level account (required to access admin-ajax.php).
  • Payload Parameters:
    • action: The AJAX action name.
    • jwppp_nonce: The CSRF token.
    • Various settings keys (e.g., jwppp-player-ads, jwppp-license-key, or jwppp-position).

3. Code Flow (Inferred)

  1. Registration: The plugin registers AJAX handlers in the constructor or an init hook using:
    add_action( 'wp_ajax_jwppp_save_options', 'jwppp_save_options_callback' );
  2. Entry Point: A Contributor user sends a POST request to admin-ajax.php with action=jwppp_save_options.
  3. Missing Check: The callback function jwppp_save_options_callback() (inferred) likely calls check_ajax_referer() to verify the nonce but fails to call current_user_can( 'manage_options' ).
  4. Execution: The function proceeds to update the WordPress options table using update_option(), allowing the attacker to change plugin behavior.

4. Nonce Acquisition Strategy

The plugin enqueues administrative scripts and localizes data including nonces. Because Contributors have access to the WordPress dashboard and the Post Editor, the plugin may expose nonces there (e.g., for the JW Player shortcode generator button).

  1. Shortcode/Script Trigger: The plugin typically enqueues jwppp-admin.js or similar on pages where the player can be configured.
  2. Identification: Check the Post Editor (post-new.php) or the dashboard.
  3. Localization Variable: Look for the jwppp_vars (inferred) object in the page source.
  4. Acquisition:
    • Create a page/post as a Contributor.
    • Use browser_navigate to go to the edit page.
    • Execute: browser_eval("window.jwppp_vars?.jwppp_nonce").
    • Note: If the action string in check_ajax_referer is jwppp-nonce (inferred), this is the value needed.

5. Exploitation Strategy

Step 1: Create a Contributor User

Use WP-CLI to create a low-privileged user to simulate the attacker.

wp user create attacker attacker@example.com --role=contributor --user_pass=password123

Step 2: Extract the Nonce

Login as the contributor and navigate to the post editor to extract the nonce from the localized script.

  • URL: /wp-admin/post-new.php
  • JS Path: window.jwppp_vars.jwppp_nonce (Verify this name in the HTML source).

Step 3: Perform Unauthorized Action

Send a POST request to change a critical plugin setting (e.g., the JW Player license key or an advertising setting).

  • Tool: http_request
  • URL: http://localhost:8080/wp-admin/admin-ajax.php
  • Headers: Content-Type: application/x-www-form-urlencoded
  • Body:
action=jwppp_save_options&jwppp_nonce=[EXTRACTED_NONCE]&jwppp-license-key=EVIL_KEY_PAYLOAD&jwppp-active-ads=1

(Note: Parameter names must be verified against the plugin source or by observing a legitimate admin request.)

6. Test Data Setup

  1. Target Version: Install JW Player for WordPress v2.3.7.
  2. Initial State:
    • Log in as Admin.
    • Go to JW Player settings and set a dummy license key: INITIAL_VALID_KEY.
  3. Attacker Context: Ensure the attacker user has no administrative capabilities.

7. Expected Results

  • Response: The server returns a success indicator (e.g., 1, {"success":true}, or a redirect).
  • Behavior: Despite being a Contributor, the request is processed because the nonce (which the Contributor can access) is verified, but the user's role is never checked.

8. Verification Steps

After sending the exploit request, use WP-CLI to verify the option has been changed in the database:

wp option get jw_player_7_settings
# OR if settings are stored individually:
wp option get jwppp-license-key

If the value matches EVIL_KEY_PAYLOAD, the missing authorization is confirmed.

9. Alternative Approaches

If the jwppp_save_options action is not the correct name:

  1. Search for AJAX Hooks: Run grep -r "wp_ajax_" wp-content/plugins/jw-player-7-for-wp/ to find all registered actions.
  2. Check admin_init: If no wp_ajax actions are vulnerable, check if the plugin uses admin_init to process $_POST data without a capability check. Since admin_init runs for all users accessing /wp-admin/, it is a common source of this vulnerability.
  3. Examine Nonce Scope: If check_ajax_referer uses a generic action like -1, any valid nonce found on the dashboard will work.
Research Findings
Static analysis — not yet PoC-verified

Summary

The JW Player for WordPress plugin is vulnerable to unauthorized access because its AJAX handlers verify security nonces but lack capability checks. This allows authenticated users with Contributor permissions or higher to perform administrative actions, such as modifying plugin settings, by sending crafted requests to the WordPress AJAX endpoint.

Vulnerable Code

// jw-player-7-for-wp/includes/jwppp-admin.php (Inferred)
add_action( 'wp_ajax_jwppp_save_options', 'jwppp_save_options_callback' );

function jwppp_save_options_callback() {
    // Nonce check exists, providing some protection against CSRF but not against unauthorized access by logged-in users
    if ( ! isset( $_POST['jwppp_nonce'] ) || ! wp_verify_nonce( $_POST['jwppp_nonce'], 'jwppp-nonce' ) ) {
        wp_die( 'Security check failed' );
    }

    // VULNERABILITY: Missing current_user_can('manage_options') or similar capability check

    if (isset($_POST['jwppp-license-key'])) {
        update_option('jwppp-license-key', sanitize_text_field($_POST['jwppp-license-key']));
    }
    // ... other settings updates ...

    wp_die();
}

Security Fix

--- a/includes/jwppp-admin.php
+++ b/includes/jwppp-admin.php
@@ -20,6 +20,10 @@
 function jwppp_save_options_callback() {
     if ( ! isset( $_POST['jwppp_nonce'] ) || ! wp_verify_nonce( $_POST['jwppp_nonce'], 'jwppp-nonce' ) ) {
         wp_die( 'Security check failed' );
     }
+
+    if ( ! current_user_can( 'manage_options' ) ) {
+        wp_die( 'You do not have sufficient permissions to access this page.' );
+    }
+
     // Process and save options...

Exploit Outline

The exploit targets the plugin's AJAX handlers which lack capability checks. 1. Authentication: The attacker must be logged in as a Contributor-level user. 2. Nonce Acquisition: The attacker visits the WordPress dashboard or Post Editor where the plugin's administrative script is enqueued. They extract the required nonce from the localized JavaScript variable, typically `window.jwppp_vars.jwppp_nonce`. 3. Request Construction: The attacker sends a POST request to `/wp-admin/admin-ajax.php` using the extracted nonce. 4. Payload: The request contains the `action` parameter (e.g., `jwppp_save_options`) and desired setting parameters (e.g., `jwppp-license-key=MALICIOUS_KEY`). 5. Result: Because the plugin only verifies the nonce and not the user's permissions, the settings are updated in the WordPress options table.

Check if your site is affected.

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