CVE-2026-48908: Verified Reproduction
CVE-2026-48908: SP Page Builder for Joomla allows unauthenticated arbitrary file upload via asset.uploadCustomIcon, enabling PHP upload and remote code execution.
CVE-2026-48908 is verified against SP Page Builder (com_sppagebuilder) · Joomla extension. Affected versions: 1.0.0 through 6.6.1. Fixed in 6.6.2. Vulnerability class: RCE. This critical reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00269.
What Is CVE-2026-48908?
CVE-2026-48908 is a critical unauthenticated arbitrary file upload vulnerability in SP Page Builder (com_sppagebuilder) for Joomla, reachable via the asset.uploadCustomIcon task, that lets an unauthenticated attacker upload a web shell and achieve remote code execution. Pruva reproduced it (reproduction REPRO-2026-00269).
CVE-2026-48908 Severity & CVSS Score
CVE-2026-48908 is rated critical severity, with a CVSS base score of 10.0 out of 10.
Critical — the most severe class — typically remotely exploitable with severe impact. Treat as an emergency.
Affected SP Page Builder (com_sppagebuilder) Versions
SP Page Builder (com_sppagebuilder) · Joomla extension versions 1.0.0 through 6.6.1 are affected.
How to Reproduce CVE-2026-48908
pruva-verify REPRO-2026-00269 curl -O https://www.pruva.dev/api/v1/reproductions/REPRO-2026-00269/artifacts/bundle/repro/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh Proof of Reproduction for CVE-2026-48908
- reached the target end-to-end
- full exploit chain demonstrated
- on the real production code path
- high confidence
- the upstream fix blocks the same trigger
multipart ZIP archive (custom_icon) containing .htaccess + uppercase .PHP web shell
- index.php?option=com_sppagebuilder&task=asset.uploadCustomIcon
reproduction_steps.sh How the agent worked
Root Cause and Exploit Chain for CVE-2026-48908
SP Page Builder for Joomla (com_sppagebuilder) exposes the controller task
index.php?option=com_sppagebuilder&task=asset.uploadCustomIcon to upload a
custom icon-font package. In versions 1.0.0 – 6.6.1 the task is reachable
without authentication, authorization, or a valid anti-CSRF token. The uploaded
ZIP archive is extracted and copied into the web root under
/media/com_sppagebuilder/assets/iconfont/<name>/, including its fonts/
subdirectory. Because the archive entries are not validated against an
extension allow-list, an attacker can package a web shell and a .htaccess
file that registers an uppercase .PHP extension with the PHP handler, then
execute the shell over HTTP. This yields unauthenticated remote code execution
as the web-server user.
- Package / component: SP Page Builder (
com_sppagebuilder) by JoomShaper —site/controllers/asset.php(SppagebuilderControllerAsset::uploadCustomIcon). - Affected versions: 1.0.0 – 6.6.1.
- Patched version: 6.6.2.
- Risk level: Critical (CWE-284 → CWE-434 Unrestricted Upload of File with Dangerous Type; advisory CVSS 4.0 10.0). Any unauthenticated remote attacker can upload and execute attacker-controlled PHP code on the Joomla host.
Impact Parity
- Disclosed / claimed maximum impact: Unauthenticated arbitrary file upload leading to remote code execution.
- Reproduced impact from this run: Full parity.
- Unauthenticated upload: The PoC sent a multipart
custom_iconZIP to theasset.uploadCustomIcontask with no Joomla session cookie and no CSRF token; the server accepted it and extracted the contents under the web root. - Code execution: The uploaded
.htaccessplus uppercase.PHPshell executed the PoC’secho 7*6marker (SPPB-RCE-42) and thenid, returninguid=33(www-data) gid=33(www-data) groups=33(www-data). - Negative control: The same PoC against the fixed 6.6.2 install received
HTTP 403 with the message
You require admin access, confirming the patch closes the path.
- Unauthenticated upload: The PoC sent a multipart
- Parity:
full. - Not demonstrated: Further post-exploitation (e.g., privilege escalation
beyond
www-data) is not part of the CVE claim.
Root Cause
In the vulnerable build the SppagebuilderControllerAsset class (in
site/controllers/asset.php) has no authentication, authorization, or CSRF
logic in its constructor or in the uploadCustomIcon() method. The method
reads the uploaded custom_icon file, validates only basic size/length limits,
writes it to a temporary ZIP, and calls the local unpack() method:
$zip_file = $tmp_path . '/builderCustomIcon.zip';
...
if (File::upload($tmp_src, $zip_file, false, true))
{
$extract = $this->unpack($zip_file);
...
Folder::copy($extract_path . '/' . $font_path, $rootPath . '/' . $fontFamily . '/fonts');
File::copy($extract_path . '/' . $font_css, $rootPath . '/' . $fontFamily . '/' . $font_css);
...
}
unpack() uses Joomla\Archive\Archive::extract() to unpack the ZIP into a
subdirectory of the Joomla tmp_path. The controller then copies the entire
fonts/ (and CSS) contents into the public web-root directory
JPATH_ROOT/media/com_sppagebuilder/assets/iconfont/<fontFamily>/. No
extension allow-list is enforced on the archive entries before copying, so the
attacker can include arbitrary files such as .htaccess and .PHP.
The server-side extension filter that does exist is a case-sensitive
block-list (rejects lowercase .php, .php3–.php8, .pht, .phtml,
.phar, etc.), but the block-list misses uppercase .PHP and .htaccess.
A default Apache PHP handler (<FilesMatch "\.php$">) does not execute
uppercase .PHP, so the PoC also drops a fonts/.htaccess containing:
AddType application/x-httpd-php .PHP
Where AllowOverride is permitted, this reconfigures the directory to treat
.PHP as PHP. The same HTTP request that uploaded the shell can then fetch it
from the web-accessible iconfont directory and execute it.
The 6.6.2 fix adds a constructor to SppagebuilderControllerAsset that
blocks unauthenticated/unauthorized requests before any method runs:
public function __construct($config = [])
{
parent::__construct($config);
$user = Factory::getUser();
$authorised = $user->authorise('core.admin', 'com_sppagebuilder')
|| $user->authorise('core.manage', 'com_sppagebuilder');
if (!$authorised)
{
...
$this->sendResponse($response, 403, true);
}
if (!$user->id)
{
...
$this->sendResponse($response, 401, true);
}
if (!Session::checkToken())
{
...
$this->sendResponse($response, 403, true);
}
}
This requires the user to be logged in, to have admin/manage privileges for the component, and to present a valid Joomla CSRF token, making the upload task unreachable from an unauthenticated attacker.
Reproduction Steps
- Script:
bundle/repro/reproduction_steps.sh(self-contained; exits 0 on confirmation, non-zero on failure). - What it does:
- Reads the durable project cache if one is configured, otherwise creates
bundle/artifacts/sppb. - Clones the public PoC
https://github.com/papageo75/CVE-2026-48908-PoC.gitonce and reuses it across runs. - For each role (
vulnandfixed):- Builds a Docker Compose stack with
joomla:5.2-php8.2-apacheandmysql:8.0, downloads the SP Page Builder ZIP (6.6.1for the vulnerable role,6.6.2for the fixed role), and installs it through Joomla’s web installer using the real administrator workflow. - Waits for the Joomla health check to return HTTP 200.
- Runs the PoC against the running container from the same Docker network
(
http://joomla), using the realasset.uploadCustomIconHTTP endpoint.
- Builds a Docker Compose stack with
- Writes
bundle/repro/runtime_manifest.jsonand per-role evidence logs underbundle/logs/.
- Reads the durable project cache if one is configured, otherwise creates
- Expected evidence of reproduction:
- Vulnerable (6.6.1): PoC prints
CODE EXECUTION CONFIRMED via '.htaccess+.PHP'and the output ofid(uid=33(www-data)). - Fixed (6.6.2): PoC prints
TARGET NOT VULNERABLE — SP Page Builder is patchedand the first upload attempt returns403 'require admin' = patched.
- Vulnerable (6.6.1): PoC prints
Evidence
Log file locations (written by reproduction_steps.sh):
bundle/logs/vuln_compose.log— Docker stack creation for the vulnerable run.bundle/logs/vuln_poc.log— PoC transcript showing RCE on 6.6.1.bundle/logs/fixed_compose.log— Docker stack creation for the fixed run.bundle/logs/fixed_poc.log— PoC transcript showing 6.6.2 rejects the upload.bundle/logs/reproduction_steps.log— full transcript of the latest run.bundle/repro/runtime_manifest.json— structured runtime evidence.
Key excerpts (from the latest verification run):
Vulnerable 6.6.1 — code execution confirmed:
[*] try .htaccess+.PHP -> EXECUTED
[+] CODE EXECUTION CONFIRMED via '.htaccess+.PHP' (echo 7*6 -> 42)
[+] webshell : http://joomla/media/com_sppagebuilder/assets/iconfont/.../fonts/....PHP?t=...&c=<cmd>
[*] running: id
------------------------------------------------------------
uid=33(www-data) gid=33(www-data) groups=33(www-data)
------------------------------------------------------------
Fixed 6.6.2 — upload now requires admin authentication:
[*] try .php -> 403 'require admin' = patched
[-] TARGET NOT VULNERABLE — SP Page Builder is patched (6.6.2+); the upload task now requires authenticated admin access.
Environment: Joomla 5.2 with PHP 8.2 (Apache), MySQL 8.0, SP Page Builder
6.6.1 (vulnerable) and 6.6.2 (fixed), running in Docker on a single custom
network. The PoC is executed from an ephemeral python:3-slim container on the
same network, with no session state or credentials.
Recommendations / Next Steps
- Upgrade to SP Page Builder 6.6.2 or later. The 6.6.2 patch adds the constructor checks described above, which are the primary fix.
- Defence in depth on the web server:
- Disable PHP execution in directories that are only expected to host static
assets (
/media/,/images/,/templates/*/css, etc.). - Set
AllowOverride Noneon these directories so an uploaded.htaccesscannot re-register handlers. - Use a case-insensitive extension allow-list (e.g., only
.ttf,.woff,.css,.json) on uploaded archive contents; never rely on a block-list of dangerous extensions.
- Disable PHP execution in directories that are only expected to host static
assets (
- Assume-breach review: search for unexpected
.php/.PHP,.htaccess, and newly created directories under/media/com_sppagebuilder/assets/iconfont/, and look for new Super User accounts or planted web shells. - Backport: if a site cannot upgrade immediately, apply the 6.6.2
constructor guard (authorization + user session +
Session::checkToken()) tosite/controllers/asset.php.
Additional Notes
- Idempotency: The reproduction script was run twice consecutively; both runs exited 0 with the same positive RCE evidence on the vulnerable build and the same 403 rejection on the fixed build.
- Limitations: The full RCE chain depends on the Apache configuration
permitting
AllowOverridein the iconfont directory and on PHP being enabled there. IfAllowOverrideis disabled or the case-sensitive.PHPhandler is blocked, the bug still permits unauthenticated file write but not direct RCE; this is still an unauthenticated arbitrary file upload vulnerability. - References:
- NVD — https://nvd.nist.gov/vuln/detail/CVE-2026-48908
- Technical write-up — https://mysites.guru/blog/sp-page-builder-zero-day-uploadcustomicon-rce/
- PoC repository — https://github.com/papageo75/CVE-2026-48908-PoC
- Vendor — https://www.joomshaper.com/page-builder
CVE-2026-48908 Reproduction Transcript
The agent's step-by-step process — every tool call, every handoff, the moment the exploit fired.
Full session Replay every step — scrub the timeline or play it back.
Artifacts and Evidence for CVE-2026-48908
Scripts, logs, diffs, and output captured during the reproduction.
How to Fix CVE-2026-48908
Upgrade SP Page Builder (com_sppagebuilder) · Joomla extension to 6.6.2 or later.
FAQ: CVE-2026-48908
How does the CVE-2026-48908 upload-to-RCE attack work?
.htaccess file that registers an uppercase .PHP extension with the PHP handler (evading naive extension filters) to the unauthenticated uploadCustomIcon task; the archive is extracted under the web root and the shell is then invoked directly over HTTP to execute arbitrary PHP.Which SP Page Builder versions are affected by CVE-2026-48908, and where is it fixed?
How severe is CVE-2026-48908?
How can I reproduce CVE-2026-48908?
asset.uploadCustomIcon task and demonstrates the extracted PHP shell executing under the web server user.References for CVE-2026-48908
Authoritative sources for CVE-2026-48908 — official vulnerability databases and the upstream advisory. Pruva's reproduction verifies the issue firsthand; these are the primary records to corroborate it.