Changeset 3481753
- Timestamp:
- 03/13/2026 08:12:48 AM (3 weeks ago)
- Location:
- vulntitan
- Files:
-
- 8 edited
- 1 copied
-
tags/2.0.7 (copied) (copied from vulntitan/trunk)
-
tags/2.0.7/CHANGELOG.md (modified) (1 diff)
-
tags/2.0.7/includes/Services/LoginAccessService.php (modified) (7 diffs)
-
tags/2.0.7/readme.txt (modified) (2 diffs)
-
tags/2.0.7/vulntitan.php (modified) (2 diffs)
-
trunk/CHANGELOG.md (modified) (1 diff)
-
trunk/includes/Services/LoginAccessService.php (modified) (7 diffs)
-
trunk/readme.txt (modified) (2 diffs)
-
trunk/vulntitan.php (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
vulntitan/tags/2.0.7/CHANGELOG.md
r3481425 r3481753 5 5 The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), 6 6 and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 8 ## [2.0.7] - 2026-03-13 9 ### Fixed 10 - Fixed custom login logout requests on some Nginx-backed WordPress sites so `/?action=logout` flows no longer fail with upstream `502 Bad Gateway` responses. 11 - Stabilized hidden login bootstrapping by priming the `wp-login.php` request context earlier and normalizing canonical custom login route handling. 7 12 8 13 ## [2.0.6] - 2026-03-12 -
vulntitan/tags/2.0.7/includes/Services/LoginAccessService.php
r3481425 r3481753 14 14 protected static bool $booted = false; 15 15 protected static bool $customLoginRequest = false; 16 protected static bool $customLoginContextPrimed = false; 16 17 17 18 public static function boot(): void … … 22 23 23 24 self::$booted = true; 25 self::primeCustomLoginRequestContext(); 24 26 25 27 add_action('init', [__CLASS__, 'interceptRequests'], 0); … … 51 53 52 54 if (self::isCustomLoginPath($requestPath)) { 53 self:: $customLoginRequest = true;55 self::markCustomLoginRequest(); 54 56 return; 55 57 } … … 78 80 } 79 81 82 self::maybeRedirectCanonicalCustomLoginPath(); 83 self::primeCustomLoginContext(); 84 80 85 global $pagenow, $action, $error, $interim_login, $user_login; 81 86 … … 85 90 $interim_login = $interim_login ?? false; 86 91 $user_login = is_string($user_login ?? null) ? $user_login : ''; 87 88 $scriptPath = (string) wp_parse_url(site_url('wp-login.php', 'login'), PHP_URL_PATH);89 if ($scriptPath !== '') {90 $_SERVER['SCRIPT_NAME'] = $scriptPath;91 $_SERVER['PHP_SELF'] = $scriptPath;92 }93 92 94 93 require_once ABSPATH . 'wp-login.php'; … … 222 221 } 223 222 223 protected static function primeCustomLoginRequestContext(): void 224 { 225 if (!FirewallService::isCustomLoginEnabled()) { 226 return; 227 } 228 229 if ((defined('WP_CLI') && WP_CLI) || (defined('XMLRPC_REQUEST') && XMLRPC_REQUEST)) { 230 return; 231 } 232 233 $requestPath = self::getCurrentRequestPath(); 234 if ($requestPath === '' || !self::isCustomLoginPath($requestPath)) { 235 return; 236 } 237 238 self::markCustomLoginRequest(); 239 } 240 241 protected static function markCustomLoginRequest(): void 242 { 243 self::$customLoginRequest = true; 244 self::primeCustomLoginContext(); 245 } 246 247 protected static function primeCustomLoginContext(): void 248 { 249 if (self::$customLoginContextPrimed) { 250 return; 251 } 252 253 self::$customLoginContextPrimed = true; 254 255 global $pagenow; 256 257 $pagenow = 'wp-login.php'; 258 259 $scriptPath = self::getWpLoginScriptPath(); 260 if ($scriptPath !== '') { 261 $_SERVER['SCRIPT_NAME'] = $scriptPath; 262 $_SERVER['PHP_SELF'] = $scriptPath; 263 } 264 } 265 266 protected static function maybeRedirectCanonicalCustomLoginPath(): void 267 { 268 if (!get_option('permalink_structure')) { 269 return; 270 } 271 272 if (strtoupper((string) ($_SERVER['REQUEST_METHOD'] ?? 'GET')) !== 'GET') { 273 return; 274 } 275 276 $requestPath = self::getCurrentRequestPath(); 277 $canonicalPath = self::stripSiteBasePath((string) wp_parse_url(FirewallService::getCustomLoginUrl(), PHP_URL_PATH)); 278 if ($requestPath === '' || $canonicalPath === '') { 279 return; 280 } 281 282 if ($requestPath === $canonicalPath || untrailingslashit($requestPath) !== untrailingslashit($canonicalPath)) { 283 return; 284 } 285 286 $redirectUrl = FirewallService::getCustomLoginUrl(); 287 $queryString = (string) ($_SERVER['QUERY_STRING'] ?? ''); 288 if ($queryString !== '') { 289 $redirectUrl .= '?' . $queryString; 290 } 291 292 wp_safe_redirect($redirectUrl); 293 exit; 294 } 295 224 296 protected static function getRelativeLoginUrlPattern(): string 225 297 { … … 324 396 325 397 return '/' . ltrim($normalizedPath, '/'); 398 } 399 400 protected static function getWpLoginScriptPath(): string 401 { 402 $sitePath = (string) wp_parse_url(site_url('/'), PHP_URL_PATH); 403 $sitePath = '/' . trim($sitePath, '/'); 404 $sitePath = $sitePath === '//' ? '/' : $sitePath; 405 406 if ($sitePath === '/') { 407 return '/wp-login.php'; 408 } 409 410 return rtrim($sitePath, '/') . '/wp-login.php'; 326 411 } 327 412 -
vulntitan/tags/2.0.7/readme.txt
r3481430 r3481753 4 4 Tested up to: 6.9 5 5 Requires PHP: 7.4 6 Stable tag: 2.0. 66 Stable tag: 2.0.7 7 7 License: GPLv2 8 8 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 133 133 == Changelog == 134 134 135 = v2.0.7 - 13 Mar, 2026 = 136 * Fixed custom login logout requests on some Nginx-backed WordPress sites so hidden login logout no longer triggers `502 Bad Gateway` responses. 137 * Stabilized hidden login request bootstrapping and canonical custom login route handling for logout/login flows. 138 135 139 = v2.0.6 - 12 Mar, 2026 = 136 140 * Added configurable custom login slug support so administrators can use a private login URL instead of the default `wp-login.php` path. -
vulntitan/tags/2.0.7/vulntitan.php
r3481425 r3481753 4 4 * Plugin URI: https://vulntitan.com/vulntitan/ 5 5 * Description: VulnTitan is a lightweight WordPress security plugin with vulnerability scanning, malware detection, file integrity monitoring, and a built-in firewall with WAF payload rules and login protection. 6 * Version: 2.0. 66 * Version: 2.0.7 7 7 * Author: Jaroslav Svetlik 8 8 * Author URI: https://vulntitan.com … … 30 30 31 31 // Define plugin constants 32 define('VULNTITAN_PLUGIN_VERSION', VULNTITAN_DEVELOPMENT ? uniqid() : '2.0. 6');32 define('VULNTITAN_PLUGIN_VERSION', VULNTITAN_DEVELOPMENT ? uniqid() : '2.0.7'); 33 33 define('VULNTITAN_PLUGIN_BASENAME', plugin_basename(__FILE__)); 34 34 define('VULNTITAN_PLUGIN_DIR', untrailingslashit(plugin_dir_path(__FILE__))); -
vulntitan/trunk/CHANGELOG.md
r3481425 r3481753 5 5 The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), 6 6 and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 8 ## [2.0.7] - 2026-03-13 9 ### Fixed 10 - Fixed custom login logout requests on some Nginx-backed WordPress sites so `/?action=logout` flows no longer fail with upstream `502 Bad Gateway` responses. 11 - Stabilized hidden login bootstrapping by priming the `wp-login.php` request context earlier and normalizing canonical custom login route handling. 7 12 8 13 ## [2.0.6] - 2026-03-12 -
vulntitan/trunk/includes/Services/LoginAccessService.php
r3481425 r3481753 14 14 protected static bool $booted = false; 15 15 protected static bool $customLoginRequest = false; 16 protected static bool $customLoginContextPrimed = false; 16 17 17 18 public static function boot(): void … … 22 23 23 24 self::$booted = true; 25 self::primeCustomLoginRequestContext(); 24 26 25 27 add_action('init', [__CLASS__, 'interceptRequests'], 0); … … 51 53 52 54 if (self::isCustomLoginPath($requestPath)) { 53 self:: $customLoginRequest = true;55 self::markCustomLoginRequest(); 54 56 return; 55 57 } … … 78 80 } 79 81 82 self::maybeRedirectCanonicalCustomLoginPath(); 83 self::primeCustomLoginContext(); 84 80 85 global $pagenow, $action, $error, $interim_login, $user_login; 81 86 … … 85 90 $interim_login = $interim_login ?? false; 86 91 $user_login = is_string($user_login ?? null) ? $user_login : ''; 87 88 $scriptPath = (string) wp_parse_url(site_url('wp-login.php', 'login'), PHP_URL_PATH);89 if ($scriptPath !== '') {90 $_SERVER['SCRIPT_NAME'] = $scriptPath;91 $_SERVER['PHP_SELF'] = $scriptPath;92 }93 92 94 93 require_once ABSPATH . 'wp-login.php'; … … 222 221 } 223 222 223 protected static function primeCustomLoginRequestContext(): void 224 { 225 if (!FirewallService::isCustomLoginEnabled()) { 226 return; 227 } 228 229 if ((defined('WP_CLI') && WP_CLI) || (defined('XMLRPC_REQUEST') && XMLRPC_REQUEST)) { 230 return; 231 } 232 233 $requestPath = self::getCurrentRequestPath(); 234 if ($requestPath === '' || !self::isCustomLoginPath($requestPath)) { 235 return; 236 } 237 238 self::markCustomLoginRequest(); 239 } 240 241 protected static function markCustomLoginRequest(): void 242 { 243 self::$customLoginRequest = true; 244 self::primeCustomLoginContext(); 245 } 246 247 protected static function primeCustomLoginContext(): void 248 { 249 if (self::$customLoginContextPrimed) { 250 return; 251 } 252 253 self::$customLoginContextPrimed = true; 254 255 global $pagenow; 256 257 $pagenow = 'wp-login.php'; 258 259 $scriptPath = self::getWpLoginScriptPath(); 260 if ($scriptPath !== '') { 261 $_SERVER['SCRIPT_NAME'] = $scriptPath; 262 $_SERVER['PHP_SELF'] = $scriptPath; 263 } 264 } 265 266 protected static function maybeRedirectCanonicalCustomLoginPath(): void 267 { 268 if (!get_option('permalink_structure')) { 269 return; 270 } 271 272 if (strtoupper((string) ($_SERVER['REQUEST_METHOD'] ?? 'GET')) !== 'GET') { 273 return; 274 } 275 276 $requestPath = self::getCurrentRequestPath(); 277 $canonicalPath = self::stripSiteBasePath((string) wp_parse_url(FirewallService::getCustomLoginUrl(), PHP_URL_PATH)); 278 if ($requestPath === '' || $canonicalPath === '') { 279 return; 280 } 281 282 if ($requestPath === $canonicalPath || untrailingslashit($requestPath) !== untrailingslashit($canonicalPath)) { 283 return; 284 } 285 286 $redirectUrl = FirewallService::getCustomLoginUrl(); 287 $queryString = (string) ($_SERVER['QUERY_STRING'] ?? ''); 288 if ($queryString !== '') { 289 $redirectUrl .= '?' . $queryString; 290 } 291 292 wp_safe_redirect($redirectUrl); 293 exit; 294 } 295 224 296 protected static function getRelativeLoginUrlPattern(): string 225 297 { … … 324 396 325 397 return '/' . ltrim($normalizedPath, '/'); 398 } 399 400 protected static function getWpLoginScriptPath(): string 401 { 402 $sitePath = (string) wp_parse_url(site_url('/'), PHP_URL_PATH); 403 $sitePath = '/' . trim($sitePath, '/'); 404 $sitePath = $sitePath === '//' ? '/' : $sitePath; 405 406 if ($sitePath === '/') { 407 return '/wp-login.php'; 408 } 409 410 return rtrim($sitePath, '/') . '/wp-login.php'; 326 411 } 327 412 -
vulntitan/trunk/readme.txt
r3481430 r3481753 4 4 Tested up to: 6.9 5 5 Requires PHP: 7.4 6 Stable tag: 2.0. 66 Stable tag: 2.0.7 7 7 License: GPLv2 8 8 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 133 133 == Changelog == 134 134 135 = v2.0.7 - 13 Mar, 2026 = 136 * Fixed custom login logout requests on some Nginx-backed WordPress sites so hidden login logout no longer triggers `502 Bad Gateway` responses. 137 * Stabilized hidden login request bootstrapping and canonical custom login route handling for logout/login flows. 138 135 139 = v2.0.6 - 12 Mar, 2026 = 136 140 * Added configurable custom login slug support so administrators can use a private login URL instead of the default `wp-login.php` path. -
vulntitan/trunk/vulntitan.php
r3481425 r3481753 4 4 * Plugin URI: https://vulntitan.com/vulntitan/ 5 5 * Description: VulnTitan is a lightweight WordPress security plugin with vulnerability scanning, malware detection, file integrity monitoring, and a built-in firewall with WAF payload rules and login protection. 6 * Version: 2.0. 66 * Version: 2.0.7 7 7 * Author: Jaroslav Svetlik 8 8 * Author URI: https://vulntitan.com … … 30 30 31 31 // Define plugin constants 32 define('VULNTITAN_PLUGIN_VERSION', VULNTITAN_DEVELOPMENT ? uniqid() : '2.0. 6');32 define('VULNTITAN_PLUGIN_VERSION', VULNTITAN_DEVELOPMENT ? uniqid() : '2.0.7'); 33 33 define('VULNTITAN_PLUGIN_BASENAME', plugin_basename(__FILE__)); 34 34 define('VULNTITAN_PLUGIN_DIR', untrailingslashit(plugin_dir_path(__FILE__)));
Note: See TracChangeset
for help on using the changeset viewer.