CVE-2026-58334
Patch Available.
This Vulnerability has been fixed in the Never-Ending Support (NES) version offered by HeroDevs.
Overview
Moodle is an open source learning management system written in PHP. Schools, universities, and companies use it to run online courses. IOMAD is a multi-tenant distribution of Moodle that lets one installation serve several companies or organizations; it is built on Moodle core and shares the affected code. The admin presets tool (tool_admin_presets) lets a site administrator export the site's configuration as an XML file, import preset files, and apply a preset to change many settings at once.
A Remote Code Execution (RCE) vulnerability (CVE-2026-58334) has been identified in the admin presets import and apply process of Moodle and IOMAD, which allows a preset file to set the paths of the executable programs that Moodle runs on the server, bypassing the $CFG->preventexecpath protection, and so run arbitrary commands. Moodle tracks this issue as MSA-26-0015 (MDL-88735).
Per MITRE CWE-15: One or more system settings or configuration elements can be externally controlled by a user. Allowing external control of system settings can disrupt service or cause an application to behave in unexpected, and potentially malicious ways.
This issue affects all versions of Moodle before 4.5.12, versions 5.0.0 through 5.0.7, versions 5.1.0 through 5.1.4, and version 5.2.0, including End-of-Life release lines such as Moodle 4.3. IOMAD releases built on these Moodle versions contain the same code and are affected as well.
Details
Module Info
- Product: Moodle, IOMAD
- Affected packages:
moodle/moodle(admin/presets,lib/mlbackend/python) - Affected versions: <4.5.12, >=5.0.0 <5.0.8, >=5.1.0 <5.1.5, >=5.2.0 <5.2.1
- GitHub repository: https://github.com/moodle/moodle (Moodle), https://github.com/iomad/iomad (IOMAD)
- Published packages: https://packagist.org/packages/moodle/moodle
- Package manager: Composer
- Fixed in:
- OSS Moodle 4.5.12, 5.0.8, 5.1.5, 5.2.1
- NES for Moodle v4.3.13
- NES for IOMAD v4.3.4
Vulnerability Info
This High-severity vulnerability is found in the moodle/moodle package in all versions before 4.5.12, 5.0.0 through 5.0.7, 5.1.0 through 5.1.4, and 5.2.0 of Moodle, and in IOMAD releases built on those versions. Moodle rates it Serious.
Several Moodle settings hold the path to a program on the server, such as pathtophp, pathtodu, pathtogs, and pathtopython. They are admin_setting_configexecutable settings, and Moodle builds shell commands from them when it needs to run those tools. Because a wrong value here means running an attacker's choice of program, Moodle offers $CFG->preventexecpath in config.php. When it is set, the settings page shows these fields read only, and admin_setting_configfile::write_setting() refuses to change them:
public function write_setting($data) {
global $CFG;
if (!empty($CFG->preventexecpath)) {
if ($this->get_setting() === null) {
// Use default during installation.
$data = $this->get_defaultsetting();
if ($data === null) {
$data = '';
}
} else {
return '';
}
}
return parent::write_setting($data);
}The admin presets tool did not go through that method. core_adminpresets\manager::import_preset() stored every setting it recognised in the XML file, and apply_settings() later wrote the values with the preset classes' own save_value(), which calls set_config() directly. The manager mapped executable path settings to the plain text preset class, so no check was made that the value was a real program:
'adminpresets_admin_setting_configexecutable' => 'adminpresets_admin_setting_configtext',A preset file could therefore set any executable path to any string, even on sites that had locked these paths with $CFG->preventexecpath. Some of the code that runs these programs also built the command line from the raw path. The Python machine learning backend, for example, started its command with the configured path and no escaping:
$cmd = $this->pathtopython . ' -m moodlemlbackend.' . $modulename . ' ';
foreach ($params as $param) {
$cmd .= escapeshellarg($param) . ' ';
}Importing and applying presets requires the moodle/site:config capability, so this is reachable by site administrators. The risk is that an administrator account, or an administrator who imports a preset file obtained from someone else, can change the programs Moodle executes and run commands on the server as the web server user. That defeats the purpose of $CFG->preventexecpath, which exists so that administrator access through the web interface does not turn into command execution on the server.
The fix adds checks in both steps. import_preset() no longer imports executable or directory path settings when $CFG->preventexecpath is set, and apply_settings() skips them in that case and also skips any executable path that does not point to an existing, executable file:
$settingdata = $presetsetting->get_settingdata();
if ($settingdata instanceof \admin_setting_configfile && !empty($CFG->preventexecpath)) {
$skipped[] = $data;
continue;
}
if ($settingdata instanceof \admin_setting_configexecutable) {
$execpath = $presetsetting->get_value();
if (!empty($execpath)) {
require_once($CFG->libdir . '/filelib.php');
if (!file_exists($execpath) || is_dir($execpath) || !file_is_executable($execpath)) {
$skipped[] = $data;
continue;
}
}
}A companion change in lib/mlbackend/python/classes/processor.php wraps the Python path in escapeshellarg() at the three places that build the backend's command line.
Mitigation
Moodle publishes security fixes only for its supported release lines. Earlier release lines, including Moodle 4.3 and the IOMAD releases built on it, are End-of-Life and will not receive any public updates to address this issue.
Users of the affected components should apply one of the following mitigations:
- Upgrade to Moodle 4.5.12, 5.0.8, 5.1.5, 5.2.1, or later, or to an IOMAD release built on one of those versions.
- Leverage a commercial support partner like HeroDevs for post-EOL security support.
Credits
- LoWeST (finder)