Back to Blog
Insights

Click2Shell: WordPress Core Flaw Turns One Click Into RCE

Click2Shell: WordPress Core Flaw Turns One Click Into RCE

On 17 September 2026, WordPress shipped 7.1.1, a maintenance and security release containing 11 core fixes. One of them closes Click2Shell: a selector-injection flaw in core, found by the research team at pwn.ai, that makes a WordPress site install a theme by itself the moment a logged-in administrator opens an attacker's link. On its own that is a high-severity oddity: the theme installs but stays inactive, and nothing on the site looks different. Chained with a real vulnerability in an ordinary catalog theme, it becomes remote code execution: the attacker's PHP running on your server after a single click. Here is exactly how the chain works, who is affected, and what to do.

What it is

FieldValue
NameClick2Shell (pwn.ai)
CVENot yet assigned. WordPress has confirmed one is coming
ClassCWE-74/CWE-943: injection into a CSS/jQuery selector (DOM selector injection)
Severity7.1 High standalone · ~9.3–9.6 Critical chained to RCE (pwn.ai assessment; THN reported 9.6)
AuthenticationAttacker needs no account, but a logged-in administrator must open the link
AffectedWordPress 6.0 through pre-7.1.1 (pwn.ai expects all versions before 7.1.1)
Fixed inWordPress 7.1.1 (17 September 2026), changeset 63664, backported to 4.7+
Exploited in the wildNo, unlike wp2shell, which CISA lists as actively exploited

One value, two interpretations

The bug starts on a completely ordinary admin route:

/wp-admin/theme-install.php?theme=THEME_SLUG

Inside wp-admin/js/theme.js, the value of theme is used twice, and the two consumers disagree about what it means:

  1. Server-side, the value is sent to the WordPress.org Themes API, which slug-canonicalizes it. Garbage punctuation gets sanitized away and the API returns a genuine catalog theme.
  2. Client-side, the browser reuses the raw, unescaped value inside a jQuery selector:
request.theme = slug;
self.view.collection.query( request );

self.view.collection.once( 'query:success', function() {
    $( 'div[data-slug="' + slug + '"]' ).trigger( 'click' );
});

That .trigger( 'click' ) is meant to open the theme's preview card. But the attacker controls the selector syntax. With a route value like:

twentytwenty"]>*>*>*/*

the API still returns the real twentytwenty theme, while the browser builds this selector:

div[data-slug="twentytwenty"]>*>*>*/*"]

The injected quote closes the attribute selector, the child combinators (>) walk from the theme card into its action buttons, and the trailing CSS comment neutralizes whatever WordPress appends. The selector lands on the genuine Install control, and WordPress's own JavaScript clicks it.

This is the elegance of the bug: the attacker never touches the install nonce or the install_themes capability. The victim's authenticated admin session supplies both, and WordPress spends them on the attacker's behalf.

From forced install to remote code execution

A silently installed theme sounds significant but inert. And by itself, it is. The theme stays inactive; the site's appearance never changes. pwn.ai is explicit that the core bug "does not accept an arbitrary theme ZIP": it only installs real packages from the official catalog.

The chain completes because of two lesser-known WordPress behaviours:

1. Inactive themes are not dormant. When the Customizer prepares a preview, WordPress loads the inactive theme's functions.php, even while a different theme remains the live one:

/wp-admin/admin-ajax.php?wp_customize=on&customize_theme=mobile-repair-zone

That request registers the theme's hooks and AJAX handlers with no activation required.

2. Catalog themes contain real vulnerabilities. pwn.ai audited the catalog for code reachable before activation and found that the then-current Mobile Repair Zone 2.5.4 theme (along with more than 40 other hosted themes) registered an AJAX installer with no nonce and no capability check:

add_action(
    'wp_ajax_mobile_repair_zone_install_and_activate_plugin',
    'mobile_repair_zone_install_and_activate_plugin'
);

The handler accepted attacker-controlled plugin_details (including a plugin_url), fetched that URL, wrote the bytes into the plugins directory, unpacked them, and loaded the plugin's entry point. No permission check anywhere.

Put the pieces together and one crafted link does the whole job:

Crafted theme-install URL
    ↓  Themes API canonicalizes → real catalog theme
jQuery selector injection → Install clicked automatically
    ↓  official theme ZIP written to disk (inactive)
Customizer preview loads the inactive theme's PHP
    ↓  unprotected AJAX handler becomes reachable
Attacker-selected plugin package fetched and included
    ↓
PHP execution under the web-server account

At that point the attacker can read wp-config.php and database credentials, access WooCommerce and plugin data, create users, and take over the site. Notably, nothing visible happens along the way: the original theme stays active and the attacker's theme stays switched off.

The one thing the attacker needs: a click

Click2Shell is not a pre-auth bug. The full chain only runs if a logged-in administrator opens the attacker's link: in an email, a comment, a support ticket, a chat message. That single open is the entire interaction: from then on everything is automatic, and the victim never clicks Install or Activate.

  • Already-authenticated admin visits the link → compromise.
  • Nobody logged in → the victim just sees the WordPress login page and the chain dies.

That user-interaction requirement is why pwn.ai scored the chain 9.3 (CVSS 3.1, UI:R) rather than higher and, alongside the core-only impact, why this flaw has not been observed in real-world attacks. Contrast that with July's wp2shell, which needed no login, no click, and sits on CISA's exploited-vulnerabilities list. The two bugs are unrelated. But they rhyme, and pwn.ai's August XSS2Shell chain (login-screen XSS to RCE) makes this the third core-to-shell chain in as many months.

Are you affected?

WordPress versionStatusAction
6.0 – 7.1.0Vulnerable to the forced-install bugUpdate to 7.1.1 now
Below 6.0Not affected by this specific bugUpdate anyway: you have other problems
7.1.1+Fixedn/a

WordPress backported the fix to all branches back to 4.7, and sites with automatic background updates will receive it on their own. But auto-updates are disabled on many managed and hardened hosts, so verify the version actually running rather than trusting the dashboard.

Even patched, audit whether the bug was used on your site before you updated:

  • List wp-content/themes/ and compare against what your team actually installed. An unfamiliar inactive theme, especially one nobody can explain, is the signature of a probe or a partial chain.
  • Search access logs for theme-install.php?theme= values containing URL-encoded selector syntax (%22, %5D, %3E, %2A) or for admin-ajax.php?wp_customize=on&customize_theme= requests that reference themes you never activated.
  • Check plugin directories for packages you did not add. The second stage of the chain writes there.

If you find those patterns landing before your patch date, treat the site as compromised and rebuild from a known-good backup.

How to protect your site

  1. Update to WordPress 7.1.1 immediately, or the matching backport for your branch. This is the only real fix; neither WordPress nor pwn.ai published a workaround.
  2. Delete themes you don't use, completely. This incident is the loudest possible confirmation of a rule we repeat in our WordPress security checklist: inactive code is still attack surface. WordPress itself loaded the inactive theme's PHP to complete this chain. "It's not activated" has never been a security control, and now it is demonstrably not even a barrier.
  3. Treat administrator sessions as the crown jewel. The chain rides on an admin's authenticated session, so the usual controls directly cut the attack's reach: 2FA on every administrator, phishing-resistant where possible, the fewest admin accounts you can live with, and admin-role users trained that a random login page after clicking a link is a red flag, not a speed bump.
  4. Keep a WAF in front of the dashboard. Rules that flag selector metacharacters in theme-install.php requests and anomalous admin-ajax.php?wp_customize= traffic give you both blocking and detection for this class of bug, including the 40+ themes with similar pre-activation flaws that pwn.ai says are still out there.

Frequently Asked Questions

Do I need a vulnerable theme to be affected?

For the forced install itself, no. That is the core bug and it works regardless of which themes your site runs. For remote code execution, yes: the demonstrated chain required a separate flaw in the installed theme (Mobile Repair Zone 2.5.4, plus 40+ others pwn.ai identified). Updating core closes the demonstrated chain against every theme.

Can I tell if a theme was silently installed on my site?

Yes. Compare the contents of wp-content/themes/ against themes you deliberately installed, and check your access logs for the detection signatures above. An unexplained inactive theme should be deleted and investigated, not ignored.

Is this bug being exploited in the wild?

There is no evidence of that, and WordPress has not attributed any incidents to it. The click requirement and the core-only impact keep it in a different risk class from wp2shell, which required no interaction and is listed by CISA as actively exploited.

Why is this serious if the theme never activates?

Because "inactive" does not mean "off". WordPress loads an inactive theme's PHP during Customizer previews, which was the bridge from installation to code execution. Any code sitting under wp-content/ is deployable attack surface, activated or not.


Click2Shell is a case study in modern WordPress exploitation: no single bug is a headline until you chain it: a selector injection nobody thought was exploitable, a preview feature nobody thought about, and an ordinary catalog theme that trusted its own AJAX handler. Chains like this are exactly what we hunt for in a penetration test, design against in secure web development, and watch for in managed detection. If you are not certain your sites were patched before someone tested the click on them, talk to us. We will help you find out.

Get Started

Want a security-first build?

Get a free security review. We'll look at where you stand today and tell you what to fix first, no strings attached.

Talk to an Expert
Click2Shell: WordPress Core Flaw Turns One Click Into RCE - IKZERO