CVE-2026-39526

WpStream < 4.11.2 - Authenticated (Subscriber+) Insecure Direct Object Reference

mediumAuthorization Bypass Through User-Controlled Key
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
4.11.2
Patched in
56d
Time to patch

Description

The WpStream – Live Streaming, Video on Demand, Pay Per View plugin for WordPress is vulnerable to Insecure Direct Object Reference in all versions up to 4.11.2 (exclusive) due to missing validation on a user controlled key. 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<4.11.2
PublishedMarch 11, 2026
Last updatedMay 5, 2026
Affected pluginwpstream

What Changed in the Fix

Changes introduced in v4.11.2

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Vulnerability Research Plan: CVE-2026-39526 (WpStream IDOR) ## 1. Vulnerability Summary The **WpStream** plugin for WordPress is vulnerable to an **Insecure Direct Object Reference (IDOR)** in versions up to 4.11.2. The vulnerability exists because the plugin fails to perform an authorization che…

Show full research plan

Vulnerability Research Plan: CVE-2026-39526 (WpStream IDOR)

1. Vulnerability Summary

The WpStream plugin for WordPress is vulnerable to an Insecure Direct Object Reference (IDOR) in versions up to 4.11.2. The vulnerability exists because the plugin fails to perform an authorization check (such as verifying post ownership or checking for edit_post capabilities) when an authenticated user updates post data via AJAX. An attacker with Subscriber-level access can manipulate the postID parameter to modify the title, content, and post type of arbitrary posts on the site.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • AJAX Action: wpstream_dashboard_save_channel_data
  • Vulnerable Parameter: postID
  • Required Authentication: Authenticated (Subscriber+)
  • Preconditions: The attacker must obtain a valid nonce for the wpstream_edit_channel_nonce action, which is typically exposed on the plugin's frontend dashboard.

3. Code Flow

  1. The AJAX action wp_ajax_wpstream_dashboard_save_channel_data is registered in includes/class-wpstream-ajax.php and maps to the function wpstream_dashboard_save_channel_data().
  2. The function first verifies a nonce: wp_verify_nonce( $_POST['nonce'], 'wpstream_edit_channel_nonce' ).
  3. It then retrieves the target post ID from user input: $postID = intval( $_POST['postID'] );.
Research Findings
Static analysis — not yet PoC-verified

Summary

The WpStream plugin for WordPress is vulnerable to an Insecure Direct Object Reference (IDOR) due to missing ownership validation in its AJAX handler for saving channel data. This allows authenticated attackers with Subscriber-level permissions to modify the title, description, and post type of arbitrary posts by providing a target post ID.

Vulnerable Code

// includes/class-wpstream-ajax.php lines 131-164
public function wpstream_dashboard_save_channel_data() {
	// Verify the nonce for security
	if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( $_POST['nonce'], 'wpstream_edit_channel_nonce' ) ) {
		die( 'Permission denied.' );
	}
	if ( ! is_user_logged_in() ) {
		wp_send_json_error( array( 'error' => 'User is not logged in.' ) );
		die();
	}

	$thumb_id     = isset( $_POST['thumb_id'] ) ? intval( $_POST['thumb_id'] ) : 0;
	$title        = sanitize_text_field( $_POST['title'] );
	$description  = sanitize_text_field( $_POST['description'] );
	$channel_paid = intval( $_POST['channel_paid'] );
	$images       = sanitize_text_field( $_POST['images'] );
	$images       = trim($images,',');
	$channel_price=0;
	if ( isset( $_POST['channel_price'] ) ) {
		$channel_price = floatval( $_POST['channel_price'] );
	}
	$postID = intval( $_POST['postID'] );

	// ... [Post type logic] ...

	if ( $postID != '0' ) {
		$post_data = array(
			'ID'           => $postID,
			'post_title'   => $title,
			'post_content' => $description,
			'post_type'    => $new_post_type,
		);
		wp_update_post( $post_data );

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/wpstream/4.11.1/includes/class-wpstream-ajax.php /home/deploy/wp-safety.org/data/plugin-versions/wpstream/4.11.2/includes/class-wpstream-ajax.php
--- /home/deploy/wp-safety.org/data/plugin-versions/wpstream/4.11.1/includes/class-wpstream-ajax.php	2025-11-04 20:51:50.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/wpstream/4.11.2/includes/class-wpstream-ajax.php	2026-03-16 07:07:36.000000000 +0000
@@ -135,6 +135,19 @@
 			die();
 		}
 
+		/* Making sure that the channel that's currently selected by the user is the one being updated */
+		$current_user = wp_get_current_user();
+		if ( isset( $_POST['postID'] ) && intval( $_POST['postID'] ) !== 0 ) {
+			$current_editing_channel = get_user_meta( $current_user->ID, 'wpstream_start_streaming_channel', true );
+			if ( intval( $current_editing_channel ) !== intval( $_POST['postID'] ) ) {
+				wp_send_json_error( array( 'error' => 'Can\'t edit this channel.' ) );
+				die();
+			}
+		} else {
+			wp_send_json_error( array( 'error' => 'Invalid channel ID.' ) );
+			die();
+		}
+
 		$thumb_id     = isset( $_POST['thumb_id'] ) ? intval( $_POST['thumb_id'] ) : 0;
 		$title        = sanitize_text_field( $_POST['title'] );
 		$description  = sanitize_text_field( $_POST['description'] );

Exploit Outline

To exploit this IDOR, an attacker first authenticates as a Subscriber and retrieves a valid 'wpstream_edit_channel_nonce' from the plugin dashboard. The attacker then sends a POST request to the '/wp-admin/admin-ajax.php' endpoint with the 'action' parameter set to 'wpstream_dashboard_save_channel_data'. By setting the 'postID' parameter to the ID of a target post (e.g., a Page or a Post authored by an Admin) and providing new values for 'title' and 'description', the attacker can modify the content of that post, as the vulnerable version of the plugin lacks a check to ensure the 'postID' belongs to the current user or that the user has appropriate 'edit_post' capabilities.

Check if your site is affected.

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