---
title: "A $25 Subscription Found the First Pre-Auth WordPress Core RCE in a Decade"
pubDatetime: 2026-07-20T00:00:00.000Z
description: "Searchlight Cyber pointed GPT5.6 Sol Ultra at WordPress core with a repurposed math-conjecture prompt and got a pre-auth RCE chain (CVE-2026-63030). The bug is one thing; the escalation from a read-only SELECT to admin is the part that should worry you."
tags: [ai-security, wordpress, vulnerability, llm, exploit-development, 2026, 2026-q3, 2026-07]
---
> [!tldr] TL;DR
> Searchlight Cyber's Adam Kues adapted the prompt OpenAI used to crack a math conjecture, pointed GPT5.6 Sol Ultra at unmodified WordPress core, and got a pre-authentication SQL injection in a couple of hours for about $25 of subscription usage. It became CVE-2026-63030, the first critical unauthenticated WordPress core RCE in roughly a decade, across 500M+ installs. The initial bug (a batch-API validation desync) is understandable in a paragraph. The genuinely alarming part is the escalation: the model turned a *read-only* SELECT injection into full RCE by chaining WordPress's own caching, embed, and cycle-detection safety code. Patch now; check with [wp2shell.com](https://wp2shell.com/).

Exploit brokers quote up to half a million dollars for a pre-auth WordPress remote code execution. [Searchlight Cyber](https://slcyber.io/research-center/exploit-brokers-pay-500000-for-a-wordpress-rce-i-found-one-with-gpt5-6/) found one for roughly the price of a large pizza. That gap is the story, and it's worse than the headline number suggests, because the cheap part was finding the bug. The expensive, human-grade part was the exploitation, and the model did that too.

WordPress is not a soft target. It runs a huge chunk of the web, it has been picked over by researchers for twenty years, and it had gone through this whole decade without a meaningful pre-auth hole in core. So when Adam Kues at Searchlight pointed a model at a clean checkout and it came back claiming pre-auth SQLi, his first reaction was disbelief. He stood up a stock instance and asked the model to steal the admin's email. A couple of minutes later it printed the address he'd registered with.

## The prompt is the interesting bit

Kues didn't write a bespoke security harness. He took the [prompt OpenAI published](https://cdn.openai.com/pdf/04d1d1e4-bc75-476a-97cf-49055cd98d31/cdc_prompt.pdf) for the run where Sol solved the [Cycle Double Cover conjecture](https://en.wikipedia.org/wiki/Cycle_double_cover), swapped the objective for "find the pre-auth-to-RCE chain that reads `/flag`," and let it run. His edits are the tell of someone who has watched models cheat. He deleted the `.git` directory and forbade diffing against patched versions, because models love to shortcut novel discovery by reading changelogs. He specified "typical production deployment with MySQL" and "pre-authentication," because models will otherwise invent an unreachable config to declare victory. And he told it to actually read the source of underlying libraries rather than guess at their APIs, spawning up to four agents and grinding for at least six hours.

Total cost: about half his weekly quota on a \$200 subscription, so call it \$25. The full weaponized chain took a bit over ten hours of model time. This is the same steer-and-swarm shape I wrote about in [T3MP3ST](/posts/t3mp3st-multi-agent-red-teaming): the branding says autonomous swarm, but the leverage is a human who knows how to constrain the objective so the agent can't lie its way out.

## The bug you can hold in your head

WordPress 5.6 added a batch API so you can bundle several REST subrequests into one call. Normally each request runs a strict pipeline: validate params, sanitize params, check permissions, execute. The batch handler splits that into two loops, validating everything first and then executing everything. The two loops are kept in sync by index: `$validation[i]` is supposed to describe `$matches[i]`.

It doesn't, always. If a subrequest is malformed, the validation loop pushes an error and hits `continue`, so the `$matches` array never gets that entry. Every subsequent match shifts back by one. Now you can validate one endpoint and execute a *different* one with the first one's clean bill of health. That's the whole primitive: attach a benign request's validation to a malicious request's handler.

The sink is a scalar-versus-array slip in the posts query. The `author_exclude` parameter is meant to be an array of integers, each run through `absint()`. Pass it as a bare string instead and it's interpolated straight into SQL. The public route enforces the array type during validation, but the desync lets you skip that validation. One wrinkle: the injectable path is a `GET`, and the batch API rejects `GET`. The model's answer is the kind of move that makes you sit back. Method validation is itself just parameter validation, so it called the batch endpoint recursively, using the desync a second time to smuggle the `GET` through. Two nested applications of the same bug, and you have a pre-auth SQL injection.

## From read-only SELECT to admin, the absurd part

Here is where I stopped being impressed by the bug and started being unsettled by the exploitation. The injection is `SELECT`-only. No writes, no stacked queries. Passwords and tokens in the database are hashed, so leaking rows doesn't hand you an account. A lesser researcher, human or model, writes it up as "critical infoleak" and ships.

Sol kept going. Because the SQLi feeds a `UNION`, it can fabricate fake `WP_Post` rows that land in WordPress's per-request in-memory cache. From there it walks a chain of gadgets, each one a legitimate feature: the [embed](https://wordpress.org/documentation/article/embeds/) cache to persist a forged row into the database as an `oembed_cache` post; a cache-reconciliation quirk that lets in-memory fields overwrite the stored `post_type`, turning that row into a `customize_changeset`; the changeset applier, which runs edits under `user_id: 1`, so it briefly *becomes the administrator*; and WordPress's own cycle-detection logic, the safety code that stops post-parent loops, abused as the trigger that forces the changeset to apply. The finale routes through a forged post whose fabricated status and type make WordPress fire the `parse_request` hook, replaying the entire original batch request from the top, this time with the admin role still attached. One of those subrequests creates a new administrator. Log in, upload a plugin zip, code execution.

Six forged posts, labelled with single letters in the writeup, arranged so that WordPress's caching and integrity machinery does the exploitation to itself. Kues, who has used every frontier model since 2022, says no human researcher completes this chain in ten hours, and that he isn't sure it's doable at all even handed the initial bug. I believe him. Spotting one gadget is skill. Spotting six disparate ones and threading them across a codebase, in an afternoon, is a different thing.

## The sober footnotes

This is real and it's patched. [CVE-2026-63030](https://fullhunt.io/blog/2026/07/17/wp2shell-wordpress-core-pre-auth-rce-cve-2026-63030.html) is assigned, [Calif and Hacktron reproduced the full chain independently](https://x.com/calif_io/status/2079016161891521022) before public PoCs surfaced, and Wordfence is calling it [the first critical unauthenticated core RCE in nearly a decade](https://www.wordfence.com/blog/2026/07/wp2shell-aftermath-the-first-critical-unauthenticated-wordpress-core-rce-in-nearly-a-decade/). On the [Hacker News thread](https://news.ycombinator.com/item?id=48951744), the sharpest pushback is a terminology one: jerrythegerbil notes "pre-authentication" and "unauthenticated" get blurred for marketing reach. Fair, but here the distinction collapses anyway, since the chain needs no prior knowledge of the target.

The uncomfortable takeaway is about the escalation. Fuzzers have found WordPress bugs for years; that's routine. What's new is a model doing the part we assumed stayed safely human: the creative, multi-gadget climb from a nothing-looking read primitive to root. If that's a \$25 capability now, the economics of finding the next one just inverted, and the defensive side is still pricing exploits like it's a seller's market. Go patch, then think about what your threat model assumes an attacker "can't be bothered" to chain together.

---

**Sources**

- Adam Kues / Searchlight Cyber, ["Exploit brokers pay \$500,000 for a WordPress RCE. I found one with GPT5.6 Sol Ultra and \$25"](https://slcyber.io/research-center/exploit-brokers-pay-500000-for-a-wordpress-rce-i-found-one-with-gpt5-6/) (20 July 2026), the primary writeup with the full chain and the exact prompt
- Searchlight Cyber, ["wp2shell: Pre-Authentication RCE in WordPress Core"](https://slcyber.io/research-center/wp2shell-pre-authentication-rce-in-wordpress-core/), the technical disclosure, and the [wp2shell.com](https://wp2shell.com/) checker
- FullHunt, [CVE-2026-63030 analysis](https://fullhunt.io/blog/2026/07/17/wp2shell-wordpress-core-pre-auth-rce-cve-2026-63030.html)
- OpenAI, [the Cycle Double Cover prompt](https://cdn.openai.com/pdf/04d1d1e4-bc75-476a-97cf-49055cd98d31/cdc_prompt.pdf) that Kues repurposed

**Coverage**

- Wordfence, ["wp2shell aftermath: the first critical unauthenticated WordPress core RCE in nearly a decade"](https://www.wordfence.com/blog/2026/07/wp2shell-aftermath-the-first-critical-unauthenticated-wordpress-core-rce-in-nearly-a-decade/)
- [Hacker News discussion](https://news.ycombinator.com/item?id=48951744) (17 July 2026)

**Related on this blog**

- [The Swarm Is the Branding. One Agent in a Loop Did the Work.](/posts/t3mp3st-multi-agent-red-teaming). Steer-and-swarm agents turned into 0-day hunters
- [Three Indirection Steps From a Reverse Shell](/posts/ai-agent-security-lethal-trifecta). When the model does the escalation for you