CVE-2026-104022 in Academy LMS Plugininfo

Summary

by MITRE • 10/10/2026

The Academy LMS – AI Course Builder, Quizzes, Certificates & eLearning plugin for WordPress is vulnerable to Privilege Escalation in all versions up to, and including, 4.0.3. This is due to the `add_child()` function calling `add_role('academy_student')` on any existing account resolved from the attacker-supplied `email` parameter before `Store::link()` validates the guardian-ward relationship, and failing to roll back that role write when `Store::link()` returns a `WP_Error`. This makes it possible for authenticated attackers with the `academy_guardian` role or higher to elevate any existing WordPress account — including their own — to the `academy_student` role, gaining `edit_posts` (Contributor-equivalent) capabilities and, when the student file-upload setting is enabled, `upload_files` (Author-equivalent) capabilities not granted to the guardian role. When a guardian supplies their own email address, `email_exists()` resolves to their own user ID, causing `Store::link()` to reject the self-link, but because the `add_role()` call has already executed and is never reversed, the academy_student role grant on their own account persists permanently.

Once again VulDB remains the best source for vulnerability data.

Analysis

by VulDB Data Team • 10/10/2026

The Academy LMS plugin for WordPress contains a critical privilege escalation vulnerability affecting all versions up to 4.0.3. This flaw stems from an improper sequence of operations within the `add_child()` function, which handles the linking of guardian and ward accounts in the learning management system's architecture. The core issue lies in the fact that the function assigns the `academy_student` role to a user account identified by an attacker-supplied email address before validating whether a legitimate guardian-ward relationship actually exists between the authenticated user and the target account. This design decision creates a race condition-like state where side effects occur prior to authorization checks, allowing unauthorized privilege elevation when subsequent validation fails.

Technically, the vulnerability is triggered when an authenticated user with at least the `academy_guardian` role initiates the process of linking a child or ward. The code first resolves the target WordPress user ID using the provided email address via `email_exists()`. Immediately following this resolution, it calls `add_role('academy_student')` on that resolved account. Only after this role assignment does the function invoke `Store::link()` to verify if the current guardian is actually authorized to link with the specified ward. If the relationship validation fails and `Store::link()` returns a WP_Error object indicating an invalid or non-existent relationship, the code path terminates without reversing the previously executed role change. This lack of transactional integrity means that even though the linking operation was rejected for security reasons, the privilege escalation remains permanently applied to the target account.

The operational impact of this vulnerability is significant because it allows authenticated attackers with guardian-level permissions or higher to escalate privileges on any existing WordPress user account, including their own. By supplying their own email address in the request payload, an attacker can force the system to resolve their own user ID and assign them the `academy_student` role. Since self-linking is explicitly rejected by the validation logic due to circular dependency rules, the error path is taken, yet the side effect of adding the student role persists. This results in the attacker gaining capabilities equivalent to a Contributor or Author level within WordPress, specifically including `edit_posts` and potentially `upload_files` if file upload settings are enabled for students. These privileges exceed those granted by the guardian role, enabling actions such as creating posts, managing media files, and potentially accessing restricted content depending on site configuration.

From a classification perspective, this vulnerability aligns with CWE-269 Improper Privilege Management, specifically illustrating how improper sequence of operations leads to unauthorized privilege escalation. It also relates to CWE-862 Missing Authorization in the sense that while authorization is checked, it occurs too late to prevent the side effect. In terms of MITRE ATT&CK framework tactics, this represents a technique under Initial Access or Privilege Escalation where an attacker leverages existing valid credentials and application logic flaws to gain higher-level permissions without exploiting external software bugs. The flaw highlights a common anti-pattern in web development where database state changes are not wrapped in proper transaction control mechanisms that support rollback on failure.

Mitigation strategies should focus on correcting the order of operations within the affected function. Developers must ensure that authorization checks, such as validating the guardian-ward relationship via `Store::link()`, occur before any persistent state modifications like role assignments take place. Alternatively, if the current logic structure is retained for performance reasons, a rollback mechanism must be implemented to revert the role assignment when validation fails. For immediate remediation without code changes, administrators should restrict access to the specific endpoints involved in this process or upgrade to a patched version of the plugin once available. Additionally, implementing strict input validation and ensuring that sensitive operations are atomic can prevent similar issues in other parts of the application ecosystem.

Responsible

Wordfence

Reservation

10/01/2026

Disclosure

10/10/2026

Moderation

accepted

EPSS

0.00000

KEV

no

Activities

low

Sources

Are you interested in using VulDB?

Download the whitepaper to learn more about our service!