SECURITY ADVISORY / 01

CVE-2025-13192 Exploit & Vulnerability Analysis

Complete CVE-2025-13192 security advisory with proof of concept (PoC), exploit details, and patch analysis for popup-builder-block.

popup-builder-block products NVD ↗
Exploit PoC Vulnerability Patch Analysis

The Exploit

Unauthenticated attacker sends a REST API request to the Popup builder plugin with a malicious campaign_id parameter containing SQL syntax.

GET /wp-json/popupbuilder/v1/analytics/device-stats?start_date=2025-01-01&end_date=2025-01-31&campaign_id=1%20OR%201=1 HTTP/1.1
Host: vulnerable-site.local
Accept: application/json

The server concatenates the unsanitized campaign_id directly into the SQL query string before calling wpdb->prepare(), allowing the injected SQL condition to execute. The attacker observes a response containing aggregated device statistics that should have been filtered to a single campaign — instead, data from all campaigns leaks because 1=1 makes the WHERE clause always true. By chaining UNION SELECT statements, the attacker can extract user tables, password hashes, or any other database content.

What the Patch Did

Before:

$campaign = $campaign_id ? " AND campaign_id = $campaign_id" : '';

return $wpdb->get_results(
    $wpdb->prepare("SELECT SUM(device_desktop) as desktop, 
        SUM(device_tablet) as tablet, 
        SUM(device_mobile) as mobile 
        FROM %i WHERE date BETWEEN %s AND %s $campaign",
        $table_name,
        $start_date,
        $end_date,
    )
);

After:

if ( $campaign_id ) {
    return $wpdb->get_results(
        $wpdb->prepare(
            "SELECT SUM(device_desktop) as desktop, 
            SUM(device_tablet) as tablet, 
            SUM(device_mobile) as mobile 
            FROM %i WHERE date BETWEEN %s AND %s AND campaign_id = %d",
            $table_name,
            $start_date,
            $end_date,
            $campaign_id
        )
    );
} else {
    return $wpdb->get_results(
        $wpdb->prepare(
            "SELECT SUM(device_desktop) as desktop, 
            SUM(device_tablet) as tablet, 
            SUM(device_mobile) as mobile 
            FROM %i WHERE date BETWEEN %s AND %s",
            $table_name,
            $start_date,
            $end_date
        )
    );
}

The patch moved $campaign_id from string interpolation outside the wpdb->prepare() call into a parameterized placeholder %d inside the query template. The %d placeholder tells WordPress's database abstraction layer to treat $campaign_id as an integer literal, escaping any SQL metacharacters. By splitting conditional logic into separate prepared statements, the fix ensures no user-controlled value is ever concatenated into the SQL string before preparation.

Root Cause

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

The campaign_id parameter enters the REST API endpoint unauthenticated. The application assigns it to the $campaign variable by direct string interpolation (" AND campaign_id = $campaign_id"), then passes this pre-built string to wpdb->prepare(). The prepared statement implementation expects the query template to be static; when dynamic SQL fragments are spliced in before preparation, the placeholder substitution logic cannot distinguish attacker input from legitimate SQL syntax. The trust boundary violation occurs because the attacker-controlled integer value is treated as executable code rather than data.

Why It Works

The load-bearing security control is the %d placeholder in the prepared statement template: "... AND campaign_id = %d". If that placeholder were absent and the code returned to direct concatenation, the injection would remain exploitable. The engineer added the conditional split (if ( $campaign_id ) { ... } else { ... }) to avoid a logical anomaly — if $campaign_id is omitted, the query must not include the AND campaign_id = %d clause at all, otherwise a NULL or zero value would corrupt the query logic. The separate prepared statement blocks ensure the template is never malformed. The %d type hint is the actual defence: it forces wpdb->prepare() to cast and escape the value as an integer, making 1 OR 1=1 render as the literal string "1" in the final query, not as a logical condition.

Hardening Checklist

  • Use wpdb->prepare() with type placeholders (%d, %s, %i) for every user-supplied variable, even integers that look harmless. Never concatenate variables into the query string before calling prepare().
  • Audit all REST API endpoints for parameter sources using $_GET, $_POST, $_REQUEST, or sanitize_*() callbacks; map each to its sink in a database query and verify it passes through a type-checked placeholder.
  • Enable WordPress security logging and monitor for SQL errors in production logs — injected SQL often fails on first attempt, generating database errors that reveal the vulnerability before data exfiltration succeeds.
  • Run static analysis on custom SQL using plugins like WP Code Inspector or grep patterns for wpdb->query() / wpdb->get_results() calls; flag any line where a variable name appears in the query string outside a placeholder.
  • Enforce capability checks on admin-facing analytics endpoints using current_user_can( 'manage_options' ) even if unauthenticated SQL injection is patched, to add a second control layer for defense in depth.

References

  • https://nvd.nist.gov/vuln/detail/CVE-2025-13192

Frequently asked questions about CVE-2025-13192

What is CVE-2025-13192?

CVE-2025-13192 is a security vulnerability identified in popup-builder-block. 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-2025-13192?

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

How does CVE-2025-13192 get exploited?

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

What products and versions are affected by CVE-2025-13192?

CVE-2025-13192 affects popup-builder-block. Check the affected-versions section of this advisory for specific version ranges, vulnerable configurations, and compatibility information.

How do I fix or patch CVE-2025-13192?

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

What is the CVSS score for CVE-2025-13192?

The severity rating and CVSS scoring for CVE-2025-13192 affecting popup-builder-block is documented in the vulnerability details section. Refer to the NVD entry for the current authoritative score.