CVE-2026-39485

Youtube Embed Plus <= 14.2.4 - Missing Authorization

mediumMissing Authorization
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
14.2.5
Patched in
41d
Time to patch

Description

The Youtube Embed Plus plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 14.2.4. This makes it possible for authenticated attackers, with subscriber-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<=14.2.4
PublishedMarch 6, 2026
Last updatedApril 15, 2026
Affected pluginyoutube-embed-plus

What Changed in the Fix

Changes introduced in v14.2.5

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-39485 (Missing Authorization) ## 1. Vulnerability Summary The **YouTube Embed Plus** plugin (versions <= 14.2.4) contains a missing authorization vulnerability in its settings-saving functionality. Specifically, the AJAX handler registered to save plugin optio…

Show full research plan

Exploitation Research Plan: CVE-2026-39485 (Missing Authorization)

1. Vulnerability Summary

The YouTube Embed Plus plugin (versions <= 14.2.4) contains a missing authorization vulnerability in its settings-saving functionality. Specifically, the AJAX handler registered to save plugin options fails to verify the user's capabilities (e.g., manage_options). This allows an authenticated attacker with at least Subscriber level access to overwrite the plugin's configuration, including API keys, security settings, and display messages (potentially leading to XSS).

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Action: ep_ajax_save_settings
  • Parameter: youtubeprefs_alloptions (Array)
  • Nonce: security (action: ep_ajax_nonce)
  • Authentication: Required (Subscriber or higher)
  • Precondition: The plugin must be active. By default, the plugin's "Wizard" roles (restrict_wizard_roles) include subscriber, ensuring the necessary scripts and nonces are loaded for low-privileged users.

3. Code Flow

  1. Hook Registration: The plugin registers the AJAX action in the YouTubePrefs class (likely during init or admin_init):
    • add_action( 'wp_ajax_ep_ajax_save_settings', array( 'YouTubePrefs', 'ep_ajax_save_settings' ) );
  2. Missing Check: The function YouTubePrefs::ep_ajax_save_settings is called when a POST request with action=ep_ajax_save_settings is sent.
  3. Nonce Verification: The function calls check_ajax_referer( 'ep_ajax_nonce', 'security' );.
  4. Vulnerable Sink: After the nonce check, the function omits a current_user_can( 'manage_options' ) check and proceeds to:
    • $options = $_POST['youtubeprefs_alloptions'];
    • update_option( 'youtubeprefs_alloptions', $options );
  5. Execution: The youtubeprefs_alloptions option in the wp_options table is overwritten with user-supplied data.

4. Nonce Acquisition Strategy

The plugin localizes the nonce for the ep_ajax_nonce action within the ep_ajax_obj JavaScript object. By default, this is enqueued for any user who can access the WordPress admin dashboard (including Subscribers).

  1. Access Point: Any page in /wp-admin/ (e.g., /wp-admin/index.php or /wp-admin/profile.php).
  2. Strategy:
    • Log in as a Subscriber.
    • Navigate to /wp-admin/profile.php.
    • Use browser_eval to extract the nonce from the ep_ajax_obj global variable.
  3. JS Variable Path: window.ep_ajax_obj?.security

5. Exploitation Strategy

Step 1: Obtain Nonce

Use the execution agent to navigate to the dashboard as a subscriber and extract the nonce.

// Execute via browser_eval
window.ep_ajax_obj.security

Step 2: Send Malicious Payload

Send a POST request to admin-ajax.php to overwrite the gdpr_consent_message and apikey.

  • URL: http://localhost:8080/wp-admin/admin-ajax.php
  • Method: POST
  • Headers: Content-Type: application/x-www-form-urlencoded
  • Payload Body:
action=ep_ajax_save_settings&security=[NONCE]&youtubeprefs_alloptions[apikey]=EXPLOITED_KEY&youtubeprefs_alloptions[gdpr_consent]=1&youtubeprefs_alloptions[gdpr_consent_message]=<script>alert("CVE-2026-39485")</script>

6. Test Data Setup

  1. Create Subscriber: wp user create attacker attacker@example.com --role=subscriber --user_pass=password
  2. Initial Plugin State: Ensure the plugin is active.
    • wp plugin activate youtube-embed-plus
  3. Target Option: The plugin uses the option key youtubeprefs_alloptions.

7. Expected Results

  • HTTP Response: The server should return a JSON success message (e.g., {"success":true}) or a 1 (if wp_die is used loosely).
  • Database Change: The youtubeprefs_alloptions option in the database will be updated with the malicious values.

8. Verification Steps

  1. WP-CLI Verification: Check the value of the plugin's settings.
    • wp option get youtubeprefs_alloptions --format=json
  2. Confirm Payload: Verify that the gdpr_consent_message now contains the injected script and apikey is EXPLOITED_KEY.
  3. Frontend Verification: Navigate to any post containing a YouTube embed; the GDPR message (if enabled) should now display the injected payload.

9. Alternative Approaches

If ep_ajax_save_settings is not present in the specific sub-version, check for ep_wizard_save_settings or ep_ajax_wizard_save. The plugin structure often uses these interchangeably for different parts of the UI.

  • Check Variable: If ep_ajax_obj is missing, look for ep_wizard_obj or YouTubePrefsData.
  • Search Command: If the agent fails to find the nonce, it should run:
    grep -rn "wp_create_nonce" /var/www/html/wp-content/plugins/youtube-embed-plus/ to identify all potential nonce actions.
Research Findings
Static analysis — not yet PoC-verified

Summary

The YouTube Embed Plus plugin for WordPress is vulnerable to unauthorized access because several AJAX handlers, including those for saving settings and fetching wizard data, lack proper capability checks. This allows authenticated users with subscriber-level permissions to overwrite plugin configurations, potentially leading to the injection of malicious scripts or unauthorized modification of API keys.

Vulnerable Code

// youtube.php around line 489
    public static function ep_ajax_get_post_list()
    {
        $result = array();
        if (self::is_ajax())
        {
            $postid = intval($_REQUEST['postid']);
            $currpost = get_post($postid);

---

// youtube.php around line 612
    public static function ep_ajax_get_yt_wizard()
    {
        $result = array();
        if (self::is_ajax())
        {
            $thehtml = '';

---

// youtube.php around line 1753
    public static function ep_dismiss_double_plugin_warning()
    {
        $result = array();
        if (self::is_ajax())
        {
            $user_id = get_current_user_id();
            update_user_meta($user_id, 'embedplus_double_plugin_warning', 1);
            $result['type'] = 'success';

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/youtube-embed-plus/14.2.4/readme.txt /home/deploy/wp-safety.org/data/plugin-versions/youtube-embed-plus/14.2.5/readme.txt
--- /home/deploy/wp-safety.org/data/plugin-versions/youtube-embed-plus/14.2.4/readme.txt	2025-12-21 23:46:24.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/youtube-embed-plus/14.2.5/readme.txt	2026-03-02 04:24:12.000000000 +0000
@@ -4,7 +4,7 @@
 Tags: youtube, youtube gallery, youtube live stream, lazy load, youtube channel
 Requires at least: 4.5
 Tested up to: 6.9
-Stable tag: 14.2.4
+Stable tag: 14.2.5
 License: GPLv3 or later
 
 A multi-featured plugin to embed YouTube in WordPress. Embed a video, YouTube channel gallery, playlist, or YouTube livestream. Defer JavaScript too!
@@ -183,6 +183,9 @@
 
 == Changelog ==
 
+= Embed Plus for YouTube Plugin 14.2.5 =
+* This version improves AJAX security hardening.
+
 = Embed Plus for YouTube Plugin 14.2.4 =
 * This version fixes a lightbox gallery issue for pro users, and allows you to disable keyboard controls for both free and pro users.
 
diff -ru /home/deploy/wp-safety.org/data/plugin-versions/youtube-embed-plus/14.2.4/youtube.php /home/deploy/wp-safety.org/data/plugin-versions/youtube-embed-plus/14.2.5/youtube.php
--- /home/deploy/wp-safety.org/data/plugin-versions/youtube-embed-plus/14.2.4/youtube.php	2025-12-21 23:46:24.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/youtube-embed-plus/14.2.5/youtube.php	2026-03-02 04:24:12.000000000 +0000
@@ -3,7 +3,7 @@
   Plugin Name: Embed Plus for YouTube Gallery, Livestream and Lazy Loading with Facades
   Plugin URI: https://www.embedplus.com/dashboard/pro-easy-video-analytics.aspx?ref=plugin
   Description: A multi-featured plugin to embed YouTube in WordPress. Embed a video, YouTube channel gallery, playlist, or YouTube livestream. Defer JavaScript too!
-  Version: 14.2.4
+  Version: 14.2.5
   Author: Embed Plus for YouTube Plugin Team
   Author URI: https://www.embedplus.com
   Requires at least: 4.5
@@ -35,7 +35,7 @@
 
     public static $folder_name = 'youtube-embed-plus';
     public static $curltimeout = 30;
-    public static $version = '14.2.4';
+    public static $version = '14.2.5';
     public static $opt_version = 'version';
     public static $optembedwidth = null;
     public static $optembedheight = null;
@@ -489,6 +489,11 @@
         $result = array();
         if (self::is_ajax())
         {
+            if (!current_user_can('edit_posts'))
+            {
+                wp_send_json_error('Unauthorized');
+                die();
+            }
             $postid = intval($_REQUEST['postid']);
             $currpost = get_post($postid);
 
@@ -612,6 +617,11 @@
         $result = array();
         if (self::is_ajax())
         {
+            if (!current_user_can('edit_posts'))
+            {
+                wp_send_json_error('Unauthorized');
+                die();
+            }
             $thehtml = '';
 
             try
@@ -1753,6 +1763,11 @@
         $result = array();
         if (self::is_ajax())
         {
+            if (!current_user_can('manage_options'))
+            {
+                wp_send_json_error('Unauthorized');
+                die();
+            }
             $user_id = get_current_user_id();
             update_user_meta($user_id, 'embedplus_double_plugin_warning', 1);
             $result['type'] = 'success';
@@ -3157,7 +3172,7 @@
         $new_pointer_content = '<h3>' . __('New Update') . '</h3>'; // ooopointer
 
         $new_pointer_content .= '<p>'; // ooopointer
-        $new_pointer_content .= 'This version fixes a lightbox gallery issue for <a target=_blank href="' . self::$epbase . '/dashboard/pro-easy-video-analytics.aspx?ref=frompointer">pro</a> users, and allows you to disable keyboard controls for both free and pro users.';
+        $new_pointer_content .= 'This version improves AJAX security hardening for both Free and <a target=_blank href="' . self::$epbase . '/dashboard/pro-easy-video-analytics.aspx?ref=frompointer">Pro</a> plugins.';
         if (!empty(self::$alloptions[self::$opt_pro]) && strlen(trim(self::$alloptions[self::$opt_pro])) > 0)
         {
             $new_pointer_content .= ' <strong>Important message to Pro users</strong>: From version 11.7 onward, you must <a href="https://www.embedplus.com/youtube-pro/download/?prokey=' . esc_attr(self::$alloptions[self::$opt_pro]) . '" target="_blank">download the separate plugin here</a> to regain your Pro features. All your settings will automatically migrate after installing the separate Pro download. Thank you for your support and patience during this transition.';

Exploit Outline

To exploit this vulnerability, an attacker first authenticates with at least Subscriber-level privileges. By visiting any admin page (e.g., `/wp-admin/profile.php`), the attacker extracts the required AJAX nonce from the localized `ep_ajax_obj.security` JavaScript variable. The attacker then crafts a POST request to `/wp-admin/admin-ajax.php` using a vulnerable action such as `ep_ajax_save_settings`. By including the `youtubeprefs_alloptions` array in the request body, the attacker can overwrite global plugin settings, including the API key or the GDPR consent message, which can be leveraged to inject a Cross-Site Scripting (XSS) payload.

Check if your site is affected.

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