CVE-2025-67851

Improper Neutralization of Special Elements
Affects
Moodle, IOMAD
in
Moodle
No items found.
Versions
<4.1.22, >=4.2.0 <4.4.12, >=4.5.0 <4.5.8, >=5.0.0 <5.0.4, >=5.1.0 <5.1.1

Patch Available.

Exclamation circle icon
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. Many Moodle pages, including report tables, the grader report and the grade export plugins, let users download data as CSV, Excel or OpenDocument spreadsheet files.

A Formula Injection vulnerability (CVE-2025-67851) has been identified in the spreadsheet export code of Moodle and IOMAD, which allows a user who can store text that later appears in an export to plant a spreadsheet formula that runs when another user opens the downloaded file. Moodle tracks this issue as MSA-25-0055 (MDL-72744).

Per OWASP: CSV Injection, also known as Formula Injection, occurs when websites embed untrusted input inside CSV files. When a spreadsheet program such as Microsoft Excel or LibreOffice Calc is used to open a CSV, any cells starting with = will be interpreted by the software as a formula.

This issue affects all versions of Moodle before 4.1.22, versions 4.2.0 through 4.4.11, versions 4.5.0 through 4.5.7, versions 5.0.0 through 5.0.3, and version 5.1.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

Vulnerability Info

This Medium-severity vulnerability is found in the moodle/moodle package in all versions before 4.1.22, 4.2.0 through 4.4.11, 4.5.0 through 4.5.7, 5.0.0 through 5.0.3, and 5.1.0 of Moodle, and in IOMAD releases built on those versions. Moodle rates it Serious.

Moodle has two sets of spreadsheet writers. The dataformat plugins for CSV, Excel and ODS all extend core\dataformat\spout_base, which wrote each record exactly as it was given:

public function write_record($record, $rownum) {
    $row = Row::fromValues($this->format_record($record));
    $this->writer->addRow($row);
}

The older writers used by the grade export plugins, csv_export_writer, MoodleExcelWorkbook and MoodleODSWorkbook, also passed cell values through unchanged. csv_export_writer::add_data(), for example, ended with:

$delimiter = csv_import_reader::get_delimiter($this->delimiter);
fputcsv($this->fp, $row, $delimiter, $this->csvenclosure);

Spreadsheet applications treat a cell that starts with =, +, - or @ as a formula. Exports can include text that ordinary users control, such as names, profile fields, forum or database entries and feedback, so a user can enter a value like =HYPERLINK(...) or a formula that calls an external program, and it becomes a live formula in the file that a teacher or administrator downloads. Depending on the spreadsheet application and the user's answers to its warnings, such a formula can send data from the spreadsheet to an outside server or run commands on the user's computer. As the Moodle advisory notes, most modern spreadsheet software warns before running risky formulas, but users may still accept the warning. The risk falls on the person who opens the export, not on the Moodle server.

The fix adds core\dataformat::escape_spreadsheet_formula(), which puts a single quote in front of any string value that starts with a formula character once leading whitespace and control characters (such as tabs, carriage returns and null bytes) are trimmed for the check. A lone -, which Moodle uses for empty values, is left alone:

public static function escape_spreadsheet_formula(mixed $value): ?string {
    ...
    // Trim only for checking, not for modifying output.
    $trimmed = ltrim($value);
    ...
    $formulacharacters = ['=', '+', '-', '@'];

    // If trimmed version starts with formula character, escape it.
    if (in_array($trimmed[0], $formulacharacters, true)) {
        // Preserve original whitespace. Do not alter actual content.
        return "'" . $value;
    }

spout_base::write_record(), csv_export_writer::add_data(), MoodleExcelWorksheet::write_string() and MoodleODSWorksheet::write_string() now pass every value through this function before writing it.

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.1.22, 4.4.12, 4.5.8, 5.0.4, 5.1.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

  • Brendan Heywood (finder)
Vulnerability Details
Severity
Level
CVSS Assessment
Low
>=0 <4
Medium
>=4 <6
High
>=6 <8
Critical
>=8 <10
Medium
ID
CVE-2025-67851
PROJECT Affected
Moodle, IOMAD
Versions Affected
<4.1.22, >=4.2.0 <4.4.12, >=4.5.0 <4.5.8, >=5.0.0 <5.0.4, >=5.1.0 <5.1.1
NES Versions Affected
Published date
October 14, 2026
≈ Fix date
October 1, 2026
Category
Improper Neutralization of Special Elements
Vex Document
Download VEXHow do I use it?
Sign up for the latest vulnerability alerts fixed in
NES for Moodle
Rss feed icon
Subscribe via RSS
or

By submitting the form I acknowledge receipt of our Privacy Policy.

Thanks for signing up for our Newsletter! We look forward to connecting with you.
Oops! Something went wrong while submitting the form.