CVE-2025-67848

Incorrect Authorization
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. The Publish as LTI tool feature (enrol_lti) lets other learning platforms launch courses and activities on a Moodle site over LTI. Launched users are matched to Moodle accounts and logged in automatically: legacy LTI launches go through the enrol_lti tool provider, and LTI 1.3 launches go through the LTI authentication plugin (auth_lti).

An Improper Access Control vulnerability (CVE-2025-67848) has been identified in the LTI provider of Moodle and IOMAD, which allows a user whose Moodle account has been suspended to keep logging in through an LTI launch from a connected platform. Only sites that publish courses or activities as LTI tools are affected. Moodle tracks this issue as MSA-25-0052 (MDL-87286).

Per MITRE CWE-284: The product does not restrict or incorrectly restricts access to a resource from an unauthorized actor.

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 High-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.

Suspending an account is how administrators stop someone from logging in without deleting their data. On the login form, authenticate_user_login() enforces this by refusing suspended accounts. The LTI code paths do not use that function: they identify the user from the launch and call complete_user_login() directly. For LTI 1.3, auth_plugin_lti::complete_login() handled a platform user who was already linked to a Moodle account like this:

if ($this->get_user_binding($launchdata['iss'], $launchdata['sub'])) {
    $user = $this->find_or_create_user_from_launch($launchdata);

    if (isloggedin()) {
        // If a different user is currently logged in, authenticate the linked user instead.
        global $USER;
        if ($USER->id !== $user->id) {
            complete_user_login($user);
        }
        // If the linked user is already logged in, skip the call to complete_user_login() because this affects deep linking
        // workflows on sites publishing and consuming resources on the same site, due to the regenerated sesskey.
    } else {
        complete_user_login($user);

The legacy tool provider in enrol/lti/classes/tool_provider.php did the same. It looked up the existing account by the username built from the launch, updated it from the launch data, and later called complete_user_login(). Neither path checked the account's suspended field.

A suspended user who can still launch the tool from the connected platform, for example through their account on another learning system, is logged in to Moodle with a full session. They can then reach the published course or activity, and other parts of the site their account can access, even though an administrator has suspended them.

The fix checks the suspended field before logging the user in. In auth_lti, a suspended account now produces a failed-login event with the reason AUTH_LOGIN_SUSPENDED and an invalidlogin error:

if ($user->suspended) {
    $failurereason = AUTH_LOGIN_SUSPENDED;
    $event = \core\event\user_login_failed::create([
        'userid' => $user->id,
        'other' => [
            'username' => $user->username,
            'reason' => $failurereason
        ]
    ]);
    $event->trigger();
    throw new \core\exception\moodle_exception('invalidlogin', 'core');
}

The enrol_lti tool provider gets the same check for existing accounts, before it updates or logs in the user.

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.

Until an upgrade is possible, sites that do not need to publish content over LTI can disable the Publish as LTI tool enrolment plugin.

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

  • Attilio Ferrari (finder)
Vulnerability Details
Severity
Level
CVSS Assessment
Low
>=0 <4
Medium
>=4 <6
High
>=6 <8
Critical
>=8 <10
High
ID
CVE-2025-67848
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
Incorrect Authorization
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.