Skip to content

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.

REPRO-2026-00269 SP Page Builder (com_sppagebuilder) · Joomla extension RCE Jul 8, 2026 CVE entry .txt
Severity
CRITICAL
CVSS
10.0
Confidence
HIGH
Reproduced in
77m 51s
Tool calls
489
Spend
$10.73
01 · Overview

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).

02 · Severity & CVSS

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 threat level
10.0 / 10 CVSS base
Weakness CWE-284 Improper Access Control; NVD also lists CWE-434 Unrestricted Upload of File with Dangerous Type

Critical — the most severe class — typically remotely exploitable with severe impact. Treat as an emergency.

03 · Affected Versions

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
or 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
Run in a VM or disposable container. This exploits a real vulnerability.
06 · Proof of Reproduction

Proof of Reproduction for CVE-2026-48908

Remote code execution — reproduced
  • 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
Trigger

multipart ZIP archive (custom_icon) containing .htaccess + uppercase .PHP web shell

Attack chain
  1. index.php?option=com_sppagebuilder&task=asset.uploadCustomIcon
Runnable proof: reproduction_steps.sh
Captured evidence: fixed pocfixed composevariant fixed testvariant fixed poc control
How the agent worked 1,354 events · 489 tool calls · 1h 18m
1h 18mDuration
489Tool calls
423Reasoning steps
1,354Events
10Dead-ends
Agent activity over 1h 18m
Support
13
Hypothesis
2
Repro
1,027
Judge
36
Variant
272
0:0077:51

Root Cause and Exploit Chain for CVE-2026-48908

Versions: 1.0.0 – 6.6.1.

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.
    1. Unauthenticated upload: The PoC sent a multipart custom_icon ZIP to the asset.uploadCustomIcon task with no Joomla session cookie and no CSRF token; the server accepted it and extracted the contents under the web root.
    2. Code execution: The uploaded .htaccess plus uppercase .PHP shell executed the PoC’s echo 7*6 marker (SPPB-RCE-42) and then id, returning uid=33(www-data) gid=33(www-data) groups=33(www-data).
    3. 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.
  • 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

  1. Script: bundle/repro/reproduction_steps.sh (self-contained; exits 0 on confirmation, non-zero on failure).
  2. 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.git once and reuses it across runs.
    • For each role (vuln and fixed):
      • Builds a Docker Compose stack with joomla:5.2-php8.2-apache and mysql:8.0, downloads the SP Page Builder ZIP (6.6.1 for the vulnerable role, 6.6.2 for 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 real asset.uploadCustomIcon HTTP endpoint.
    • Writes bundle/repro/runtime_manifest.json and per-role evidence logs under bundle/logs/.
  3. Expected evidence of reproduction:
    • Vulnerable (6.6.1): PoC prints CODE EXECUTION CONFIRMED via '.htaccess+.PHP' and the output of id (uid=33(www-data)).
    • Fixed (6.6.2): PoC prints TARGET NOT VULNERABLE — SP Page Builder is patched and the first upload attempt returns 403 'require admin' = patched.

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 None on these directories so an uploaded .htaccess cannot 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.
  • 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()) to site/controllers/asset.php.

Additional Notes

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.

Event 1/40
0:003:34
0:00
session startedaccounts/fireworks/models/kimi-k2p7-code · CVE-2026-48908 · REPRO-20
0:04
0:06
web search
0:07
0:09
0:10
0:26
0:26
extract_facts
no facts extracted
0:27
0:27
0:27
supportrepro
2:59
3:06
3:06
3:10
3:10
3:14
3:14
3:15
3:16
3:16
3:19
3:19
3:24
3:26
web search
3:27
3:32
3:34
web search
08 · How to Fix

How to Fix CVE-2026-48908

Upgrade SP Page Builder (com_sppagebuilder) · Joomla extension to 6.6.2 or later.

Coming soon

Step-by-step mitigation and hardening guidance for CVE-2026-48908 — configuration checks, workarounds where no patch exists, and how to verify you're protected — is on the way.

10 · FAQ

FAQ: CVE-2026-48908

How does the CVE-2026-48908 upload-to-RCE attack work?

An attacker submits a ZIP archive containing a PHP web shell plus a .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?

SP Page Builder 1.0.0 through 6.6.1 are affected; it is fixed in 6.6.2.

How severe is CVE-2026-48908?

Critical severity, CVSS 10.0 (maximum score), reflecting unauthenticated remote code execution requiring no privileges or user interaction.

How can I reproduce CVE-2026-48908?

Download the verified script and run it in an isolated environment against Joomla with SP Page Builder 1.0.0-6.6.1 installed; it sends an unauthenticated multipart ZIP upload to the asset.uploadCustomIcon task and demonstrates the extracted PHP shell executing under the web server user.
11 · References

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.