
Docker validation lab and Python PoC for CVE-2026-92084, an unauthenticated shortcode execution flaw in Beaver Builder Lite <= 2.11.0.5, with patched control and nuclei screen.
Security-research material for reproducing and validating CVE-2026-92084:
Beaver Builder (Lite) <= 2.11.0.5 executes arbitrary registered WordPress
shortcodes planted in widget output rendered by the Sidebar module, via the
builder's layout-wide do_shortcode() pass.
'renders_shortcodes' => false;
the bracket-encoding machinery itself shipped earlier and is unchanged)AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N) - CWE-94Use only on systems you own or are explicitly authorized to test. The PoC posts one comment whose author name contains a lab-registered marker shortcode. No destructive shortcode is used and nothing is written to disk.
Status: proven in the supplied lab.
Beaver Builder Lite 2.11.0.5 (WordPress 7.1.2, builder page with a Sidebar module + Recent Comments widget):
comment posted : author name "[cve92084]" on the builder page
result : rendered page contains the marker shortcode's server-side
output "CVE92084-SHORTCODE-FIRED"
(executed by the layout-wide do_shortcode() pass)
2.11.0.6 : brackets entity-encoded, marker absent (patched negative
control; page shows the literal text [cve92084])
This demonstrates server-side execution of an arbitrary registered shortcode with output embedded in the page, disclosed to every visitor. It does not demonstrate RCE; impact depends on which shortcodes are registered on the target (post/meta exposure, forms, plugin-provided shortcodes with side effects).
The sink. FLBuilder::render_content() runs the assembled builder
layout through a wide shortcode pass before echoing it:
// classes/class-fl-builder.php:2139, Beaver Builder Lite 2.11.0.5
$content = do_shortcode( $content );
The injection point. The Sidebar module renders a WordPress sidebar's widget output verbatim into that layout:
// modules/sidebar/includes/frontend.php:4, 2.11.0.5
if ( ! dynamic_sidebar( $settings->sidebar ) ) {
Widget content is untrusted user data - the core Recent Comments widget
echoes get_comment_author_link(), i.e. whatever name an (unauthenticated)
commenter supplied. FLBuilder::double_escape_shortcodes() only re-brackets
the [[x]] escaped form, so a plain [cve92084] passes through and the
do_shortcode() pass executes it.
The fix. 2.11.0.5 already ships the neutralization machinery -
FLBuilderModule::$renders_shortcodes = true (class-fl-builder-module.php:143)
and FLBuilder::escape_foreign_module_shortcodes() hooked to both module
render filters (class-fl-builder.php:109-110, applied at 3240), which
entity-encodes the brackets of any registered shortcode in module output.
The Sidebar module simply never opted out. The single functional change in
2.11.0.6 is the opt-out:
// modules/sidebar/sidebar.php, 2.11.0.6
'renders_shortcodes' => false,
// dynamic_sidebar() renders third-party widget output that can contain
// untrusted user data (e.g. a comment author name via the core Recent
// Comments widget); do not run its shortcodes.
/wp-comments-post.php with the shortcode payload as
the comment author name.do_shortcode() pass executes the
payload. Its output replaces the author name, visible to every visitor.Requirements: Docker with Compose v2, Python 3.10+ on the host.
./lab verify
Builds the 2.11.0.5 lab, requires the marker to fire, then builds the
2.11.0.6 lab and requires its absence. Remove everything with
./lab reset.
Vulnerable control:
[!!!] SHORTCODE EXECUTION CONFIRMED
posted : comment author '[cve92084]' on page 5
evidence: 'CVE92084-SHORTCODE-FIRED' present in the rendered builder page
context : ...<a href="https://github.com/hassham1/cve-2026-92084-beaver-builder-shortcode-poc/blob/main/..." class="url">CVE92084-SHORTCODE-FIRED</a>...
RESULT: VULNERABLE CONTROL CONFIRMED
Patched control:
[=] shortcode text present but NOT executed: brackets entity-encoded
(patched >= 2.11.0.6 behavior: escape_foreign_shortcodes).
RESULT: PATCHED CONTROL CONFIRMED
A marker in the page only inside the displayed comment (raw text) is not accepted as proof; the marker must appear as the shortcode's executed output.
./lab start vulnerable # 2.11.0.5 lab on http://127.0.0.1:9488
./lab test # assert marker fires
./lab start patched # 2.11.0.6 lab
./lab test # assert absence
./lab status
./lab reset
Run the PoC by hand (loopback default; authorized external targets need the explicit override):
python3 poc/poc_cve_2026_92084.py --url http://127.0.0.1:9488 --post-id 5
python3 poc/poc_cve_2026_92084.py --url https://target.example \
--post-id 5 --allow-authorized-non-loopback [--insecure]
The nuclei template (nuclei/cve-2026-92084.yaml) is a version screen only
(readme.txt stable tag <= 2.11.0.5). The behavioral chain requires comment
submission plus an approval transition, which is not practical to express in
nuclei; the Python PoC performs the full flow.
| Version | Assessment |
|---|---|
| Beaver Builder Lite 2.11.0.5 | Shortcode execution reproduced end to end |
| Beaver Builder Lite 2.11.0.6 | Patched negative control reproduced |
| Beaver Builder Lite <= 2.11.0.4 | Affected per advisory; not individually tested |
| Beaver Builder (Pro/Agency) | Not tested - advisory scope is the Lite plugin |
.
├── .github/workflows/validate.yml
├── .gitignore
├── LICENSE
├── README.md
├── SECURITY.md
├── docker-compose.yml
├── lab
├── nuclei/
│ └── cve-2026-92084.yaml
├── poc/
│ └── poc_cve_2026_92084.py
└── provision/
└── install.php
Not committed: assets/ (plugin zips), .lab-state, __pycache__/.
| Claim | Status |
|---|---|
| Shortcode execution via Sidebar module widget output | Proven (2.11.0.5) |
| Execution output disclosed on the rendered builder page | Proven |
| Patched negative control (2.11.0.6, brackets encoded) | Proven |
| Default configuration (lab sidebar + Recent Comments widget) | Proven (this is the lab topology) |
| Other widgets echoing user data (tag cloud, meta, custom) | Not tested |
| Impact beyond registered shortcode output (RCE) | Not claimed |