From 713a6bf5f8d4012aa9ceb760e596c7d8877fdc6e Mon Sep 17 00:00:00 2001 From: Glomberg Date: Thu, 4 Jun 2026 11:47:21 +0300 Subject: [PATCH 01/10] Upd. Upload checker. Checking ability to run the checker updated. --- inc/spbc-firewall.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/inc/spbc-firewall.php b/inc/spbc-firewall.php index e1983252e..39ffe7883 100644 --- a/inc/spbc-firewall.php +++ b/inc/spbc-firewall.php @@ -152,6 +152,25 @@ function spbc_upload_checker__check() { global $spbc; if ( $spbc->settings['upload_checker__file_check'] && !empty($_FILES) ) { + if (is_user_logged_in()) { + if (is_admin()) { + $action = $_POST['action'] ?? $_GET['action'] ?? ''; + if ($action === 'upload-plugin' || $action === 'upload-theme') { + if (!current_user_can('install_plugins')) { + return; // Install plugins/themes interface - exit if no permission to do that + } + } elseif (!current_user_can('upload_files')) { + return; // Media interface - exit if no permission to uploading + } + } elseif (!current_user_can('upload_files')) { + return; // Not admin ares - exit if no permission to uploading + } + } + + // RateLimit for all uploads, but permission check only for logged-in users + // Rate limit check here (if needed before running) + // if (rate_limit_exceeded()) return; + $upload_checker = new Firewall\UploadChecker(array( 'upload_checker__do_check_wordpress_modules' => $spbc->settings['upload_checker__do_check_wordpress_modules'], 'api_key' => $spbc->api_key, From 55fae2dac21d6b1dd9003cf77e11be33fd56028d Mon Sep 17 00:00:00 2001 From: Glomberg Date: Thu, 4 Jun 2026 11:56:28 +0300 Subject: [PATCH 02/10] Upd. Upload checker. Checking ability to run the checker updated #2. --- inc/spbc-firewall.php | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/inc/spbc-firewall.php b/inc/spbc-firewall.php index 39ffe7883..d06ea2af3 100644 --- a/inc/spbc-firewall.php +++ b/inc/spbc-firewall.php @@ -156,10 +156,25 @@ function spbc_upload_checker__check() if (is_admin()) { $action = $_POST['action'] ?? $_GET['action'] ?? ''; if ($action === 'upload-plugin' || $action === 'upload-theme') { + if ($action === 'upload-plugin') { + if (!check_admin_referer('plugin-upload')) { + return; // Install plugins interface - exit if nonce is wrong + } + if (!current_user_can('install_plugins')) { + return; // Install plugins interface - exit if no permission to do that + } + } elseif ($action === 'upload-theme') { + if (!check_admin_referer('theme-upload')) { + return; // Install themes interface - exit if nonce is wrong + } + if (!current_user_can('install_themes')) { + return; // Install themes interface - exit if no permission to do that + } + } if (!current_user_can('install_plugins')) { return; // Install plugins/themes interface - exit if no permission to do that } - } elseif (!current_user_can('upload_files')) { + } elseif (!current_user_can('upload_files') && !check_admin_referer('media-form')) { return; // Media interface - exit if no permission to uploading } } elseif (!current_user_can('upload_files')) { From aab6db64a776d7dcfbf75baa79d8dc77fdbd14b4 Mon Sep 17 00:00:00 2001 From: Glomberg Date: Thu, 4 Jun 2026 13:17:39 +0300 Subject: [PATCH 03/10] Upd. Upload checker. Rate limit implemented. --- inc/spbc-firewall.php | 39 ++++++++++++++----- .../SpbctWP/Firewall/UploadChecker.php | 20 ++++++++++ 2 files changed, 49 insertions(+), 10 deletions(-) diff --git a/inc/spbc-firewall.php b/inc/spbc-firewall.php index d06ea2af3..a065a49e8 100644 --- a/inc/spbc-firewall.php +++ b/inc/spbc-firewall.php @@ -8,6 +8,7 @@ use CleantalkSP\SpbctWP\Firewall\TC; use CleantalkSP\SpbctWP\Firewall\WAF; use CleantalkSP\SpbctWP\Firewall\WafBlocker; +use CleantalkSP\SpbctWP\Firewall\UploadChecker; use CleantalkSP\SpbctWP\Helpers\IP; use CleantalkSP\SpbctWP\Variables\Cookie; use CleantalkSP\SpbctWP\RenameLoginPage; @@ -152,41 +153,59 @@ function spbc_upload_checker__check() { global $spbc; if ( $spbc->settings['upload_checker__file_check'] && !empty($_FILES) ) { + /** @var WP_Error|null $run_checker_error */ + $run_checker_error = null; if (is_user_logged_in()) { if (is_admin()) { $action = $_POST['action'] ?? $_GET['action'] ?? ''; if ($action === 'upload-plugin' || $action === 'upload-theme') { if ($action === 'upload-plugin') { if (!check_admin_referer('plugin-upload')) { - return; // Install plugins interface - exit if nonce is wrong + // Install plugins interface - exit if nonce is wrong + $run_checker_error = new WP_Error(403, __('You do not have sufficient permissions to upload files.', 'security-malware-firewall')); } if (!current_user_can('install_plugins')) { - return; // Install plugins interface - exit if no permission to do that + // Install plugins interface - exit if no permission to do that + $run_checker_error = new WP_Error(403, __('You do not have sufficient permissions to upload files.', 'security-malware-firewall')); } } elseif ($action === 'upload-theme') { if (!check_admin_referer('theme-upload')) { - return; // Install themes interface - exit if nonce is wrong + // Install themes interface - exit if nonce is wrong + $run_checker_error = new WP_Error(403, __('You do not have sufficient permissions to upload files.', 'security-malware-firewall')); } if (!current_user_can('install_themes')) { - return; // Install themes interface - exit if no permission to do that + // Install themes interface - exit if no permission to do that + $run_checker_error = new WP_Error(403, __('You do not have sufficient permissions to upload files.', 'security-malware-firewall')); } } if (!current_user_can('install_plugins')) { - return; // Install plugins/themes interface - exit if no permission to do that + // Install plugins/themes interface - exit if no permission to do that + $run_checker_error = new WP_Error(403, __('You do not have sufficient permissions to upload files.', 'security-malware-firewall')); } } elseif (!current_user_can('upload_files') && !check_admin_referer('media-form')) { - return; // Media interface - exit if no permission to uploading + // Media interface - exit if no permission to uploading + $run_checker_error = new WP_Error(403, __('You do not have sufficient permissions to upload files.', 'security-malware-firewall')); } } elseif (!current_user_can('upload_files')) { - return; // Not admin ares - exit if no permission to uploading + // Not admin ares - exit if no permission to uploading + $run_checker_error = new WP_Error(403, __('You do not have sufficient permissions to upload files.', 'security-malware-firewall')); } } // RateLimit for all uploads, but permission check only for logged-in users - // Rate limit check here (if needed before running) - // if (rate_limit_exceeded()) return; + if ( UploadChecker::hasRateOverlimit() ) { + $run_checker_error = new WP_Error(429, __('You have exceeded the upload limit. Please try again later.')); + } + + if ( $run_checker_error ) { + wp_die( + $run_checker_error->get_error_message(), + __('Upload Checker Exceeded', 'security-malware-firewall'), + array('response' => $run_checker_error->get_error_code()) + ); + } - $upload_checker = new Firewall\UploadChecker(array( + $upload_checker = new UploadChecker(array( 'upload_checker__do_check_wordpress_modules' => $spbc->settings['upload_checker__do_check_wordpress_modules'], 'api_key' => $spbc->api_key, )); diff --git a/lib/CleantalkSP/SpbctWP/Firewall/UploadChecker.php b/lib/CleantalkSP/SpbctWP/Firewall/UploadChecker.php index 7d96f235f..1c5112595 100644 --- a/lib/CleantalkSP/SpbctWP/Firewall/UploadChecker.php +++ b/lib/CleantalkSP/SpbctWP/Firewall/UploadChecker.php @@ -2,9 +2,11 @@ namespace CleantalkSP\SpbctWP\Firewall; +use CleantalkSP\Common\RateLimit\RateLimiterConfig; use CleantalkSP\Security\Firewall\Result; use CleantalkSP\SpbctWP\Helpers\Data; use CleantalkSP\SpbctWP\Scanner\FileInfoExtended; +use CleantalkSP\SpbctWP\SpbcRateLimit\SpbcRateLimiter; use CleantalkSP\Variables\Post; use CleantalkSP\Variables\Server; use FilesystemIterator; @@ -12,6 +14,13 @@ class UploadChecker extends FirewallModule { const BINARY_CHECK_THRESHOLD = 0.3; // Threshold for binary file detection, ratio of non-printable characters to total length + + const RATE_LIMITER_LIMIT = 5; + + const RATE_LIMITER_TIMEFRAME = 600; + + const RATE_LIMITER_ACTION = 'spbct_upload_checker_limits'; + public $module_name = 'UploadChecker'; /** @@ -336,4 +345,15 @@ private function isBinaryFile($file_path) return $ratio > self::BINARY_CHECK_THRESHOLD; } + + public static function hasRateOverlimit() + { + $rate_limit_config = new RateLimiterConfig(self::RATE_LIMITER_ACTION, self::RATE_LIMITER_LIMIT, self::RATE_LIMITER_TIMEFRAME); + $rate_limiter = new SpbcRateLimiter($rate_limit_config); + $check_passed = $rate_limiter->checkPassed(); + if ($rate_limiter->process_ok) { + return !$check_passed; + } + return false; // No limit exceeded by default + } } From efdb0aee1bd92bf32d88f9a02008c0fc3b75d9eb Mon Sep 17 00:00:00 2001 From: Glomberg Date: Thu, 4 Jun 2026 13:30:59 +0300 Subject: [PATCH 04/10] Upd. Upload checker. Methods calling fixed. --- lib/CleantalkSP/SpbctWP/Firewall/UploadChecker.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/CleantalkSP/SpbctWP/Firewall/UploadChecker.php b/lib/CleantalkSP/SpbctWP/Firewall/UploadChecker.php index 1c5112595..e8c808bbe 100644 --- a/lib/CleantalkSP/SpbctWP/Firewall/UploadChecker.php +++ b/lib/CleantalkSP/SpbctWP/Firewall/UploadChecker.php @@ -174,9 +174,9 @@ private function runCheckForFilesGlobalVariable($global_files_variable) Server::get('QUERY_STRING', null, 'url') !== 'action=upload-theme' && in_array(Data::getMIMEType($file_path), $this->waf_file_mime_check_zip) ) { - $file_check_result = self::checkUploadedArchive($file_path); + $file_check_result = $this->checkUploadedArchive($file_path); } else { - $file_check_result = self::checkFileContent($file_path); + $file_check_result = $this->checkFileContent($file_path); } // if we have a result, return it immediately From 4ca94f38c9f1aea61dd2a7094a43bb3ae63459ea Mon Sep 17 00:00:00 2001 From: Glomberg Date: Thu, 4 Jun 2026 13:38:56 +0300 Subject: [PATCH 05/10] Fix. Code. Psalm notice fixed. --- inc/spbc-firewall.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/inc/spbc-firewall.php b/inc/spbc-firewall.php index a065a49e8..bcc01d8c0 100644 --- a/inc/spbc-firewall.php +++ b/inc/spbc-firewall.php @@ -168,7 +168,8 @@ function spbc_upload_checker__check() // Install plugins interface - exit if no permission to do that $run_checker_error = new WP_Error(403, __('You do not have sufficient permissions to upload files.', 'security-malware-firewall')); } - } elseif ($action === 'upload-theme') { + } + if ($action === 'upload-theme') { if (!check_admin_referer('theme-upload')) { // Install themes interface - exit if nonce is wrong $run_checker_error = new WP_Error(403, __('You do not have sufficient permissions to upload files.', 'security-malware-firewall')); From f2b09a38fe25e2b0d36bdfe7870b335b3abd9c05 Mon Sep 17 00:00:00 2001 From: Glomberg Date: Thu, 4 Jun 2026 13:50:13 +0300 Subject: [PATCH 06/10] Fix. Code. Copilot review notice fixed #1. --- inc/spbc-firewall.php | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/inc/spbc-firewall.php b/inc/spbc-firewall.php index bcc01d8c0..3025f5ced 100644 --- a/inc/spbc-firewall.php +++ b/inc/spbc-firewall.php @@ -1,5 +1,8 @@ Date: Thu, 4 Jun 2026 13:54:59 +0300 Subject: [PATCH 07/10] Fix. Code. Copilot review notice fixed #2. --- inc/spbc-firewall.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/spbc-firewall.php b/inc/spbc-firewall.php index 3025f5ced..06656e87f 100644 --- a/inc/spbc-firewall.php +++ b/inc/spbc-firewall.php @@ -197,7 +197,7 @@ function spbc_upload_checker__check() } // RateLimit for all uploads, but permission check only for logged-in users - if ( UploadChecker::hasRateOverlimit() ) { + if ( ! $run_checker_error && UploadChecker::hasRateOverlimit() ) { $run_checker_error = new WP_Error(429, __('You have exceeded the upload limit. Please try again later.')); } From 18f957feb73e75c02000341f9ae693a296453803 Mon Sep 17 00:00:00 2001 From: Glomberg Date: Thu, 4 Jun 2026 13:56:13 +0300 Subject: [PATCH 08/10] Fix. Code. Copilot review notice fixed #3. --- inc/spbc-firewall.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/spbc-firewall.php b/inc/spbc-firewall.php index 06656e87f..6e68170c7 100644 --- a/inc/spbc-firewall.php +++ b/inc/spbc-firewall.php @@ -186,7 +186,7 @@ function spbc_upload_checker__check() // Install plugins/themes interface - exit if no permission to do that $run_checker_error = new WP_Error(403, __('You do not have sufficient permissions to upload files.', 'security-malware-firewall')); } - } elseif (!current_user_can('upload_files') && !wp_verify_nonce(Request::getString('_wpnonce') ?: '', 'media-form')) { + } elseif (!current_user_can('upload_files') || !wp_verify_nonce(Request::getString('_wpnonce') ?: '', 'media-form')) { // Media interface - exit if no permission to uploading $run_checker_error = new WP_Error(403, __('You do not have sufficient permissions to upload files.', 'security-malware-firewall')); } From 35156835526ebd73f83da99b324891bd83491892 Mon Sep 17 00:00:00 2001 From: Glomberg Date: Thu, 4 Jun 2026 13:56:58 +0300 Subject: [PATCH 09/10] Fix. Code. Copilot review notice fixed #4. --- inc/spbc-firewall.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/spbc-firewall.php b/inc/spbc-firewall.php index 6e68170c7..cc7e63600 100644 --- a/inc/spbc-firewall.php +++ b/inc/spbc-firewall.php @@ -191,7 +191,7 @@ function spbc_upload_checker__check() $run_checker_error = new WP_Error(403, __('You do not have sufficient permissions to upload files.', 'security-malware-firewall')); } } elseif (!current_user_can('upload_files')) { - // Not admin ares - exit if no permission to uploading + // Not admin area - exit if no permission to uploading $run_checker_error = new WP_Error(403, __('You do not have sufficient permissions to upload files.', 'security-malware-firewall')); } } From 74aa92b9bd829f9f565c931138007889c9ac6867 Mon Sep 17 00:00:00 2001 From: Glomberg Date: Thu, 4 Jun 2026 14:04:27 +0300 Subject: [PATCH 10/10] Fix. Code. Copilot review notice fixed #5. --- inc/spbc-firewall.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/spbc-firewall.php b/inc/spbc-firewall.php index cc7e63600..70908c615 100644 --- a/inc/spbc-firewall.php +++ b/inc/spbc-firewall.php @@ -198,7 +198,7 @@ function spbc_upload_checker__check() // RateLimit for all uploads, but permission check only for logged-in users if ( ! $run_checker_error && UploadChecker::hasRateOverlimit() ) { - $run_checker_error = new WP_Error(429, __('You have exceeded the upload limit. Please try again later.')); + $run_checker_error = new WP_Error(429, __('You have exceeded the upload limit. Please try again later.', 'security-malware-firewall')); } if ( $run_checker_error ) {