SECURITY ADVISORY / 01

CVE-2024-4434 Exploit & Vulnerability Analysis

Complete CVE-2024-4434 security advisory with proof of concept (PoC), exploit details, and patch analysis for learnpress.

learnpress products NVD ↗
Exploit PoC Vulnerability Patch Analysis

The Exploit

An unauthenticated attacker can inject arbitrary SQL into LearnPress course queries via the term_id parameter in the course filter API by passing a non-integer value that bypasses esc_sql() validation.

GET /wp-json/learnpress/v1/courses?filter={"term_ids":["1' AND SLEEP(5)-- -"]} HTTP/1.1
Host: target-site.com
User-Agent: curl/7.68.0
Accept: */*

The server will hang for 5+ seconds as the injected SLEEP(5) query executes within the SQL IN() clause. An attacker observes the delay in response time, confirming code execution. By replacing SLEEP(5) with UNION-based or time-blind exfiltration queries, the attacker extracts user credentials, course enrollment data, and other sensitive database records without authentication.

What the Patch Did

Before:

$term_ids_format = esc_sql( join( ',', $filter->term_ids ) );
$filter->where[] = $this->wpdb->prepare( 'AND tx.term_id IN (' . $term_ids_format . ')' );

After:

$filter->term_ids = array_map( 'absint', $filter->term_ids );
$term_ids_format = join( ',', $filter->term_ids );
$filter->where[] = "AND tx.term_id IN ($term_ids_format)";

The patch added input validation using array_map( 'absint', ... ) to convert all array elements to absolute integers before concatenating them into SQL. The absint() WordPress function strips all non-numeric characters and ensures type safety at the application layer, guaranteeing that only integers can ever reach the SQL string. The removal of esc_sql() and wpdb::prepare() follows because these escaping methods are ineffective against pre-concatenated arrays — the real defence is type coercion, not string escaping.

Root Cause

CWE-89: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection').

The vulnerability exists in class-lp-course-db.php lines 507–516 and 522–530. User-supplied course filter parameters arrive from the REST API endpoint /wp-json/learnpress/v1/courses with query parameters like filter={"term_ids":["1","2"]}. These values are deserialized into PHP arrays and passed directly to $filter->term_ids. The code then joins the array into a comma-separated string using join() and wraps the result in esc_sql(), intending to escape SQL syntax. However, esc_sql() operates on the final string (e.g., "1,2' OR '1'='1"), escaping quotes at the character level rather than validating the array structure. An attacker inserts SQL metacharacters into individual array elements (e.g., ["1' AND SLEEP(5)-- -"]), which survive esc_sql() because commas inside quoted strings are not escaped. The concatenated SQL statement reaches wpdb::prepare() with the injection payload already embedded, and prepare() cannot undo the concatenation. The query executes with attacker SQL injected into the IN() clause syntax.

Why It Works

The load-bearing line is $filter->term_ids = array_map( 'absint', $filter->term_ids );.

Without this line, an attacker's payload string (e.g., "1' AND SLEEP(5)-- -") passes through unchanged, reaches the SQL concatenation, and injects commands. The absint() function converts "1' AND SLEEP(5)-- -" to the integer 1 by stripping all non-numeric characters — a guaranteed type conversion, not a filter that can be bypassed by encoding or escaping tricks.

The subsequent removal of esc_sql() and wpdb::prepare() is a consequence, not the core defence. Once all values are integers via absint(), string escaping becomes redundant; in fact, retaining it would suggest a false confidence in escaping that does not apply to arrays. The patch engineers correctly recognized that escaping is the wrong tool for array input validation and replaced it with type coercion — the only method that guarantees injection is impossible when the sink expects only numeric literals.

Hardening Checklist

  • Validate array elements at the point of deserialization, not after concatenation. Use array_map( 'absint', ... ), array_filter( ... , FILTER_VALIDATE_INT ), or equivalent type coercion before any string operations.
  • Never concatenate user input into SQL strings, even after escaping. Always use wpdb::prepare() with placeholders (%d, %s) before concatenation, and ensure all user values are passed as the prepare() arguments, not baked into the query string.
  • Audit all uses of esc_sql() on arrays or loop-joined values. esc_sql() is intended for single scalar strings; it provides no protection when applied post-concatenation to delimited lists. Replace with type validation at the array level.
  • Use absint() or intval() for numeric REST API parameters before any SQL context. Many WordPress REST endpoints default to string parameters; explicitly cast course IDs, term IDs, and user IDs to integers immediately after deserialization.
  • Enable SQL query logging in development and test injected payloads (e.g., term_ids[]=1' OR '1'='1) to verify they do not alter the query structure. Review the actual SQL in wp-config.php debug logs before merging.

References

  • https://nvd.nist.gov/vuln/detail/CVE-2024-4434
  • LearnPress plugin repository and changelog on WordPress.org

Frequently asked questions about CVE-2024-4434

What is CVE-2024-4434?

CVE-2024-4434 is a security vulnerability identified in learnpress. This security advisory provides detailed technical analysis of the vulnerability, exploit methodology, affected versions, and complete remediation guidance.

Is there a PoC (proof of concept) for CVE-2024-4434?

Yes. This writeup includes proof-of-concept details and a technical exploit breakdown for CVE-2024-4434. Review the analysis sections above for the PoC walkthrough and code examples.

How does CVE-2024-4434 get exploited?

The technical analysis section explains the vulnerability mechanics, attack vectors, and exploitation methodology affecting learnpress. PatchLeaks publishes this information for defensive and educational purposes.

What products and versions are affected by CVE-2024-4434?

CVE-2024-4434 affects learnpress. Check the affected-versions section of this advisory for specific version ranges, vulnerable configurations, and compatibility information.

How do I fix or patch CVE-2024-4434?

The patch analysis section provides guidance on updating to patched versions, applying workarounds, and implementing compensating controls for learnpress.

What is the CVSS score for CVE-2024-4434?

The severity rating and CVSS scoring for CVE-2024-4434 affecting learnpress is documented in the vulnerability details section. Refer to the NVD entry for the current authoritative score.