Tech 9 min read

Joomla JCE CVE-2026-48907 is exploited: patch 2.9.99.7 and hunt rogue profiles

IkesanContents

TL;DR

What happened Unauthenticated profile import in Joomla Content Editor (JCE) 1.0.0–2.9.99.4 reaches PHP upload and execution. CVSS v4.0 10.0. Added to CISA KEV on June 16, 2026; federal due date June 19, 2026.

What to do

  1. Update JCE to 2.9.99.7 — not 2.9.99.6, which has a regression that wrongly blocks legitimate uploads
  2. If you can’t reach PHP 7.4 / Joomla 3.10, apply the free patch for JCE 2.7.x–2.9.x
  3. Updating only closes the entry point; it does not clean a site that was already hit

What to check Editor profiles you don’t recognize (names like J940401, label Pwned), PHP files under images, media, tmp, and log hits on task=profiles.import.


Joomla Content Editor (JCE) CVE-2026-48907 was added to CISA KEV on June 16, 2026. It affects JCE 2.9.99.4 and earlier, registered in CISA’s JSON as improper access control in Widget Factory Joomla Content Editor. An unauthenticated user can create a new editor profile and, through it, reach PHP upload and execution.

The Hacker News ties together the KEV addition, JCE’s own advisory, mySites.guru’s field confirmation, and the public exploit code. The flaw was reported by the YesWeHack research team, and a PoC was later published separately on GitHub. NVD lists CVSS v4.0 at 10.0 CRITICAL and CVSS v3.1 at 9.8 CRITICAL. CISA’s SSVC (Stakeholder-Specific Vulnerability Categorization, used to set remediation priority) is also marked active, automatable, and technicalImpact total.

The entry point is the profile import

A JCE editor profile is the per-user-group setting that splits editor features and file operations. Permissions like allowed upload extensions, the file browser, the image manager, and the target directory are decided on the profile side.

The bug is that the profile import handler can be reached by an unauthenticated request. An attacker imports a profile they built themselves and, on the site, creates a configuration that allows uploading PHP and script files. Using that profile as a foothold, they place a web shell (a malicious file that runs arbitrary commands or PHP code over HTTP).

In YesWeHack’s analysis, this RCE comes from three chained weaknesses. The first is missing authorization: the profile import handler only checked the CSRF token, not user authentication. The second is missing extension validation: File::makeSafe(), which sanitizes the file name, only strips characters that are illegal on the filesystem and never checks the file type, so a double extension like nuclei-<hash>.xml.php passes straight through. The third is disabled upload safety: internally, File::upload($source, $destination, false, true) is called with the fourth argument (allow unsafe) set to true, explicitly turning off Joomla’s built-in extension blacklist.

In practice, the attacker first grabs a CSRF token from a public page’s HTML, then sends a crafted multipart request to profiles.import to insert the profile. Through that profile, a web shell is written under tmp, and accessing it over HTTP GET executes the PHP.

mySites.guru reports finding rogue profiles and web shells on real Joomla sites. It started with 3 sites in a single managed portfolio and has since reached the hundreds. After the public exploit code dropped on June 9, 2026, automated attacks against JCE sites spread, and mySites.guru expects thousands within days. It points to the 2012 ImageManager flaw, the same kind of unauthenticated upload, which eventually reached tens of thousands of sites, as a reference for scale. The reported targets are mostly Linux web servers.

Whether public registration is open or closed doesn’t change the verdict. The entry point here is not creating a registered user but the unauthenticated profile import task, so any site that exposes the JCE component externally is in scope for the same check.

flowchart TD
    A["Grab CSRF token from a public page"] --> B["Send to profiles.import unauthenticated"]
    B --> C["Create rogue import profile"]
    C --> D["Disable the extension blacklist"]
    D --> E["Drop .xml.php webshell under tmp"]
    E --> F["Execute PHP via HTTP GET"]

2.9.99.5 closes the hole, but go to 2.9.99.7

JCE released 2.9.99.5 on June 3, 2026, fixing the critical vulnerability in 2.9.99.4 and earlier. On June 6, 2.9.99.6 added more hardening to narrow the attack path. But 2.9.99.6 has a bug where a false-positive PHP-tag check also blocks legitimate image and file uploads; 2.9.99.7 fixes that and adds further hardening. Don’t stop at 2.9.99.6 — go all the way to 2.9.99.7.

2.9.99.7 requires PHP 7.4+ and Joomla 3.10+. For sites that can’t go that far, a free patch package is available for JCE 2.7.x, 2.8.x, and 2.9.x. It only closes the vulnerability, though, and does not include the additional hardening from 2.9.99.6 onward. JCE 2.6.x appears to have the unauthenticated profile import path closed in its default configuration, but the vendor itself treats that as not independently verified. 2.6.x is out of support, so it stays on the migration list.

What changed with the KEV listing isn’t the high score but that the flaw moved into confirmed-exploited status. I wrote about this in LiteLLM’s CISA KEV RCE too: KEV is run as a list of “confirmed exploited in the wild,” not “theoretically dangerous.” The due date here is June 19, 2026, only three days after the addition.

Updating doesn’t remove what was already dropped

What JCE stresses is that updating and cleanup are separate jobs. Updating JCE closes the profile import entry point. But rogue profiles created before the update, and PHP files already dropped, won’t disappear on their own.

In the JCE admin, check for editor profiles you don’t remember creating. The rogue profiles mySites.guru reports often have machine-generated names: a capital J followed by six digits (J940401, J938560, and so on). Some use the name Pwned with RCE via JCE in the description. Some set ordering to a large negative value like -99999 to force the profile to the top of the list. Inside the profile, check whether the Image Manager or File Browser Permitted File Extensions include PHP or script extensions (php, phtml, txt).

To check straight from the database, search the #__wf_profiles table (#__ is the Joomla table prefix) by name pattern.

SELECT id, name FROM `#__wf_profiles` WHERE name REGEXP '^J[0-9]{6}$';

In the logs, look for the following two requests, which arrive unauthenticated:

POST .../index.php?option=com_jce&task=profiles.import                          → 200
POST .../index.php?option=com_jce&task=plugin.rpc&plugin=browser&method=upload  → 200

A profiles.import immediately followed by a browser-plugin upload (plugin.rpc) returning 200 is the typical trace. The URL sometimes keeps an attacker marker like id=RCExxx (RCEc37, RCE401, and so on). The timestamp of that first request is a rough marker for when the compromise began. Hosting environments sometimes keep access logs only briefly, so if you put the update off, you can lose the time you were first hit.

On the file side, check for PHP files under images, media, tmp, plus media/system/js and libraries/joomla. JCE also mentions files with php in the name, like foo.php.xml. mySites.guru lists real examples: .xml.php double-extension droppers, obfuscated web shells containing eval(gzinflate(base64_decode(...))) or shell_exec($_POST), and a marker file named Nxploited. If the profile doesn’t specify an upload target, files land in the default images, so start there.

ShowDoc’s file-upload RCE had the same shape. When extension control on an upload feature breaks down, an attacker puts a PHP file somewhere callable from the web, and from then on plain HTTP access is enough to reach code execution on the server. With JCE, the difference is that swapping the profile is what lets the attacker decide what may be uploaded.

Triage starts with whether JCE is installed

This blog hasn’t covered Joomla, JCE, or Widget Factory themselves yet. The closest are CISA-KEV RCEs and CMS and PHP file uploads where a web shell is left behind after compromise, and the response pattern is the same.

When you manage multiple sites, the first thing to check is whether JCE is installed and which version. Both JCE Free and JCE Pro are affected. For 2.9.99.4 and earlier, handle the update and the forensic check in the same ticket, regardless of external exposure, whether registration is open, or the major Joomla version.

If you find a compromise, keep a copy of the rogue profiles and suspicious files before deleting anything. Then update JCE to 2.9.99.7 to close the entry point, and delete the rogue profiles and uploaded files. Change the admin login, database, hosting, and FTP passwords, and invalidate login sessions. If the same credentials were reused on other sites, swap those out as well. Finally, run a full scan to confirm no other backdoors remain.

References