CVE-2026-6817

Quiz Maker by AYS <= 6.7.1.29 - Unauthenticated Stored Cross-Site Scripting via 'rate_reason'

mediumImproper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
5.8
CVSS Score
5.8
CVSS Score
medium
Severity
6.7.1.30
Patched in
1d
Time to patch

Description

The Quiz Maker by AYS plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'rate_reason' parameter in all versions up to, and including, 6.7.1.29 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=6.7.1.29
PublishedMay 1, 2026
Last updatedMay 2, 2026
Affected pluginquiz-maker

What Changed in the Fix

Changes introduced in v6.7.1.30

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan - CVE-2026-6817 ## 1. Vulnerability Summary The **Quiz Maker by AYS** plugin (<= 6.7.1.29) contains an unauthenticated stored cross-site scripting (XSS) vulnerability. The plugin allows users (including unauthenticated guests) to submit ratings and feedback ("reasons") …

Show full research plan

Exploitation Research Plan - CVE-2026-6817

1. Vulnerability Summary

The Quiz Maker by AYS plugin (<= 6.7.1.29) contains an unauthenticated stored cross-site scripting (XSS) vulnerability. The plugin allows users (including unauthenticated guests) to submit ratings and feedback ("reasons") upon completing a quiz. The rate_reason parameter is stored in the database without sufficient sanitization and is later rendered in the WordPress administrative dashboard (the "Reviews" list) without proper escaping.

An attacker can inject arbitrary JavaScript, which will execute in the context of an administrator viewing the quiz reviews, potentially leading to session hijacking or the creation of unauthorized administrative accounts.

2. Attack Vector Analysis

  • Endpoint: wp-admin/admin-ajax.php
  • AJAX Action: ays_finish_quiz (Commonly used for quiz completion and rating submission in this plugin).
  • Vulnerable Parameter: rate_reason
  • Authentication: None required (Unauthenticated).
  • Preconditions: At least one quiz must be published and accessible via a shortcode.
  • Sink: The injected script is executed when an admin visits the "Reviews" page: wp-admin/admin.php?page=ays_quiz_all_reviews_quiz_maker.

3. Code Flow

  1. Submission (Public):
    • The Quiz_Maker_Public class (in public/class-quiz-maker-public.php) registers AJAX handlers for quiz completion.
    • The handler (likely ays_finish_quiz) retrieves $_POST['rate_reason'].
    • The data is stored in the {$wpdb->prefix}aysquiz_reviews table (or similar results table) via a database insert operation.
  2. Display (Admin):
    • An administrator navigates to the "Reviews" list.
    • The All_Reviews_List_Table class in includes/lists/class-quiz-maker-all-reviews-list-table.php is instantiated to display the records.
    • The rate_reason value is retrieved from the database.
    • The value is echoed into the table row, typically within a column_default or specific column_rate_reason method (not fully shown in snippet, but implied by the WP_List_Table implementation), without using esc_html() or wp_kses().

4. Nonce Acquisition Strategy

The plugin enqueues public scripts and localizes a nonce for AJAX operations.

  1. Identify Shortcode: The main shortcode is [ays_quiz id='QUIZ_ID'] (verified from README.txt).
  2. Creation: Use WP-CLI to create a test quiz and a page containing its shortcode.
  3. Extraction:
    • Navigate to the page.
    • The plugin localizes data into a JavaScript object. Based on the plugin's structure, the object is typically named ays_quiz_ajax.
    • JS Variable: window.ays_quiz_ajax
    • Nonce Key: nonce
    • Action String: The nonce is generated via wp_create_nonce('ays_quiz_ajax_nonce').

5. Exploitation Strategy

Step 1: Target Identification

Determine a valid Quiz ID. If no quiz exists, one must be created.

Step 2: Obtain Nonce

Access a page where the quiz is rendered and extract the ays_quiz_ajax.nonce value.

Step 3: Inject Payload

Send an unauthenticated POST request to admin-ajax.php.

Request Details:

  • URL: http://TARGET_URL/wp-admin/admin-ajax.php
  • Method: POST
  • Headers: Content-Type: application/x-www-form-urlencoded
  • Body Parameters:
    • action: ays_finish_quiz
    • quiz_id: [ID_OF_CREATED_QUIZ]
    • ays_quiz_questions_ids: [ID_OF_A_QUESTION] (often required for valid completion)
    • ays_quiz_nonce: [EXTRACTED_NONCE]
    • ays_quiz_rate: 5
    • rate_reason: <script>alert(document.domain);</script>

Step 4: Trigger Execution

Log in as an Administrator and navigate to the Reviews page.

6. Test Data Setup

  1. Create Quiz:
    # Create a simple quiz via WP-CLI (if possible) or use a known ID
    # Note: AYS Quiz Maker stores data in custom tables, so we use wp_eval to insert a dummy quiz
    wp eval "global \$wpdb; \$wpdb->insert(\"{\$wpdb->prefix}aysquiz_quizes\", array('title' => 'Exploit Test', 'status' => 'publish')); echo \$wpdb->insert_id;"
    
  2. Create Page:
    wp post create --post_type=page --post_title="Quiz Page" --post_status=publish --post_content="[ays_quiz id='1']"
    

7. Expected Results

  • The AJAX submission should return a JSON success message (e.g., {"status":true,...}).
  • When the admin visits wp-admin/admin.php?page=ays_quiz_all_reviews_quiz_maker, the browser will execute alert(document.domain).

8. Verification Steps

  1. Check Database:
    wp db query "SELECT rate_reason FROM wp_aysquiz_reviews ORDER BY id DESC LIMIT 1;"
    
    Confirm the rate_reason contains the raw <script> tag.
  2. Check Admin UI (Manual/Automated):
    Use browser_navigate as an admin to the reviews page and check for the presence of the alert or the unescaped string in the HTML source.

9. Alternative Approaches

If ays_finish_quiz is too complex or requires valid answers, attempt a direct rating action if available:

  • Action: ays_quiz_rate
  • Payload: Send rate_reason and quiz_id to this action.
  • JS Check: Inspect public/js/quiz-maker-public.js (if accessible) to see exactly how the "Rating" submit button sends data to admin-ajax.php. Look for jQuery.ajax calls involving rate_reason.

Check if your site is affected.

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