JW Player for WordPress <= 2.3.7 - Missing Authorization
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:NTechnical Details
<=2.3.7# 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) orjwppp_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, orjwppp-position).
3. Code Flow (Inferred)
- Registration: The plugin registers AJAX handlers in the constructor or an
inithook using:add_action( 'wp_ajax_jwppp_save_options', 'jwppp_save_options_callback' ); - Entry Point: A Contributor user sends a POST request to
admin-ajax.phpwithaction=jwppp_save_options. - Missing Check: The callback function
jwppp_save_options_callback()(inferred) likely callscheck_ajax_referer()to verify the nonce but fails to callcurrent_user_can( 'manage_options' ). - 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).
- Shortcode/Script Trigger: The plugin typically enqueues
jwppp-admin.jsor similar on pages where the player can be configured. - Identification: Check the Post Editor (
post-new.php) or the dashboard. - Localization Variable: Look for the
jwppp_vars(inferred) object in the page source. - Acquisition:
- Create a page/post as a Contributor.
- Use
browser_navigateto go to the edit page. - Execute:
browser_eval("window.jwppp_vars?.jwppp_nonce"). - Note: If the action string in
check_ajax_refererisjwppp-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
- Target Version: Install JW Player for WordPress v2.3.7.
- Initial State:
- Log in as Admin.
- Go to JW Player settings and set a dummy license key:
INITIAL_VALID_KEY.
- Attacker Context: Ensure the
attackeruser 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:
- Search for AJAX Hooks: Run
grep -r "wp_ajax_" wp-content/plugins/jw-player-7-for-wp/to find all registered actions. - Check
admin_init: If nowp_ajaxactions are vulnerable, check if the plugin usesadmin_initto process$_POSTdata without a capability check. Sinceadmin_initruns for all users accessing/wp-admin/, it is a common source of this vulnerability. - Examine Nonce Scope: If
check_ajax_refereruses a generic action like-1, any valid nonce found on the dashboard will work.
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
@@ -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.