Automated Threat Modeling

LearnPress CVE-2026-4365: Brief Summary of Unauthenticated Quiz Answer Deletion via Missing Authorization

A brief summary of CVE-2026-4365, a critical missing-authorization flaw in the LearnPress WordPress plugin. Unauthenticated attackers can delete arbitrary quiz answers using a nonce the plugin exposes publicly. Includes patch analysis and mitigation guidance.

CVE Analysis

7 min read

ZeroPath CVE Analysis
ZeroPath CVE Analysis

2026-04-13

LearnPress CVE-2026-4365: Brief Summary of Unauthenticated Quiz Answer Deletion via Missing Authorization
Experimental AI-Generated Content

This CVE analysis is an experimental publication that is completely AI-generated. The content may contain errors or inaccuracies and is subject to change as more information becomes available. We are continuously refining our process.

If you have feedback, questions, or notice any errors, please reach out to us.

[email protected]

Introduction

A missing authorization check in the LearnPress WordPress plugin lets any unauthenticated visitor delete arbitrary quiz answer options. The flaw is tracked as CVE-2026-4365 with a CVSS score of 9.1, and it can silently corrupt course assessments across more than 100,000 active installations. The only token an attacker needs is a wp_rest nonce, and the plugin itself embeds that nonce in public HTML.

LearnPress, developed by ThimPress, is one of the most popular open-source Learning Management System (LMS) plugins for WordPress. It powers online course creation, quizzes, and student management for educational institutions, corporate training platforms, and independent instructors worldwide. At over 100,000 active installations, a LearnPress vulnerability has a broad blast radius across the WordPress ecosystem.

Technical Information

The vulnerability is classified under CWE-862 (Missing Authorization). It comes from an architectural oversight in which three separate components chain together into an unauthenticated path for deleting data.

The Nonce Exposure Problem

LearnPress embeds a wp_rest nonce directly into the lpData JavaScript object, which is rendered in the public frontend HTML of every page where the plugin is active. Any visitor can see this nonce, authenticated or not. The relevant code is in class-lp-assets.php at line 177.

In standard WordPress security practice, nonces are paired with capability checks so that a request gets both CSRF protection and authorization. A nonce alone does not prove a user is authorized to perform an action. It only proves the request came from a page that WordPress rendered. By exposing this nonce publicly, LearnPress effectively neutralizes its only security gate.

The AJAX Dispatcher

The lp-load-ajax dispatcher, implemented in AbstractAjax.php at line 33, accepts incoming AJAX requests and routes them to the appropriate handler. The dispatcher validates the wp_rest nonce but does no other authentication or capability check. Because the nonce is public, any visitor passes this validation trivially.

The Vulnerable Action

The delete_question_answer action, found in EditQuestionAjax.php at line 285, is what deletes quiz answer options. The function has no capability check and no ownership check. It accepts a question answer ID and deletes that answer directly.

Attack Flow

The exploitation path is straightforward:

  1. An attacker visits any public page on a WordPress site running LearnPress (versions up to and including 4.3.2.8).
  2. The attacker inspects the page source or JavaScript context to extract the wp_rest nonce from the lpData object.
  3. The attacker crafts a POST request to the lp-load-ajax endpoint, specifying the delete_question_answer action and including the extracted nonce along with the target answer ID.
  4. The AJAX dispatcher validates the nonce (which passes, since WordPress legitimately generated it) and routes the request to the handler.
  5. The delete_question_answer function runs the deletion without checking whether the requester has any WordPress capabilities or any relationship to the question.
  6. The targeted quiz answer option is permanently removed from the database.

The following table summarizes how the three components interact:

ComponentLocationFlawSecurity Implication
lpData objectclass-lp-assets.phpExposes wp_rest nonce in public HTMLProvides attackers the required token
lp-load-ajax dispatcherAbstractAjax.phpUses nonce as the sole security gateBypasses standard authentication
delete_question_answerEditQuestionAjax.phpNo capability or ownership checkAllows arbitrary answer deletion

The attacker needs only a browser and a simple HTTP client, yet deleting quiz answers can silently corrupt assessments, invalidate student results, and undermine the integrity of entire course catalogs. That asymmetry between effort and damage is what makes this vulnerability so serious.

Patch Information

The vulnerability was patched in LearnPress version 4.3.3, released to the WordPress plugin repository. The fix is a surgical, single-line addition inside the QuestionAnswerModel class at inc/Models/Question/QuestionAnswerModel.php.

In version 4.3.2.8 and earlier, the delete() method calls check_valid_before_delete() as its gatekeeper. That pre-delete validation checked only two things: whether the parent question existed, and whether the question type still had the minimum number of answers. It did no authorization check at all.

The model class already had a check_capabilities_update() method, and the save() method used it properly for create and update operations. That method calls WordPress's user_can() to verify that the current user holds the edit_lp_lesson capability for the specific question. The delete path never called it.

In version 4.3.3, the developers added a single call to $this->check_capabilities_update() inside check_valid_before_delete(), right after the question existence check and before the answer count validation:

public function check_valid_before_delete() { $questionPostModel = $this->get_question_post_model(); if ( ! $questionPostModel ) { throw new Exception( __( 'Question not found', 'learnpress' ) ); } + + $this->check_capabilities_update(); if ( $questionPostModel->get_type() === 'single_choice' || ...

The check_capabilities_update() method itself enforces the authorization:

public function check_capabilities_update() { $user = wp_get_current_user(); if ( ! user_can( $user, 'edit_' . LP_LESSON_CPT, $this->question_id ) ) { throw new Exception( __( 'You do not have permission to edit this item.', 'learnpress' ) ); } }

After the patch, an unauthenticated attacker can still send a crafted POST request to the delete_question_answer AJAX action with the publicly exposed wp_rest nonce, but the request now fails. The check_capabilities_update() call retrieves the current user, which will be an anonymous visitor with no capabilities. The user_can() check fails, and the method throws an exception that halts the deletion before it reaches the database.

The developers also bumped the method's PHPDoc version tag from @version 1.0.0 to @version 1.0.1, which confirms this was a targeted, intentional security fix. The patch is elegant because it reuses the check_capabilities_update() authorization method that already protected the save() flow. Leaving the delete path unguarded was an oversight.

Organizations running LearnPress should update to version 4.3.3 or later immediately. You can compare the vulnerable and patched model files directly in the WordPress plugin SVN repository.

Affected Systems and Versions

All versions of the LearnPress WordPress plugin up to and including 4.3.2.8 are affected. The vulnerability is present in any WordPress installation where LearnPress is active, regardless of WordPress core version or server configuration.

The fix is available in LearnPress version 4.3.3.

Vendor Security History

LearnPress has a documented pattern of security vulnerabilities, and organizations that rely on the plugin should pay attention to it:

  • An authenticated SQL injection via the order parameter, reachable by users with Contributor-level access, affected versions up to 4.2.6.9.3. It was patched in version 4.2.6.9.4.
  • CVE-2026-4333, a stored cross-site scripting (XSS) vulnerability, was recently identified in LearnPress. It points to the same recurring gaps in input validation and authorization.

This history of authorization bypasses, injection flaws, and XSS issues suggests that organizations deploying LearnPress should monitor it strictly, apply updates promptly, and consider additional hardening such as Web Application Firewalls with WordPress-specific rulesets.

References

Detect & fix
what others miss

Works with
  • GitHub
  • GitLab
  • Bitbucket
  • Azure DevOps Services
  • Gerrit
  • CVS
  • Jira
  • Linear
  • Slack
  • Security Compass
Explore integrations
Security magnifying glass visualization