CVE-2026-58340
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. Grade calculations refer to other grade items by their ID numbers, written as [[idnumber]]. The Edit calculation page in the gradebook setup lists the course's grade items and lets a teacher add ID numbers to items that do not have one.
A Cross-Site Scripting (XSS) vulnerability (CVE-2026-58340) has been identified in the grade calculation page of Moodle and IOMAD. The page saved new grade item ID numbers without checking the session token and printed them without escaping, which allows an attacker to store a script in a grade item ID number by getting a logged-in teacher to open a crafted link, and to run that script in the browser of anyone who later opens the page. Moodle tracks this issue as MSA-26-0021 (MDL-88542).
Per OWASP: Cross-Site Scripting (XSS) attacks are a type of injection, in which malicious scripts are injected into otherwise benign and trusted websites. XSS attacks occur when an attacker uses a web application to send malicious code, generally in the form of a browser side script, to a different end user. Flaws that allow these attacks to succeed are quite widespread and occur anywhere a web application uses input from a user within the output it generates without validating or encoding it.
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(grade/edit/tree/calculation.php) - 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.
grade/edit/tree/calculation.php reads the submitted ID numbers with optional_param_array('idnumbers', null, PARAM_RAW), so the values are not cleaned. The form includes a sesskey field, but the handler never checked it before saving the values with add_idnumber():
} elseif (!empty($section) AND $section='idnumbers' AND !empty($idnumbers)) { // Handle idnumbers separately (non-mform)
//first validate and store the new idnumbers
foreach ($idnumbers as $giid => $value) {
if ($gi = grade_item::fetch(array('id' => $giid))) {When the page draws the grade tree, get_grade_tree() put each stored ID number into the HTML as it was:
if ($type != 'category') {
if (is_null($current_itemid) OR $grade_item->id != $current_itemid) {
if ($idnumber) {
$name .= ": [[$idnumber]]";The two problems combine. An attacker who gets a teacher to open a crafted link, or a page that sends the request in the background, can make that teacher save an ID number containing HTML and JavaScript on grade items that do not have an ID number yet. The script is stored and runs in the browser of whoever opens the calculation page for that course afterwards, with that user's session. The page requires moodle/grade:manage, which the editing teacher and manager archetypes have by default, so the victims are the course's teachers, managers, and administrators, and a script running in their session can act with their permissions.
Users who already hold moodle/grade:manage could save such a value directly, and Moodle flags that capability with an XSS risk. The cross-site request forgery is what lets an attacker without that capability store the script.
The fix calls require_sesskey() before any ID number is saved, and escapes the ID number with s() when the tree is printed ($name .= ": [[" . s($idnumber) . "]]";):
} elseif (!empty($section) AND $section='idnumbers' AND !empty($idnumbers)) { // Handle idnumbers separately (non-mform)
require_sesskey();
//first validate and store the new idnumbersMitigation
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
- Paul Holden from Moodle HQ (finder)