# RCA Report: CVE-2026-56290 — Page Builder CK Unauthenticated Arbitrary File Upload to RCE

## Summary

CVE-2026-56290 is a critical unauthenticated arbitrary file upload vulnerability in the Page Builder CK Joomla extension (`com_pagebuilderck`) by Cédric Keiflin (joomlack.fr). The extension's front-end file upload handler (`browse.ajaxAddPicture`) performs no authentication or authorization checks — the only protection is a Joomla anti-CSRF token, which any unauthenticated visitor can retrieve from the site's public pages. Combined with attacker-controlled destination folder and filename (including extension), this allows any remote attacker to upload a PHP web shell to any writable directory on the server and execute it, resulting in full Remote Code Execution (RCE). The vulnerability affects all versions up to and including 3.5.10, and was fixed in version 3.6.0 (released June 27, 2026) by adding `CKFof::checkSecurity()` authorization checks to the upload controller and base controller's `execute()` method.

## Impact

- **Package/component affected**: `com_pagebuilderck` (Page Builder CK) Joomla extension
- **Affected versions**: All versions up to and including 3.5.10 (current line); also back-ported fixes for Joomla 3 (3.1.1) and Joomla 4 (3.4.10)
- **Risk level**: Critical (CVSS 4.0 Base Score: 10.0)
- **Consequences**: Full Remote Code Execution on the web server. An unauthenticated attacker can upload and execute arbitrary PHP code, leading to complete site compromise, data theft, defacement, backdoor planting, and use of the server to attack others. Active in-the-wild exploitation confirmed: web shells (e.g., `bhup.php`) found planted in `/media/com_pagebuilderck/gfonts/` on compromised sites.

## Impact Parity

- **Disclosed/claimed maximum impact**: Unauthenticated arbitrary file upload leading to full Remote Code Execution (CVSS 10.0, CWE-284/CWE-434)
- **Reproduced impact from this run**: Full RCE confirmed — an unauthenticated attacker uploaded a PHP web shell to the server and executed it via HTTP, obtaining server OS information (uname, current user) as proof of code execution
- **Parity**: `full`
- **Not demonstrated**: N/A — the complete attack chain from unauthenticated request to code execution was demonstrated end-to-end

## Root Cause

The vulnerability exists in the `CKBrowse::ajaxAddPicture()` method, which handles file uploads for the Page Builder CK extension's media manager. The root cause is a failure of access control (CWE-284):

1. **No authentication check**: The upload endpoint is accessible via the front-end (`site/controllers/browse.php` includes the admin controller). In the vulnerable version, the `CKController::execute()` method did not call `CKFof::checkSecurity()` for non-display tasks, and the `ajaxAddPicture()` controller method only called `CKFof::checkAjaxToken()` (CSRF token check) without any authentication or authorization check.

2. **CSRF token is not a security barrier**: Joomla's CSRF token is printed into public pages and can be retrieved by any visitor in a single HTTP GET request. The token is embedded in the page's `<script type="application/json" class="joomla-script-options new">` tag as `"csrf.token":"<32-char-hex>"`.

3. **Attacker-controlled destination and filename**: The `path` parameter in the upload request controls the destination directory, and the uploaded file's name (including extension) is used directly after `CKFile::makeSafe()` — which sanitizes the filename but does NOT block `.php` extensions. The extension check code is commented out in the source.

4. **No file type validation**: The upload handler accepts any file type. The code has a commented-out extension check (`// if (CKFile::getExt($filename) != 'jpg')`) that was never enforced.

**The fix** (version 3.6.0/3.6.1) adds `CKFof::checkSecurity()` calls in three locations:
- `CKController::execute()`: `if ($task !== 'display') CKFof::checkSecurity();` — blocks all non-display tasks for unauthorized users
- Individual controller methods (e.g., `browse.ajaxAddPicture()`): `CKFof::checkSecurity();` — redundant defense-in-depth
- Helper functions in `pagebuilderck.php`

`CKFof::checkSecurity()` calls `$user->authorise('core.edit', 'com_pagebuilderck')`, which returns false for guest users, causing a 403 exception.

## Reproduction Steps

1. **Reference**: `bundle/repro/reproduction_steps.sh`
2. **What the script does**:
   - Starts Joomla 5.2 + MariaDB 10.11 in Docker containers
   - Installs Joomla via CLI installer
   - Installs the Page Builder CK extension (v3.6.1, the fixed version)
   - Reverts the security fix (`CKFof::checkSecurity()` calls) to recreate the vulnerable state, equivalent to running version ≤ 3.5.10
   - Fixes permissions on the media directory (to match a real web-installed environment)
   - Obtains a CSRF token from the public Joomla home page (unauthenticated)
   - Uploads a PHP web shell via `POST /index.php?option=com_pagebuilderck&task=browse.ajaxAddPicture&<token>=1` with `path=media/com_pagebuilderck/gfonts`
   - Accesses the uploaded web shell via HTTP to execute PHP code (RCE proof)
   - Restores the fixed version and tests the negative control (should return 403)
3. **Expected evidence of reproduction**:
   - Upload response: `{"img":"/media/com_pagebuilderck/gfonts/exploit_shell.php","filename":"exploit_shell.php"}`
   - RCE output: `RCE_PROOF_<timestamp>Linux <hostname> <kernel> x86_64_www-data`
   - Fixed version: HTTP 403 "You don't have permission to access this"

## Evidence

### Log file locations
- `bundle/logs/evidence.log` — Full execution log with timestamps
- `bundle/logs/upload_vulnerable_response.txt` — Upload API response (vulnerable version)
- `bundle/logs/rce_vulnerable_output.txt` — Web shell execution output (RCE proof)
- `bundle/logs/upload_fixed_response.txt` — Upload attempt response (fixed version, 403)
- `bundle/logs/exploit_shell.php` — The uploaded PHP web shell
- `bundle/repro/runtime_manifest.json` — Runtime evidence manifest

### Key excerpts proving reproduction

**Upload success (vulnerable version)**:
```json
{"img" : "/media/com_pagebuilderck/gfonts/exploit_shell.php", "filename" : "exploit_shell.php"}
```

**RCE proof (web shell execution)**:
```
RCE_PROOF_1783247923Linux a32046ad96c2 7.0.14-arch1-1 #1 SMP PREEMPT_DYNAMIC Sat, 27 Jun 2026 16:15:10 +0000 x86_64_www-data
```

**Negative control (fixed version)**:
```html
<title>Error: 403</title>
...
<span class="badge bg-secondary">403</span> You don't have permission to access this.
```

### Environment details
- Joomla 5.2 (PHP 8.2.28, Apache 2.4.62)
- MariaDB 10.11
- Page Builder CK 3.6.1 (fix reverted to simulate ≤3.5.10)
- Docker containers with isolated network

## Recommendations / Next Steps

1. **Immediate action**: Upgrade Page Builder CK to version 3.6.0+ (or 3.1.1 for Joomla 3, 3.4.10 for Joomla 4)
2. **Check for compromise**: Search for stray `.php` files under `/media/com_pagebuilderck/` and its subfolders (especially `gfonts/`), and more broadly for PHP files containing upload handler signatures like `$_POST['_upl']`
3. **WAF rule**: Block unauthenticated POST requests to `index.php?option=com_pagebuilderck&task=browse.ajaxAddPicture` as a temporary mitigation
4. **Server hardening**: Disable PHP execution in upload/media directories via `.htaccess` (note: this is not a complete fix since the attacker controls the destination folder)
5. **Joomla core**: Keep Joomla updated to benefit from core `com_ajax` ACL hardening (Joomla 5.4.4+/6.0.4+)

## Additional Notes

- **Idempotency**: The script is idempotent — it tears down existing containers with `docker compose down -v` before starting fresh ones. Each run creates a clean environment.
- **Fix reversion approach**: The vulnerable version was recreated by taking the official fixed package (v3.6.1) and reverting the specific security fix (removing `CKFof::checkSecurity()` calls). This is equivalent to running the vulnerable version because the only change between 3.5.10 and 3.6.0 was the addition of these authorization checks. A minor `$_FILES` direct-access patch was also applied for Joomla 5.2 Input class compatibility.
- **Real-world exploitation**: This vulnerability was actively exploited in the wild within hours of the fix being released. Web shells were planted in `/media/com_pagebuilderck/gfonts/bhup.php` — the same directory path used in this reproduction.
- **CSRF token**: The Joomla CSRF token is session-based but available to all visitors. Any unauthenticated GET request to a public page returns the token in the page's JavaScript options.
