Joomla! Novarain/Tassos Framework Vulnerabilities February 16, 2026 SSD Secure Disclosure technical team Vulnerability publication Summary Source code review of the Novarain/Tassos Framework revealed three critical primitives – unauthenticated file read, unauthenticated file deletion, and SQL injection leading to arbitrary database read – across five widely deployed Joomla! extensions (Convert Forms, EngageBox, Google Structured Data, Advanced Custom Fields, and Smile Pack). Taken together, these flaws enable reliable remote code execution (RCE) and administrator account takeover on unpatched Joomla! instances. Vendor Response The vendor has released updates, you can find them in the Downloads section of our site: https://www.tassos.gr/downloads Credit The vulnerabilities have been discovered by, an independent security researcher p1r0x, working with SSD Secure Disclosure. Affected Versions Novarain/Tassos Framework ( plg_system_nrframework ) v4.10.14 – v6.0.37 Convert Forms v3.2.12 – v5.1.0 EngageBox v6.0.0 – v7.1.0 Google Structured Data v5.1.7 – v6.1.0 Advanced Custom Fields v2.2.0 – v3.1.0 Smile Pack v1.0.0 – v2.1.0 Vulnerability Details All affected extensions ship the same system plugin, historically named Novarain Framework and later rebranded as Tassos Framework. The vulnerable code resides in plg_system_nrframework , retrieved from the vendor release site . Environment Setup Testing leveraged the official Joomla! Docker image alongside MariaDB. A ready-to-use Compose specification is available at env-setup/compose.yml : db: image: mariadb:11 container_name: joomla-db restart: unless-stopped environment: MARIADB_DATABASE: joomla MARIADB_USER: joomla MARIADB_PASSWORD: test123# MARIADB_ROOT_PASSWORD: admin123# volumes: - db_data:/var/lib/mysql Deploy the stack, complete the Joomla! installer, and then upload any target extension via System → Manage → Extensions → Install . Installation method does not affect exploitability, but ensure the extension status is set to Enabled . Source code analysis In plg_system_nrframework folder, there is a nrframework.php file. /** * Listens to AJAX requests on ?option=com_ajax&format=raw&plugin=nrframework * * @return void */ public function onAjaxNrframework() { Session::checkToken('request') or jexit(Text::_('JINVALID_TOKEN')); // Check if we have a valid task $task = $this->app->input->get('task', null); $non_admin_tasks = [ 'include' ]; // Only in backend if (!in_array(strtolower($task), $non_admin_tasks) && !$this->app->isClient('administrator')) { return; } // Check if we have a valid method task $taskMethod = 'ajaxTask' . $task; if (!method_exists($this, $taskMethod)) { die('Task not found'); } $this->$taskMethod(); } In this code block, we can see, that this is an AJAX listener, which to unauthorized users only allows non_admin_tasks , which is only include . Therefore, the user is only allowed to call the function ajaxTaskInclude (method names in PHP are case insensitive). private function ajaxTaskInclude() { $input = $this->app->input; $file = $input->get('file'); $path = JPATH_SITE . '/' . $input->get('path', '', 'RAW'); $class = $input->get('class'); $file_to_include = $path . $file . '.php'; if (!file_exists($file_to_include)) { die('FILE_ERROR'); } @include_once $file_to_include; if (!class_exists($class)) { die('CLASS_ERROR'); } if (!method_exists($class, 'onAJAX')) { die('METHOD_ERROR'); } (new $class())->onAJAX($input->getArray()); } This function takes the file, path and class input, and then checks if a PHP file with the stated class and method called onAjax exists. If it does, it includes the class and then calls the onAjax method in the given class. This is not a secure coding practice, since it can call any class in any file that contains method onAjax under JPATH_SITE root. Arbitrary File Read A file at plugins/system/nrframework/fields/nrchainedfields.php is one of the candidates, that has a method onAjax . public function onAjax($options) { $options = new Registry($options); if (!$select_id = $options->get('select_id')) { echo json_encode([ 'error' => true, 'response' => Text::_('NR_CANNOT_PROCESS_REQUEST') ]); jexit(); } if (!$value = $options->get('value')) { echo json_encode([ 'error' => true, 'response' => Text::_('NR_CANNOT_PROCESS_REQUEST') ]); jexit(); } if (!$value = json_decode($options->get('value'), true)) { echo json_encode([ 'error' => true, 'response' => Text::_('NR_CANNOT_PROCESS_REQUEST') ]); jexit(); } if (!$data_source = $options->get('data_source')) { echo json_encode([ 'error' => true, 'response' => Text::_('NR_CANNOT_PROCESS_REQUEST') ]); jexit(); } if (!$csv = $options->get('csv')) { echo json_encode([ 'error' => true, 'response' => Text::_('NR_CANNOT_PROCESS_REQUEST') ]); jexit(); } $csv = json_decode($csv, true); // get field ID from select ID $id = preg_replace('/_[0-9]+$/', '', $select_id); if (!$id || !$select_id || !$value || !$csv) { echo json_encode([ 'error' => true, 'response' => Text::_('NR_CANNOT_PROCESS_REQU...
Critical vulnerabilities in the Joomla! Novarain/Tassos Framework (`plg_system_