Searchlight Cyber wp2shell WordPress RCE discovered with GPT‑5.6 Sol Ultra for $25
Searchlight Cyber wp2shell WordPress RCE discovered with GPT‑5.6 Sol Ultra for $25
TL;DR
Searchlight Cyber leveraged GPT‑5.6 Sol Ultra to find a pre‑authentication SQL injection in WordPress’s Batch API, chained it through cache poisoning, embed abuse, and a malicious customize_changeset to achieve remote code execution (RCE) on a default WordPress install—all for roughly $25 in compute time. The exploit demonstrates why exploit brokers are willing to pay $500 k for a WordPress RCE.
The Prompt That Started the Hunt
The researcher fed GPT‑5.6 Sol Ultra a six‑hour, four‑agent prompt adapted from OpenAI’s Cycle Double Cover (CDC) prompt. The prompt instructed the model to:
- Treat the WordPress source tree as a closed codebase (no internet, no changelogs).
- Explore a wide range of attack surfaces (input parsing, serialization, race conditions, etc.).
- Aggressively spawn up to four agents, dynamically re‑balancing effort based on progress.
- Produce a complete pre‑authentication RCE chain that can read
/flagon a typical MySQL‑backed deployment.
The researcher cloned the latest stable WordPress release into wordpress‑ctf/main/ and left third_party/ empty to force the model to work solely with the core code.
The Core Bug: Batch API Validation Desynchronisation
WordPress’s REST Batch API validates all sub‑requests in a first loop, then executes them in a second loop. The validation loop populates two parallel arrays, $matches (handler references) and $validation (validation results). When a request fails is_wp_error($single_request), the code continues without pushing a corresponding entry into $matches:
if ( is_wp_error( $single_request ) ) {
$has_error = true;
$validation[] = $single_request;
continue; // <-- $matches not updated
}
This off‑by‑one shift means the validation result at index i can be applied to the handler at index i+1. An attacker can therefore validate a harmless request and execute it with the handler of a different, vulnerable request.
The First Exploit Primitive: A Pre‑Auth SQL Injection
The GET /wp/v2/posts endpoint builds a SQL WHERE clause using the author__not_in parameter. When the parameter is a scalar string, WordPress interpolates it directly without escaping:
$author__not_in = implode(',', (array) $query_vars['author__not_in']);
$where .= " AND {$wpdb->posts}.post_author NOT IN ($author__not_in) ";
Normally the REST schema forces author__not_in to be an array, causing each element to be sanitized with absint. By using the Batch API desynchronisation bug, the attacker can feed a scalar string (e.g., "0) OR 1=1 -- ") to the validation of a different request while the execution occurs on the GET /wp/v2/posts handler, yielding a classic SQL injection that returns all rows.
Payload Example (recursive batch call)
POST /wp-json/batch/v1
{
"requests": [
{"method":"POST","path":"http://:"},
{"method":"POST","path":"/wp/v2/posts","body":{
"requests":[
{"method":"GET","path":"http://:"},
{"method":"DELETE","path":"/wp/v2/posts/1","body":{"author_exclude":"0) OR 1=1 -- "}},
{"method":"GET","path":"/wp/v2/posts"}
]
}},
{"method":"POST","path":"/batch/v1"}
]
}
The outer request desynchronises the HTTP method validation; the inner request desynchronises the author_exclude parameter, delivering the injection.
From SQLi to RCE: Chaining Gadgets
The researcher let GPT‑5.6 continue beyond the SQLi, producing a multi‑stage chain:
- Cache Poisoning – WordPress caches
WP_Postobjects per request. By returning crafted rows via the SQLi, the attacker controls the in‑memory representation of posts, including theirpost_content. - Embed Abuse – Embedding a local post (
[embed]/?p=10[/embed]) creates anoembed_cacherow in the database. The attacker can fabricate such rows with arbitrarypost_typeandpost_content. - Customize Changeset – A
customize_changesetpost stores a JSON diff that is applied with theuser_idembedded in the payload. By forcing the changeset’suser_idto1(the admin), WordPress temporarily runs with administrator privileges. - Parent‑Cycle Gadget – WordPress detects cycles in the post‑parent hierarchy and, when found, calls
wp_update_post(['ID'=>X,'post_parent'=>0]). This call does not overwritepost_content, allowing the attacker‑controlled content to persist. - Hook Replay – The cycle gadget can be used to trigger the
parse_requestaction ("{$new_status}_{$post_type}"). Invokingdo_action('parse_request', …)re‑executes the entire Batch API request as the assumed admin. - Admin Account Creation – On the second pass, a previously‑failed request to create a new admin user now succeeds because the request runs with admin rights.
- Back‑door Plugin Upload – With an admin account, the attacker uploads a malicious plugin ZIP, achieving persistent code execution on the server.
Cost, Timeline, and Impact
- Compute cost: $25 (≈ 50 % of a $200 weekly GPT‑5.6 Sol Ultra subscription).
- Time to full chain: just over 10 hours of model runtime plus a day of human analysis.
- Scope: WordPress powers > 500 million sites; a pre‑auth RCE in the default configuration is a critical, high‑severity vulnerability.
- Market value: Exploit brokers reportedly pay $500 k for a reliable WordPress RCE, explaining the headline claim.
Community Reaction (Hacker News Comments)
- Some commenters doubt the $500 k figure, suggesting the article may be overstating broker payouts.
"There is no evidence that $500k has been paid or would be paid for an exploit like this one." – Zsfe510asG
- Others note the technical depth, comparing it to past AI‑assisted exploits and praising the write‑up.
"That was an incredible writeup! … LLMs level the field." – cadamsdotcom
- A few raise concerns about model guardrails and the ethics of AI‑generated exploits.
"I’m surprised GPT‑5.6 didn’t block that prompt due to guardrails." – raesene9
- Skeptics ask for verification of the vulnerability’s public disclosure and patch status.
"Is this real? … I’m not seeing any mention where they report this to WP or the patch." – tantalor
Why This Matters
- Proof of concept: The chain proves that a state‑of‑the‑art LLM can discover a novel, pre‑authentication WordPress RCE with minimal compute cost.
- Economic incentive: The $500 k bounty figure shows a strong market demand for such zero‑days, motivating both defenders and attackers to adopt AI‑assisted research.
- Defensive implications: Traditional static analysis missed the Batch API desynchronisation bug; defenders need to incorporate AI‑driven code‑understanding tools to surface similar logic‑flaws.
- Future of security research: As LLMs become more capable, the bottleneck shifts from bug‑finding to prompt engineering, exploit chaining, and verification—skills that will dominate next‑generation security teams.
Mitigation steps (as of the publication date):
- Update WordPress to the latest release where the Batch API validation bug is patched.
- Disable the Batch API (
/wp-json/batch/v1) if not required. - Harden the REST API with authentication and rate‑limiting.
- Monitor for unexpected
oembed_cacherows orcustomize_changesetcreations. - Employ AI‑assisted static analysis to detect validation/execution mismatches in future code.
The full technical details, including the exact payloads and the GitHub‑style proof‑of‑concept, are available on the Searchlight Cyber research page linked above.