CVE-2025-13092

Devs CRM – Manage tasks, attendance and teams all together <= 1.1.8 - Unauthenticated Information Expsoure

mediumMissing Authorization
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
Unpatched
Patched in
N/A
Time to patch

Description

The Devs CRM – Manage tasks, attendance and teams all together plugin for WordPress is vulnerable to unauthorized access of data due to a missing capability check on the /wp-json/devs-crm/v1/attendances REST API Endpoint in all versions up to, and including, 1.1.8. This makes it possible for unauthenticated attackers to retrieve private user data, including password hashes.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=1.1.8
PublishedDecember 12, 2025
Last updatedJune 23, 2026
Affected plugindevs-crm
Research Plan
Unverified

# Exploitation Research Plan: CVE-2025-13092 (Devs CRM Unauthenticated Info Exposure) ## 1. Vulnerability Summary The **Devs CRM** plugin for WordPress (versions <= 1.1.8) suffers from an unauthenticated information exposure vulnerability via its REST API. The endpoint `/wp-json/devs-crm/v1/attenda…

Show full research plan

Exploitation Research Plan: CVE-2025-13092 (Devs CRM Unauthenticated Info Exposure)

1. Vulnerability Summary

The Devs CRM plugin for WordPress (versions <= 1.1.8) suffers from an unauthenticated information exposure vulnerability via its REST API. The endpoint /wp-json/devs-crm/v1/attendances fails to implement a proper permission_callback in its register_rest_route definition. Consequently, any unauthenticated user can query this endpoint to retrieve attendance data, which incorrectly includes sensitive user object details, specifically including the user_pass (bcrypt/MD5 password hashes) from the wp_users table.

2. Attack Vector Analysis

  • Endpoint: /wp-json/devs-crm/v1/attendances
  • Method: GET
  • Authentication: None required (Unauthenticated).
  • Vulnerable Parameter: None (the entire endpoint is exposed).
  • Preconditions: The plugin must be active. Attendance records must exist for data to be returned (or the query must trigger a return of user objects associated with attendance).

3. Code Flow (Inferred)

  1. Registration: The plugin likely registers the route in a function hooked to rest_api_init.
    // Likely location: includes/class-rest-api.php or main plugin file
    register_rest_route( 'devs-crm/v1', '/attendances', array(
        'methods'             => 'GET',
        'callback'            => array( $this, 'get_attendances' ),
        'permission_callback' => '__return_true', // OR missing entirely
    ));
    
  2. Callback Execution: When the endpoint is hit, the get_attendances callback (inferred name) is executed.
  3. Data Retrieval: The callback queries attendance data. If this data is joined with the wp_users table (e.g., using get_users() or a raw $wpdb query), it fails to sanitize the output or explicitly exclude the user_pass field.
  4. Response: The REST API server serializes the PHP objects/arrays into JSON and returns them to the requester.

4. Nonce Acquisition Strategy

Based on the vulnerability description ("Unauthenticated Information Exposure"), this endpoint is designed to be public or was accidentally left public.

  • Is a Nonce Required? Generally, for unauthenticated GET requests to the WordPress REST API, a nonce (_wpnonce) is not required. Nonces are primarily used for cookie-based authentication for logged-in users to prevent CSRF.
  • If a nonce is unexpectedly required:
    1. The agent will search the plugin source for wp_localize_script.
    2. Common variable names for this plugin might be devs_crm_obj or devs_crm_vars.
    3. If scripts are only loaded on specific pages (e.g., a "Dashboard" page), the agent will create a page with a relevant shortcode like [devs_crm_attendance] (inferred).
    4. The agent would then use browser_eval("window.devs_crm_obj?.nonce").

5. Exploitation Strategy

Step 1: Discover the Namespace

Confirm the REST API namespace is accessible.

  • Request: GET /wp-json/devs-crm/v1
  • Tool: http_request

Step 2: Trigger Information Exposure

Send a GET request to the vulnerable attendances endpoint.

  • Request:
    GET /wp-json/devs-crm/v1/attendances HTTP/1.1
    Host: target.local
    Accept: application/json
    
  • Tool: http_request
  • Expected Payload: No parameters are expected to be necessary, though pagination parameters like ?per_page=100 might increase the data yield.

Step 3: Analyze Response

Inspect the JSON response for keys such as user_pass, user_login, user_email, or nested user objects containing $P$B... or $2y$... strings.

6. Test Data Setup

To ensure the vulnerability is detectable, we must have attendance data linked to users in the database.

  1. Create a Dummy User:
    wp user create employee employee@example.com --role=subscriber --user_pass=password123
  2. Generate Attendance Data:
    Attendance is likely stored in a custom table (e.g., wp_devs_crm_attendances). We may need to use the plugin's UI or WP-CLI to insert a record for the new user.
    Scripted setup:
    # Use WP-CLI to trigger whatever function registers attendance
    wp eval "global \$wpdb; \$wpdb->insert(\"{\$wpdb->prefix}devs_crm_attendances\", ['user_id' => 2, 'check_in' => current_time('mysql')]);"
    
    (Note: Table name is inferred, verify with wp db tables | grep devs_crm)

7. Expected Results

  • Success: The HTTP response code is 200 OK. The JSON body contains an array of objects. At least one object contains a field user_pass (or similar) containing a WordPress password hash (starts with $P$ or $2y$).
  • Failure: The response code is 401 Unauthorized or 403 Forbidden, or the response is 200 OK but sensitive fields like user_pass are absent.

8. Verification Steps

  1. Identify Hash from HTTP Response: Note the hash value returned in the JSON (e.g., $P$B...).
  2. Compare with Database: Use WP-CLI to verify this matches the actual hash for that user.
    wp db query "SELECT user_pass FROM wp_users WHERE ID = 2"
    
  3. Check for Other Data: Verify if other fields like user_activation_key or user_email are also exposed.

9. Alternative Approaches

If the /attendances endpoint returns empty:

  • Try /wp-json/devs-crm/v1/teams or /wp-json/devs-crm/v1/tasks (common CRM endpoints).
  • Check if the plugin uses a different namespace version like /v2/.
  • If the endpoint is blocked by a default WordPress restriction, try adding _method=GET or using POST with X-HTTP-Method-Override: GET.

Check if your site is affected.

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