Research/CVE-2026-78159
N-dayCVE-2026-78159CriticalPublic

CVE-2026-78159: WordPress The Events Calendar, unauthenticated code execution

A classic-theme event comment is run through blocks on moderation preview. is_safe_widget_instance rejects objects only, so a plain array reaches Element_Classes::parse_array and invokes a string callable. The lab canary is a witness function, not a shell.

Name
CVE-2026-78159: WordPress The Events Calendar, unauthenticated code execution
Type
N-day analysis
CVE
CVE-2026-78159
CVE Risk
critical
Disclosure Status
public
Vendor
StellarWP
Affected
WordPress plugin The Events Calendar through 6.17.3. Patched in 6.17.3.1.
Published
28 Oct 2026
Updated
28 Oct 2026
Tags
n-day, wordpress, rce, cwe-94

WordPress The Events Calendar, unauthenticated code execution

The Events Calendar 6.17.3 - stellarwp

I am @abraxas_null. Loopback lab. The client is CVE-2026-78159-Abraxas-Labs.py.

parse_array is the sink, not an ajax action=. Unauthenticated comment on a tribe_events post plants a wp:legacy-widget block. V2 single-event buffers comments_template() then do_blocks(). is_safe_widget_instance() rejects objects only, so a plain-array payload reaches Element_Classes::parse_array() and invokes string-callable values. idBase is tribe-widget-events-list, not events-list. Patched in 6.17.3.1 (Wordfence also points at 6.17.4.1 for a sibling).

CVE-2026-78159 (NVD). CWE-94. Vendor: StellarWP. WordPress plugin The Events Calendar through 6.17.3. Patched in 6.17.3.1.

What an attacker can do

Comments open on events, classic theme. POST a comment, follow the moderation-preview Location, GET that URL. POCWitness78159 in the HTML means call_user_func ran during render. A real callable in the PHP environment is RCE. The lab canary is poc_witness_78159, not system() and not wp_update_user.

How this showed up in the lab

Wordfence named parse_array. I read Element_Classes, then Template_Bootstrap do_blocks, then the widget service provider. HTTP is POST /wp-comments-post.php then GET the moderation-preview URL.

Harvest comment_post_ID from /event/lab-event/. POST the legacy-widget comment. Follow Location. SUCCESS only if POCWitness78159 appears after that GET.

Wrong turns already in the lab: generic 200 event HTML without the string; stopping at wp-comments-post 200/302 without following Location; comment 409/duplicate without the block; block theme (tec_is_full_site_editor() skips the bootstrap, so do_blocks never sees comment HTML); system() / exec() / password-reset payload.

The lab

Port 8088. TEC 6.17.3. Twenty Twenty-One. showComments=yes, published lab-event, first comments held. mu-plugin canary.

Target only 127.0.0.1:8088 (or the loopback you bound).

Plain text
cd lab
docker compose up --force-recreate
python3 ../CVE-2026-78159-Abraxas-Labs.py

Witness: Moderation-preview GET body contains POCWitness78159. Generic event HTML without that string is not it. debug.log may also append it.

References