Executive Summary
CVE-2026-48907 is a critical unauthenticated remote code execution vulnerability in the Joomla Content Editor (JCE) plugin, developed by The Widget Factory and Ryan Demmer. JCE is one of the most widely installed Joomla extensions, with installations across a significant proportion of the approximately 2 million active Joomla sites globally.
The vulnerability exists in the plugin’s profile import endpoint. A combination of missing authentication checks, absent file extension validation, and explicitly disabled upload safety controls allows any unauthenticated attacker to upload a PHP webshell and execute it within seconds. The exploit requires only a valid CSRF token, which is trivially obtainable from any public-facing Joomla page.
CISA added CVE-2026-48907 to the Known Exploited Vulnerabilities (KEV) catalog on June 16, 2026, with a remediation deadline of June 19, 2026. The vulnerability is actively exploited by automated botnets performing opportunistic scanning. A public proof-of-concept and Docker-based exploitation environment are available on GitHub.
CVSS 4.0 score: 10.0 (CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/E:A/AU:Y).
Affected Versions
All JCE versions from 1.0.0 through 2.9.99.4 are vulnerable. This encompasses the entire history of the plugin.
JCE 2.9.99.5 introduces the initial patch (released June 3, 2026, two days before CVE assignment). JCE 2.9.99.6 adds further hardening and codebase-wide security review (released June 8, 2026). The vendor has also released free patch packages for older 2.7.x, 2.8.x, and 2.9.x branches to address sites running non-current major versions.
Joomla 3.x installations cannot receive the current patch due to platform incompatibility and remain exposed. Legacy Joomla 3.x sites running JCE should be treated as compromised-pending-discovery.
Vulnerability Details
The vulnerability is a three-part exploit chain, each weakness individually necessary for full exploitation.
Weakness 1: Missing Authorization on the Profile Import Endpoint
The endpoint index.php?option=com_jce&task=profiles.import performed CSRF token validation only — it did not check whether the requesting user was authenticated or held the core.manage privilege. CSRF tokens in Joomla are embedded in public-facing page HTML and JavaScript metadata. Any unauthenticated client that makes a GET request to the Joomla homepage can harvest a valid CSRF token and replay it in a subsequent POST to the import endpoint. The CSRF check was purely an origin control, not an access control.
Weakness 2: No File Extension Validation
The upload handler called File::makeSafe() to sanitize the uploaded filename. This function sanitizes special characters but does not inspect or restrict file extensions. A file named nuclei-deadbeef.xml.php passes makeSafe() unchanged. The double-extension filename causes the web server to interpret the file as PHP when requested.
Weakness 3: Upload Safety Controls Explicitly Disabled
The upload call used the following invocation:
File::upload($source, $destination, false, true)
The fourth argument ($allow_unsafe) was set to true. This parameter explicitly disables Joomla’s built-in extension blacklist, which would normally reject .php and other executable extension types. The platform’s own defense-in-depth was disabled at the code level.
Combined Attack Surface
The intersection of these three weaknesses produces a complete pre-authentication PHP upload and execution primitive with no technical barriers.
Exploitation in the Wild
Exploit Chain (step by step):
- Token extraction: Attacker sends
GET /and extracts the CSRF token from the HTML response. - Webshell upload: Attacker sends
POST /index.php?option=com_jce&task=profiles.importas amultipart/form-datarequest with a PHP webshell embedded in a file namednuclei-<hash>.xml.php. The file lands in the Joomla/tmp/directory by default. - RCE trigger: Attacker sends
GET /tmp/nuclei-<hash>.xml.php. Because Joomla’s default configuration permits PHP execution from/tmp/, the shell executes immediately.
Full webshell variants also upload to /images/, /media/, or /images/jce/ depending on installation configuration.
The minimal confirmation payload is <?= 45*69 ?>, which returns 3105 on a vulnerable target. The public PoC (github.com/ywh-jfellus/CVE-2026-48907) includes a Docker Compose environment for side-by-side testing of vulnerable (2.9.99.4) and patched (2.9.99.5) versions.
Timeline:
| Date | Event |
|---|---|
| June 3, 2026 | JCE 2.9.99.5 patch released |
| June 5, 2026 | CVE-2026-48907 assigned by Joomla! Project CNA |
| June 8, 2026 | JCE 2.9.99.6 hardening release |
| June 9, 2026 | Public PoC documented (GitHub, Sploitus) |
| June 12–16, 2026 | Active exploitation confirmed by vendor and external researchers |
| June 16, 2026 | Added to CISA KEV catalog |
Threat Actor Context:
No specific named threat actor or ransomware group has been attributed to exploitation at this time. Observed exploitation is opportunistic and automated: botnet scanning began within days of public PoC publication. Observed post-exploitation activity includes defacement and cryptocurrency mining implant deployment. The attack is rated automatable (AU:Y) in the CVSS 4.0 vector; at scale, mass exploitation of unpatched Joomla installations is straightforward. The CISA KEV listing with a three-day remediation deadline reflects both the severity and the breadth of active scanning.
Patch and Remediation
Immediate action: Update JCE to version 2.9.99.6 or later via the Joomla Extension Manager. Version 2.9.99.5 resolves the core vulnerability; 2.9.99.6 adds additional hardening and is preferred.
For sites unable to update immediately: The vendor has released free patch packages for older 2.7.x, 2.8.x, and 2.9.x branches. Apply the appropriate legacy patch if a version upgrade is not immediately feasible.
For Joomla 3.x sites: No patch is available. Consider these installations unmitigatable and escalate to full assessment and migration planning.
Patches applied in 2.9.99.5+:
- Added
$user->authorise('core.manage', 'com_jce')authentication check on the import endpoint — unauthenticated requests are now rejected before any file handling occurs. - Extension allowlist: only
.xmlextensions are accepted, validated viapathinfo($filename, PATHINFO_EXTENSION). - Removed the
$allow_unsafe=trueparameter — Joomla’s built-in extension blacklist is now active for all uploads. - Upload size cap: 512 KB maximum.
- XXE protection: external entity loading disabled in the XML parser handling profile imports.
- XML field allowlist: only known-safe fields are processed from imported profile documents.
Network-level workaround (temporary, not a substitute for patching):
Block or rate-limit POST requests to paths matching index.php where the query string contains option=com_jce and task=profiles.import at the WAF or reverse proxy layer. This does not remediate the underlying vulnerability but reduces automated exploitation exposure while patching is underway.
Detection
Web server access logs:
Look for POST requests to /index.php where the query string contains com_jce and task=profiles.import. Any such POST from a session not authenticated as a Joomla admin is suspicious. Volume and IP diversity will indicate automated scanning.
grep "com_jce.*task=profiles.import" /var/log/apache2/access.log | grep "POST"
Filesystem indicators:
Scan for PHP files in locations where no PHP should exist:
/tmp/*.phpor/tmp/*.xml.php— primary drop location/images/jce/*.php/media/*.php- Any file matching
nuclei-*.xml.phpunder the Joomla webroot
find /var/www/html -name "*.php" -newer /var/www/html/configuration.php -not -path "*/libraries/*" -not -path "*/administrator/*"
JCE admin panel:
Rogue profiles created by the exploit appear at the top of the JCE profile list with auto-generated names. A secondary side-effect of exploitation is the removal of toolbar buttons from editor configurations. Sudden disappearance of editor toolbars from the Joomla backend is an indirect indicator.
IOCs:
- Filename pattern:
nuclei-[a-f0-9]+\.xml\.php - POST request URI:
/?option=com_jce&task=profiles.importor/index.php?option=com_jce&task=profiles.import - User-agent pattern: commonly automated (scripted) clients with minimal or absent user-agent strings in exploitation tooling
YARA-compatible file detection:
rule CVE_2026_48907_JCE_Webshell {
strings:
$php_tag = "<?php"
$system = "system(" nocase
$eval = "eval(" nocase
$passthru = "passthru(" nocase
condition:
$php_tag and (1 of ($system, $eval, $passthru))
and filename matches /nuclei-[a-f0-9]+\.xml\.php/
}
References: