{"id":"CVE-2026-104022","aliases":["EUVD-2026-96029","GHSA-vxgf-qvq7-h87v"],"status":"published","title":"Academy LMS \u003c= 4.0.3 - Authenticated (Custom+) Privilege Escalation to add_child REST endpoint","description":"The Academy LMS – AI Course Builder, Quizzes, Certificates \u0026 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.","severity":{"version":"3.1","score":5.4,"vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N","level":"medium","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-12","score":0.00125,"percentile":0.02216,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":false},"cwes":["CWE-269"],"published":"2026-10-10T02:26:31Z","modified":"2026-10-13T13:30:21Z","products":[{"vendor":"kodezen","product":"academy lms – ai course builder, quizzes, certificates \u0026 elearning"}],"references":[{"url":"https://www.wordfence.com/threat-intel/vulnerabilities/id/a54dd9e5-59e7-4655-9f64-e198deda1383?source=cve"},{"url":"https://plugins.trac.wordpress.org/browser/academy/tags/4.0.2/includes/guardian/rest-api.php#L160"},{"url":"https://plugins.trac.wordpress.org/browser/academy/tags/4.0.2/includes/guardian/rest-api.php#L138"},{"url":"https://plugins.trac.wordpress.org/browser/academy/tags/4.0.2/includes/guardian/rest-api.php#L85"},{"url":"https://plugins.trac.wordpress.org/browser/academy/tags/4.0.2/includes/guardian/store.php#L39"},{"url":"https://plugins.trac.wordpress.org/changeset?reponame=\u0026old=3734598%40academy\u0026new=3734598%40academy"},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-104022"},{"url":"https://github.com/advisories/GHSA-vxgf-qvq7-h87v"}],"sources":{"cve":[{"id":"CVE-2026-104022","title":"Academy LMS \u003c= 4.0.3 - Authenticated (Custom+) Privilege Escalation to add_child REST endpoint","description":"The Academy LMS – AI Course Builder, Quizzes, Certificates \u0026 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.","status":"published","published":"2026-10-10T02:26:31.622Z","modified":"2026-10-11T16:55:20.564Z","cvss":[{"version":"3.1","score":5.4,"vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N","level":"medium","assessor":"cna"}],"cwes":["CWE-269"],"updated_at":"2026-11-02T14:20:09.448255Z"}],"euvd":[{"id":"EUVD-2026-96029","description":"The Academy LMS – AI Course Builder, Quizzes, Certificates \u0026 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.","status":"published","published":"2026-10-10T02:26:31Z","modified":"2026-10-11T16:55:20Z","cvss":[{"version":"3.1","score":5.4,"vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N","level":"medium"}],"updated_at":"2026-11-02T17:27:22.074542Z"}],"ghsa":[{"id":"GHSA-vxgf-qvq7-h87v","title":"The Academy LMS – AI Course Builder, Quizzes, Certificates \u0026 eLearning plugin for WordPress is...","description":"The Academy LMS – AI Course Builder, Quizzes, Certificates \u0026 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.","status":"published","published":"2026-10-10T03:30:20Z","modified":"2026-10-10T03:30:27Z","cvss":[{"version":"3.1","score":5.4,"vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N","level":"medium"}],"cwes":["CWE-269"],"updated_at":"2026-11-02T15:13:01.290603Z"}],"nvd":[{"id":"CVE-2026-104022","description":"The Academy LMS – AI Course Builder, Quizzes, Certificates \u0026 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.","status":"published","published":"2026-10-10T03:17:03.953Z","modified":"2026-10-13T13:30:21.62Z","cvss":[{"version":"3.1","score":5.4,"vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N","level":"medium","assessor":"secondary"}],"cwes":["CWE-269"],"updated_at":"2026-11-02T14:12:55.473789Z"}]}}
