PHP Object Injection Patched in Quiz and Survey Master Plugin Affecting 40k+ Sites

Published 9 October 2025
Table of Contents

This blog post is about an unauthenticated PHP object injection vulnerability in the Quiz and Survey Master plugin. If you're a Quiz and Survey Master plugin user, please update the plugin to version 10.2.6.

The vulnerabilities mentioned here were discovered and reported by Patchstack Alliance community member Phat RiO - BlueRock.

✌️ Our users are protected from this vulnerability. Are yours?

Web developers

Mitigate vulnerabilities in real-time without changing code.

See pricing
Plugin developers

Identify vulnerabilities in your plugins and get recommendations for fixes.

Request audit
Hosting companies

Protect your users, improve server health and earn additional revenue.

Patchstack for hosts

About Quiz and Survey Master plugin

The plugin Quiz and Survey Master, which has over 40,000 active installations, allows site owners to create quizzes, surveys, and forms in just a few clicks. It allows everything from fun trivia quizzes to in-depth customer satisfaction assessments, using a user-friendly drag-and-drop quiz maker interface.

PHP Object Injection

In versions 10.2.5 and below, the plugin is vulnerable to a PHP object injection, which allows any unauthenticated attacker to inject arbitrary PHP objects for deserialization. The vulnerability has been patched in version 10.2.6 and is tracked with CVE-2025-49401.

The root cause of the issue lies in the qsm_questions_answers_shortcode_to_text function:

function qsm_questions_answers_shortcode_to_text( $mlw_quiz_array, $qmn_question_answer_template, $questions, $qmn_questions, $answer, $qsm_question_cnt, $total_question_cnt ) {
	global $mlwQuizMasterNext, $qmn_total_questions;
	$question_types = $mlwQuizMasterNext->pluginHelper->get_question_type_options();
	$quiz_options  = $mlwQuizMasterNext->quiz_settings->get_quiz_options();
	// TRIMMED

			if ( ! empty( $_POST['quiz_answer_random_ids'] ) ) {
				$answers_random = array();
				$quiz_answer_random_ids = sanitize_text_field( wp_unslash( $_POST['quiz_answer_random_ids'] ) );
				$quiz_answer_random_ids = qmn_sanitize_random_ids_data( $quiz_answer_random_ids );
				if ( ! empty( $quiz_answer_random_ids[ $answer['id'] ] ) && is_array( $quiz_answer_random_ids[ $answer['id'] ] ) ) {
					foreach ( $quiz_answer_random_ids[ $answer['id'] ] as $key ) {
						$answers_random[ $key ] = $total_answers[ $key ];
					}
				}
				$total_answers = $answers_random;
			}
	// TRIMMED
	return wp_kses_post( $display );
}

The function takes the user input from $_POST['quiz_answer_random_ids'] as $quiz_answer_random_ids, and passes it to the qmn_sanitize_random_ids_data function.

function qmn_sanitize_random_ids_data( $qmn_sanitize_random_ids ) {
	if ( is_string( $qmn_sanitize_random_ids ) ) {
		if ( preg_match( '/^(O|C):\d+:/', $qmn_sanitize_random_ids ) ) {
			return '';
		}

		if ( is_serialized( $qmn_sanitize_random_ids ) ) {
			$unserialized = maybe_unserialize( $qmn_sanitize_random_ids );
			if ( ! is_object( $unserialized ) && ! is_resource( $unserialized ) ) {
				return $unserialized;
			}
		}
	}

	return $qmn_sanitize_random_ids;
}

The function basically checks if the passed input is serialized. If it's serialized, it unserializes the data with maybe_unserialize function and returns it.

The whole flow is called when processing the quiz answers, called by the hook wp_ajax_nopriv_qmn_process_quiz.

The patch

In version 10.2.6, the vendor patched the vulnerability by adding a new function qsm_safe_unserialize which properly unserializes the serialized data by using ['allowed_classes' => false] argument that prevents invoking arbitrary objects.

Conclusion

It is strongly suggested never to use the unserialize function unless absolutely necessary. Alternatives such as the json_decode function could be used to process the data. The best practice is always to use ['allowed_classes' => false] with unserialize if it is unavoidable to use.

Want to learn more about finding and fixing vulnerabilities?

Explore our Academy to master the art of finding and patching vulnerabilities within the WordPress ecosystem. Dive deep into detailed guides on various vulnerability types, from discovery tactics for researchers to robust fixes for developers. Join us and contribute to our growing knowledge base.

Timeline

31 July, 2025We received the vulnerability report and notified the vendor.
15 August, 2025The vendor publishes the patched version to the WP repository.
03 September, 2025We published the vulnerability entry to the database.
09 October, 2025Security advisory article publicly released.

🤝 You can help us make the Internet a safer place

Plugin developer?

Streamline your disclosure process to fix vulnerabilities faster and comply with CRA.

Get started for free
Hosting company?

Protect your users too! Improve server health and earn added revenue with proactive security.

Patchstack for hosts
Security researcher?

Report vulnerabilities to our gamified bug bounty program to earn monthly cash rewards.

Learn more

The latest in Security Advisories

Looks like your browser is blocking our support chat widget. Turn off adblockers and reload the page.
crossmenu