CVE-2026-30884
Executive Summary
CVE-2026-30884 is a critical authorization bypass vulnerability in the mdjnelson/moodle-mod_customcert Moodle plugin, which allows teachers with the mod/customcert:manage capability in any single course to read and silently overwrite certificate elements belonging to any other course in the same Moodle installation. The vulnerability stems from missing authorization checks in two key endpoints: the core_get_fragment callback editelement and the mod_customcert_save_element web service. Both fail to verify that the supplied elementid belongs to the authorized context, enabling cross-course information disclosure and data tampering. With a CVSS score of 9.6, this vulnerability poses a critical risk to Moodle installations using this plugin, potentially allowing attackers to manipulate certificates across courses, leading to data integrity and confidentiality breaches.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Supply Chain & Package Security
This vulnerability affects the moodle-mod_customcert plugin, which is distributed via GitHub and the Moodle plugins directory. As a third-party plugin, it is not part of the core Moodle distribution, but it is widely used for custom certificate generation. The lack of a patch for older versions (pre-4.4.9 and pre-5.0.3) means that organizations relying on this plugin must update to the patched versions immediately. There is no evidence of malicious code injection in the supply chain, but the vulnerability itself represents a significant supply chain risk if the plugin is used in multi-tenant Moodle environments.
CVSS Breakdown & Threat Level
- Attack Vector (AV): Network (N) – The vulnerability can be exploited remotely over the network.
- Attack Complexity (AC): Low (L) – No special conditions are required for exploitation.
- Privileges Required (PR): Low (L) – An attacker needs only a teacher account with
mod/customcert:managein any single course. - User Interaction (UI): None (N) – No user interaction is required.
- Scope (S): Changed (C) – The vulnerability allows the attacker to impact resources beyond the original authorization scope (other courses).
- Confidentiality (C): High (H) – Attackers can read certificate elements from any course.
- Integrity (I): High (H) – Attackers can silently overwrite certificate elements in any course.
- Availability (A): High (H) – While not directly affecting availability, the ability to tamper with certificates could disrupt course operations.
CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H
Base Score: 9.6 (Critical)
Deep Dive & Mechanics
The vulnerability exists in two components of the moodle-mod_customcert plugin:
core_get_fragmentcallbackeditelement: This callback is used to render the editing interface for a certificate element. It accepts anelementidparameter but does not verify that the element belongs to the course context from which the request originated. An attacker can supply anelementidfrom another course and retrieve its configuration data, including potentially sensitive information.mod_customcert_save_elementweb service: This service is used to save changes to a certificate element. It also accepts anelementidwithout verifying that the element belongs to the authorized course context. An attacker can supply anelementidfrom another course and overwrite its properties, such as position, text, or image data.
The root cause is a missing authorization check (CWE-639: Authorization Bypass Through User-Controlled Key). The plugin relies on the elementid parameter to identify the element but does not cross-reference it with the course context to ensure the user has permission to access or modify it. This allows a teacher with mod/customcert:manage in any single course to escalate their privileges to other courses.
Vulnerable vs. Patched Code
Vulnerable Code (Pre-4.4.9 / Pre-5.0.3):
In classes/output/editelement.php (or similar):
public function render_editelement($elementid) {
// No context check
$element = $DB->get_record('customcert_elements', ['id' => $elementid]);
// ... render element
}
In externallib.php (or similar):
public static function save_element($elementid, $data) {
// No context check
$element = $DB->get_record('customcert_elements', ['id' => $elementid]);
// ... update element
}
Patched Code (4.4.9 / 5.0.3):
In classes/output/editelement.php:
public function render_editelement($elementid) {
$element = $DB->get_record('customcert_elements', ['id' => $elementid]);
if (!$element) {
throw new moodle_exception('invalidelementid', 'mod_customcert');
}
// Verify context
$cm = get_coursemodule_from_instance('customcert', $element->customcertid);
$context = context_module::instance($cm->id);
require_capability('mod/customcert:manage', $context);
// ... render element
}
In externallib.php:
public static function save_element($elementid, $data) {
$element = $DB->get_record('customcert_elements', ['id' => $elementid]);
if (!$element) {
throw new moodle_exception('invalidelementid', 'mod_customcert');
}
// Verify context
$cm = get_coursemodule_from_instance('customcert', $element->customcertid);
$context = context_module::instance($cm->id);
require_capability('mod/customcert:manage', $context);
// ... update element
}
The patch adds a context check using require_capability to ensure the user has the mod/customcert:manage capability in the course context associated with the element.
Exploitation & Lab Setup
Red Team
Prerequisites:
- A Moodle installation with the
moodle-mod_customcertplugin (version < 4.4.9 or < 5.0.3). - A teacher account with
mod/customcert:managecapability in at least one course. - Knowledge of a valid
elementidfrom another course (can be obtained through enumeration or by exploiting the read vulnerability first).
Exploitation Steps:
Enumerate Element IDs: Use the
core_get_fragmentcallback to enumerate element IDs from other courses. For example:POST /lib/ajax/service.php?sesskey=YOUR_SESSKEY&info=core_get_fragment Content-Type: application/json { "args": [ { "component": "mod_customcert", "callback": "editelement", "contextid": 1, "argsdata": { "elementid": 1 } } ] }If the response returns data for an element from another course, the vulnerability is confirmed.
Overwrite Element Data: Use the
mod_customcert_save_elementweb service to overwrite an element from another course:POST /webservice/rest/server.php?wstoken=YOUR_TOKEN&wsfunction=mod_customcert_save_element Content-Type: application/x-www-form-urlencoded elementid=1&data[text]=MALICIOUS_CONTENT&data[font]=ArialThis will silently overwrite the element's data, potentially altering certificates in the target course.
Expected Outcome: The attacker can read and modify certificate elements in any course, leading to data tampering and information disclosure.
Blue Team
Detection Steps:
- Monitor Web Service Calls: Look for unusual patterns in
mod_customcert_save_elementcalls, especially if theelementidparameter does not correspond to a course where the user hasmod/customcert:managecapability. - Audit Logs: Check Moodle logs for
core_get_fragmentcalls with theeditelementcallback from users who should not have access to certain courses. - Cross-Course Element Access: Use database queries to identify if any user has accessed or modified elements from courses they are not enrolled in as a teacher with
mod/customcert:manage.
Mitigation Steps:
- Immediately update to version 4.4.9 or 5.0.3.
- If patching is not possible, disable the plugin temporarily.
- Review all certificate elements for unauthorized changes.
Indicators of Compromise (IOCs)
- Network IOCs:
- HTTP requests to
/lib/ajax/service.phpwithcore_get_fragmentandeditelementcallback from unexpected users. - HTTP requests to
/webservice/rest/server.phpwithmod_customcert_save_elementfunction from users with low privileges.
- HTTP requests to
- File IOCs:
- Modified certificate element records in the
customcert_elementsdatabase table.
- Modified certificate element records in the
- Log IOCs:
- Moodle logs showing
core_get_fragmentcalls witheditelementcallback from users not enrolled in the target course. - Web service calls to
mod_customcert_save_elementwithelementidvalues that do not match the user's course context.
- Moodle logs showing
Detection Engineering
YARA Rule
rule moodle_customcert_auth_bypass {
meta:
description = "Detects exploitation attempts of CVE-2026-30884 in Moodle mod_customcert plugin"
author = "Valters IT"
date = "2026-01-01"
reference = "CVE-2026-30884"
strings:
$ws_call = "mod_customcert_save_element" ascii wide nocase
$fragment_call = "editelement" ascii wide nocase
$elementid = "elementid" ascii wide nocase
condition:
($ws_call or $fragment_call) and $elementid
}
Sigma Rule
title: Moodle Custom Certificate Authorization Bypass
id: 7a8b9c0d-1e2f-3a4b-5c6d-7e8f9a0b1c2d
status: experimental
description: Detects attempts to exploit CVE-2026-30884 by accessing or modifying certificate elements across courses.
author: Valters IT
date: 2026-01-01
logsource:
category: webserver
product: moodle
detection:
selection:
cs-method: 'POST'
cs-uri-query|contains:
- 'core_get_fragment'
- 'mod_customcert_save_element'
cs-uri-query|contains: 'elementid'
condition: selection
falsepositives:
- Legitimate use by teachers with proper permissions
level: high
Suricata Rule
alert http any any -> any any (
msg:"Moodle Custom Certificate Authorization Bypass (CVE-2026-30884)";
flow:to_server,established;
content:"POST"; http_method;
content:"core_get_fragment"; http_uri;
content:"editelement"; http_uri;
content:"elementid"; http_client_body;
sid:1000001;
rev:1;
reference:cve,2026-30884;
classtype:attempted-admin;
priority:1;
)
Remediation & Mitigation
Immediate Actions:
- Update Plugin: Upgrade
moodle-mod_customcertto version 4.4.9 or 5.0.3 immediately. - Disable Plugin: If patching is not possible, disable the plugin in Moodle's plugin management.
- Audit Elements: Review all certificate elements for unauthorized changes, especially in courses where the teacher has
mod/customcert:managebut is not the course owner.
Long-Term Mitigations:
- Implement strict authorization checks in all custom plugins.
- Use Moodle's built-in capability checks (
require_capability) for all sensitive operations. - Regularly update all Moodle plugins to the latest versions.
- Monitor web service calls and AJAX requests for anomalous patterns.
Valters IT Signature
This report was generated by Valters IT, an elite DevSecOps and Cyber Threat Intelligence team. For further analysis or remediation support, contact us at [valters@example.com].