1. Vulnerability Background
What is this vulnerability?
- CVE-2025-9318 is a time-based SQL injection vulnerability in the WordPress Quiz and Survey Master (QSM) plugin.
- The vulnerable code was in
php/rest-api.php, where the request parameteris_linkingwas used to build a SQLIN (...)clause without sufficient validation or escaping. - The plugin also exposed REST endpoints with
permission_callback => '__return_true', creating an authorization bypass for those routes.
Why is it critical/important?
- SQL injection allows attackers to manipulate database queries, which can lead to data exfiltration, authentication bypass, or even full site compromise.
- Time-based SQLi is particularly dangerous because it can be exploited in blind conditions, where the attacker cannot directly see query results but can infer them through response timing.
- Combined with insufficient REST API permissions, this vulnerability enlarges the attacker surface and can be exploited by low-privileged users.
What systems/versions are affected?
- QSM – Easy Quiz and Survey Maker plugin for WordPress
- All versions up to and including 10.3.1
- Any WordPress site running the vulnerable plugin with REST API access enabled is at risk
2. Technical Details
Root cause analysis
- The root cause is unsafe SQL query construction in
php/rest-api.php. is_linkingwas read directly from the request and later concatenated into a dynamic SQL clause:WHERE question_id IN (" . $comma_separated_ids . ")- The code also built a linked question list from user-controlled data without strict validation.
- Separately, endpoint registration used
'permission_callback' => '__return_true', which bypasses all authorization checks and allows unauthorized access.
Attack vector and exploitation conditions
- The attacker needs to reach a vulnerable QSM REST API endpoint that processes
is_linking. - The payload can be supplied through the
is_linkingparameter in a REST request. - Because the value is inserted directly into an
IN (...)list, a crafted value like1, IF(SUBSTRING(@@version,1,1)=5, SLEEP(5), 0)can induce a measurable delay. - Exploitation is feasible with subscriber-level or low-privileged access if the REST endpoint is accessible, and even more so when permission callbacks are incorrectly configured.
Security implications
- Unauthorized database access and data disclosure
- Blind SQL injection via timing attacks
- Possible extraction of sensitive site and database information
- Expanded attack surface due to broken REST API authorization
3. Patch Analysis
What code changes were made?
- Permission callbacks on multiple REST routes were changed:
from
'permission_callback' => '__return_true'to a closure that callscurrent_user_can('edit_qsm_quizzes') is_linkinginput now sanitized usingintval()- Existing linked question IDs are normalized by:
- splitting on commas
- trimming values
- filtering empty strings
- converting each value to integer via
array_map('intval')
- Linked IDs are deduplicated and filtered before query construction
- The SQL query now uses a sanitized list of integer IDs
How do these changes fix the vulnerability?
- The permission callback restricts endpoint access to users with the
edit_qsm_quizzescapability, closing the authorization bypass. intval()prevents arbitrary SQL fragments from being injected throughis_linking.- Normalizing the linked question list ensures only numeric IDs are incorporated into the query.
- Deducing and filtering the ID list prevents non-numeric input from reaching the SQL statement.
Security improvements introduced
- Enforced capability-based access control on REST endpoints
- Input validation and sanitization of query parameters
- Safer SQL query composition by limiting injected content to integer values
- Reduced attack surface by removing public exposure of sensitive endpoints
4. Proof of Concept (PoC) Guide
Prerequisites for exploitation
- WordPress site with QSM plugin version 10.3.1 or earlier installed
- Access to a vulnerable QSM REST API endpoint that accepts
is_linking - Ability to send authenticated REST requests (subscriber-level or accessible endpoint)
Step-by-step exploitation approach
- Identify the QSM REST endpoint implementing
is_linkinghandling. - Send a crafted request with the
is_linkingparameter containing an injected SQL expression, for example:is_linking=1, IF(SUBSTRING(@@version,1,1)='5', SLEEP(5), 0) - Observe response timing:
- normal input should return quickly
- injected input should delay the response by the sleep interval if SQL injection succeeds
- Use a time-based payload to infer database contents such as version, table names, or other sensitive values.
Expected behavior vs exploited behavior
- Expected behavior:
is_linkingis treated as an integer ID- query returns the expected linked quiz question records
- Exploited behavior:
is_linkinginjects SQL syntax into the query- query executes attacker-controlled expressions
- response timing or results leak database information
How to verify the vulnerability exists
- Confirm QSM version is 10.3.1 or older
- Locate the REST endpoint in
php/rest-api.php - Send a test payload with an injected sleep expression
- If the endpoint response is delayed consistently, the vulnerability is present
- Alternatively, monitor database logs for malformed
IN (...)queries containing injected payload content
5. Recommendations
Mitigation strategies
- Update QSM to a patched version above 10.3.1
- If patching is not immediately possible, disable the plugin or restrict REST access to trusted users only
- Apply input validation and sanitization for all user-controlled REST parameters
Detection methods
- Inspect REST API endpoint registration for
permission_callback => '__return_true' - Monitor access to QSM REST routes in web logs
- Detect unusual
is_linkingparameter values or repeated timing-based requests - Use database query logging to find unexpected
IN (...)payloads
Best practices to prevent similar issues
- Never use
__return_truefor REST API permission callbacks - Always enforce capability checks with
current_user_can()for plugin endpoints - Sanitize all request inputs before using them in SQL queries
- Prefer parameterized queries and prepared statements over direct string concatenation
- Normalize and validate list input values before building query clauses
- Apply least privilege to REST endpoints and limit access to necessary roles only