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).
cd lab
docker compose up --force-recreate
python3 ../CVE-2026-78159-Abraxas-Labs.pyWitness: Moderation-preview GET body contains POCWitness78159. Generic event HTML without that string is not it. debug.log may also append it.