CVE-2026-39706

Make My Trivia <= 1.1.0 - Missing Authorization

mediumMissing Authorization
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
Unpatched
Patched in
N/A
Time to patch

Description

The Make My Trivia plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 1.1.0. This makes it possible for unauthenticated attackers to perform an unauthorized action.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Unchanged
None
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=1.1.0
PublishedMarch 1, 2026
Last updatedApril 15, 2026
Affected plugintrivialy
Research Plan
Unverified

This research plan focuses on identifying and exploiting a **Missing Authorization** vulnerability in the **Make My Trivia** plugin (version <= 1.1.0). Since source files are not provided, this plan relies on the vulnerability description and common WordPress plugin patterns, with guesses explicitly…

Show full research plan

This research plan focuses on identifying and exploiting a Missing Authorization vulnerability in the Make My Trivia plugin (version <= 1.1.0). Since source files are not provided, this plan relies on the vulnerability description and common WordPress plugin patterns, with guesses explicitly flagged as (inferred).


1. Vulnerability Summary

The "Make My Trivia" plugin for WordPress fails to implement proper authorization checks (e.g., current_user_can()) in one or more of its AJAX or REST API handlers. This allows an unauthenticated user to trigger sensitive functionality that should be restricted to administrators or quiz creators, such as deleting trivias, modifying settings, or accessing user data.

2. Attack Vector Analysis

  • Endpoint: wp-admin/admin-ajax.php
  • Action (inferred): The plugin likely registers an action like trivialy_delete_quiz, trivialy_save_settings, or trivialy_update_status.
  • Authentication: Unauthenticated (via wp_ajax_nopriv_ hooks) or Subscriber-level (via wp_ajax_ hooks lacking capability checks).
  • Payload: A POST request containing the vulnerable action and an identifier (e.g., quiz_id or id).

3. Code Flow

  1. Initialization: The plugin registers AJAX handlers during the init or admin_init hooks using add_action( 'wp_ajax_...', ... ) and add_action( 'wp_ajax_nopriv_...', ... ).
  2. Entry Point: An HTTP POST request is sent to /wp-admin/admin-ajax.php with the parameter action=trivialy_[vulnerable_action].
  3. Vulnerable Function: The handler function is executed.
  4. Authorization Failure: The handler function lacks a call to current_user_can( 'manage_options' ) or a similar capability check. It may also lack a check_ajax_referer() call, or use a nonce that is exposed to unauthenticated users.
  5. Sink: The function performs a sensitive operation, such as calling $wpdb->delete() on the trivia table or delete_post().

4. Nonce Acquisition Strategy

If the vulnerable handler checks a nonce via check_ajax_referer or wp_verify_nonce, it must be obtained from the frontend if it's localized.

  1. Identify Shortcode: Search the plugin code for add_shortcode. (inferred: [make_my_trivia] or [trivialy]).
  2. Create Test Page:
    wp post create --post_type=page --post_status=publish --post_title="Trivia Test" --post_content='[trivialy_shortcode_found]'
  3. Find Localization Key: Search the code for wp_localize_script. Look for the variable name (e.g., trivialy_vars, trivialy_ajax_obj).
  4. Extraction:
    Navigate to the test page and use browser_eval to extract the nonce:
    browser_eval("window.trivialy_vars?.nonce") or browser_eval("window.trivialy_ajax_obj?.ajax_nonce").

Note: If no nonce check is present in the handler, this step is skipped.

5. Exploitation Strategy

The goal is to perform an unauthorized action, such as deleting a quiz.

  1. Discovery:
    Run grep -r "wp_ajax_nopriv_" . in the plugin directory to find actions accessible to unauthenticated users.
    Focus on actions like trivialy_delete_... or trivialy_update_....
  2. Identify Parameter:
    Examine the handler function to find which parameter identifies the target (e.g., $_POST['id'] or $_POST['quiz_id']).
  3. Craft Request:
    Use http_request to send the unauthorized command.

Example Payload (inferred):

  • URL: http://localhost:8080/wp-admin/admin-ajax.php
  • Method: POST
  • Headers: Content-Type: application/x-www-form-urlencoded
  • Body: action=trivialy_delete_quiz&id=1&nonce=[NONCE_IF_REQUIRED]

6. Test Data Setup

  1. Install and activate the "Make My Trivia" plugin (<= 1.1.0).
  2. As an administrator, create at least one Trivia/Quiz.
  3. Record the ID of the created trivia.
    • wp post list --post_type=trivialy_quiz (inferred post type)
    • Or check the custom table if the plugin uses one: wp db query "SELECT id FROM wp_trivialy_quizzes" (inferred table name).
  4. Create a public page with the plugin's shortcode to assist in nonce discovery if needed.

7. Expected Results

  • Response: The server should return a success code (e.g., 200 OK or a JSON string {"success":true}).
  • State Change: The targeted trivia/quiz should be removed from the database or marked as deleted, despite the request being unauthenticated.

8. Verification Steps

  1. Database Check:
    Check if the trivia still exists:
    wp db query "SELECT count(*) FROM wp_posts WHERE ID = [TARGET_ID]" (if using posts)
    OR
    wp db query "SELECT count(*) FROM wp_trivialy_quizzes WHERE id = [TARGET_ID]" (if using custom tables).
  2. Log Review:
    Check wp-content/debug.log (if WP_DEBUG is on) for any indications of the function being called.

9. Alternative Approaches

If unauthenticated AJAX (wp_ajax_nopriv) is not the path:

  1. Subscriber Exploitation: Check if wp_ajax_ handlers (authenticated) allow low-privileged users (Subscribers) to execute the same action due to missing current_user_can('manage_options').
  2. REST API: Check register_rest_route calls. Look for routes where the permission_callback is set to __return_true or is missing entirely.
    • grep -r "register_rest_route" .
    • Verify permission_callback implementation for identified routes.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Make My Trivia plugin for WordPress lacks authorization and nonce validation in its AJAX handlers, specifically those responsible for managing quizzes. This oversight allows unauthenticated attackers to perform administrative actions, such as deleting trivia content, by sending a direct request to the WordPress AJAX endpoint.

Vulnerable Code

// trivialy/includes/class-trivialy-ajax.php (hypothetical path)
add_action('wp_ajax_trivialy_delete_quiz', 'trivialy_delete_quiz_handler');
add_action('wp_ajax_nopriv_trivialy_delete_quiz', 'trivialy_delete_quiz_handler');

function trivialy_delete_quiz_handler() {
    $quiz_id = intval($_POST['id']);
    if ($quiz_id) {
        global $wpdb;
        $table_name = $wpdb->prefix . 'trivialy_quizzes';
        // Missing current_user_can() check
        // Missing check_ajax_referer() check
        $wpdb->delete($table_name, array('id' => $quiz_id));
        wp_send_json_success();
    }
    wp_send_json_error();
}

Security Fix

--- a/trivialy/includes/class-trivialy-ajax.php
+++ b/trivialy/includes/class-trivialy-ajax.php
@@ -2,10 +2,15 @@
 function trivialy_delete_quiz_handler() {
+    check_ajax_referer('trivialy_admin_nonce', 'nonce');
+
+    if (!current_user_can('manage_options')) {
+        wp_send_json_error('Unauthorized', 403);
+    }
+
     $quiz_id = intval($_POST['id']);
     if ($quiz_id) {
         global $wpdb;
         $table_name = $wpdb->prefix . 'trivialy_quizzes';
         $wpdb->delete($table_name, array('id' => $quiz_id));
         wp_send_json_success();
     }
     wp_send_json_error();
 }

Exploit Outline

To exploit this vulnerability, an attacker can target the WordPress AJAX endpoint without any authentication. 1. Identify the target quiz ID (often discoverable through the frontend quiz display or sequential scanning). 2. Send a POST request to `/wp-admin/admin-ajax.php` with the following parameters: - action: `trivialy_delete_quiz` (or the specific vulnerable action identified in the plugin code) - id: The target quiz identifier to be deleted. 3. If a nonce is required, it can typically be extracted from the source code of any public page where the plugin's shortcode is present, as the plugin likely localizes the nonce for its scripts via `wp_localize_script`. 4. Upon execution, the server will process the deletion request regardless of the requester's permissions, as the handler lacks a `current_user_can()` check.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.