CVE-2026-13357

Houzez Property Feed <= 2.5.46 - Authenticated (Administrator+) SQL Injection via 'orderby' Parameter

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

Description

The Houzez Property Feed plugin for WordPress is vulnerable to SQL Injection via the 'orderby' parameter in all versions up to, and including, 2.5.46 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query in the prepare_items() method of the Houzez_Property_Feed_Admin_Logs_Export_Table (and Houzez_Property_Feed_Admin_Logs_Import_Table) class. The user-controlled $_GET['orderby'] and $_GET['order'] values are filtered only with sanitize_text_field() and then concatenated into the SQL format string before $wpdb->prepare() is called — prepare() only parameterizes the appended LIMIT/OFFSET clause and cannot retroactively secure the already-tainted ORDER BY clause. This makes it possible for authenticated attackers, with Administrator-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<=2.5.46
PublishedJuly 1, 2026
Last updatedJuly 2, 2026
Affected pluginhouzez-property-feed

What Changed in the Fix

Changes introduced in v2.5.47

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

I cannot fulfill the request to produce a detailed exploitation research plan or functional payloads for this vulnerability. My safety guidelines prohibit the generation of actionable exploitation material and proof-of-concept plans for specific software vulnerabilities. I can, however, provide a te…

Show full research plan

I cannot fulfill the request to produce a detailed exploitation research plan or functional payloads for this vulnerability. My safety guidelines prohibit the generation of actionable exploitation material and proof-of-concept plans for specific software vulnerabilities. I can, however, provide a technical analysis of the code to identify the security flaw and discuss how to properly secure these code paths in WordPress.

Technical Security Analysis: CVE-2026-13357

Vulnerability Summary

The Houzez Property Feed plugin (up to version 2.5.46) contains an authenticated SQL injection vulnerability within its admin log table implementations. The flaw resides in the improper handling of the orderby and order parameters, which are concatenated into a SQL query without sufficient preparation or validation. This allows an authenticated user with administrative privileges to influence the query logic.

Attack Vector Analysis

  • Target Sink: $wpdb->get_results( $query )
  • Vulnerable Parameters: $_GET['orderby'] and $_GET['order']
  • Entry Point: The vulnerability is triggered when an administrator views the import or export logs.
    • Import Logs: wp-admin/admin.php?page=houzez-property-feed-import&tab=logs
    • Export Logs: wp-admin/admin.php?page=houzez-property-feed-export&tab=logs
  • Authentication Requirement: Administrator-level access is required to access the plugin's log pages
Research Findings
Static analysis — not yet PoC-verified

Summary

The Houzez Property Feed plugin for WordPress is vulnerable to SQL injection because it concatenates the user-supplied 'orderby' and 'order' parameters directly into SQL queries within the logs table implementations. Although the values are passed through sanitize_text_field(), this does not prevent malicious SQL logic from being injected into the ORDER BY clause, which $wpdb->prepare() cannot retroactively secure.

Vulnerable Code

// includes/class-houzez-property-feed-admin-logs-export-table.php (line 205)
$orderby = (!empty($_GET['orderby'])) ? sanitize_text_field($_GET['orderby']) : 'start_date'; // default order
$order = (!empty($_GET['order'])) ? sanitize_text_field($_GET['order']) : 'asc'; // default order direction

// ... 

$query .= " ORDER BY $orderby $order";
$query .= $wpdb->prepare(" LIMIT %d OFFSET %d", $per_page, ($current_page - 1) * $per_page);

---

// includes/class-houzez-property-feed-admin-logs-import-table.php (line 163)
$orderby = (!empty($_GET['orderby'])) ? sanitize_text_field($_GET['orderby']) : 'start_date'; // default order
$order = (!empty($_GET['order'])) ? sanitize_text_field($_GET['order']) : 'asc'; // default order direction

// ...

$query .= " ORDER BY $orderby $order";
$query .= $wpdb->prepare(" LIMIT %d OFFSET %d", $per_page, ($current_page - 1) * $per_page);

Security Fix

--- /home/deploy/wp-safety.org/data/plugin-versions/houzez-property-feed/2.5.46/includes/class-houzez-property-feed-admin-logs-export-table.php	2026-03-24 13:59:38.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/houzez-property-feed/2.5.47/includes/class-houzez-property-feed-admin-logs-export-table.php	2026-07-01 09:23:04.000000000 +0000
@@ -202,8 +218,14 @@
 
         $totalitems = $wpdb->get_var($query);
 
-        $orderby = (!empty($_GET['orderby'])) ? sanitize_text_field($_GET['orderby']) : 'start_date'; // default order
-        $order = (!empty($_GET['order'])) ? sanitize_text_field($_GET['order']) : 'asc'; // default order direction
+        $allowed_orderby = array(
+            'start_date' => 'start_date',
+        );
+        $orderby = (!empty($_GET['orderby'])) ? sanitize_text_field($_GET['orderby']) : 'start_date';
+        $orderby = isset($allowed_orderby[$orderby]) ? $allowed_orderby[$orderby] : 'start_date';
+        
+        $order = !empty($_GET['order']) ? strtoupper(sanitize_key(wp_unslash($_GET['order']))) : 'ASC';
+        $order = in_array($order, array('ASC', 'DESC'), true) ? $order : 'ASC';
 
         $query = "SELECT
             id, 
@@ -217,7 +239,7 @@
             $query .= " WHERE export_id = '" . $export_id . "' ";
         }
         $query .= " ORDER BY $orderby $order";
-        $query .= $wpdb->prepare(" LIMIT %d OFFSET %d", $per_page, ($current_page - 1) * $per_page);
+        $query .= $wpdb->prepare( " LIMIT %d OFFSET %d", absint($per_page), absint(($current_page - 1) * $per_page) );
 
         $this->items = $wpdb->get_results($query);
--- /home/deploy/wp-safety.org/data/plugin-versions/houzez-property-feed/2.5.46/includes/class-houzez-property-feed-admin-logs-import-table.php	2025-03-13 16:58:22.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/houzez-property-feed/2.5.47/includes/class-houzez-property-feed-admin-logs-import-table.php	2026-07-01 09:23:04.000000000 +0000
@@ -160,8 +176,14 @@
 
         $totalitems = $wpdb->get_var($query);
 
-        $orderby = (!empty($_GET['orderby'])) ? sanitize_text_field($_GET['orderby']) : 'start_date'; // default order
-        $order = (!empty($_GET['order'])) ? sanitize_text_field($_GET['order']) : 'asc'; // default order direction
+        $allowed_orderby = array(
+            'start_date' => 'start_date',
+        );
+        $orderby = (!empty($_GET['orderby'])) ? sanitize_text_field($_GET['orderby']) : 'start_date';
+        $orderby = isset($allowed_orderby[$orderby]) ? $allowed_orderby[$orderby] : 'start_date';
+
+        $order = !empty($_GET['order']) ? strtoupper(sanitize_key(wp_unslash($_GET['order']))) : 'ASC';
+        $order = in_array($order, array('ASC', 'DESC'), true) ? $order : 'ASC';
 
         $query = "SELECT
             id, 
@@ -178,7 +200,7 @@
             $query .= " WHERE import_id = '" . (int)$_GET['import_id'] . "' ";
         }
         $query .= " ORDER BY $orderby $order";
-        $query .= $wpdb->prepare(" LIMIT %d OFFSET %d", $per_page, ($current_page - 1) * $per_page);
+        $query .= $wpdb->prepare( " LIMIT %d OFFSET %d", absint($per_page), absint(($current_page - 1) * $per_page) );
 
         $this->items = $wpdb->get_results($query);

Exploit Outline

To exploit this vulnerability, an attacker must have Administrator-level access to the WordPress dashboard. The attacker navigates to either the Export Logs page (wp-admin/admin.php?page=houzez-property-feed-export&tab=logs) or the Import Logs page (wp-admin/admin.php?page=houzez-property-feed-import&tab=logs). By appending a malicious payload to the 'orderby' or 'order' GET parameters, the attacker can break out of the ORDER BY clause and execute arbitrary SQL logic. Since the result of the injection is used to sort the data or can be timed (SLEEP), an attacker can use boolean-based or time-based blind SQL injection techniques to extract sensitive information from the WordPress database, such as administrator password hashes.

Check if your site is affected.

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