Bug when another plugin has an admin page with &tab= matching llar
-
LLAR version: 2.26.11
To reproduce:
- The user doesn’t have the ‘manage_options’ capability (so the llar admin menu won’t appear)
- Enable another plugin with an admin page with a &tab= that llar uses, e.g. &tab=settings
- Go to the admin page & tab of that plugin, so the url should be something like admin.php?page=myplugin&tab=settings
Instead of steps 2 & 3 you can also use any page with tab= in the query string, so going to /wp-admin/profile.php?tab=settings will produce the same error without the need for another plugin.
That will produce many errors, the first is:
[30-Jun-2024 14:57:40 UTC] PHP Warning: Undefined array key 2 in CENSORED\wp-admin\includes\plugin.php on line 1890 [30-Jun-2024 14:57:40 UTC] PHP Stack trace: [30-Jun-2024 14:57:40 UTC] PHP 1. {main}() CENSORED\wp-admin\admin.php:0 [30-Jun-2024 14:57:40 UTC] PHP 2. require() CENSORED\wp-admin\admin.php:158 [30-Jun-2024 14:57:40 UTC] PHP 3. require_once() CENSORED\wp-admin\menu.php:422 [30-Jun-2024 14:57:40 UTC] PHP 4. do_action($hook_name = 'admin_menu', ...$arg = variadic('')) CENSORED\wp-admin\includes\menu.php:161 [30-Jun-2024 14:57:40 UTC] PHP 5. WP_Hook->do_action($args = [0 => '']) CENSORED\wp-includes\plugin.php:517 [30-Jun-2024 14:57:40 UTC] PHP 6. WP_Hook->apply_filters($value = '', $args = [0 => '']) CENSORED\wp-includes\class-wp-hook.php:348 [30-Jun-2024 14:57:40 UTC] PHP 7. LLAR\Core\LimitLoginAttempts->admin_menu('') CENSORED\wp-includes\class-wp-hook.php:324 [30-Jun-2024 14:57:40 UTC] PHP 8. remove_submenu_page($menu_slug = 'limit-login-attempts', $submenu_slug = 'limit-login-attempts') CENSORED\wp-content\plugins\limit-login-attempts-reloaded\core\LimitLoginAttempts.php:758
The bug is in limit-login-attempts-reloaded\core\LimitLoginAttempts.php function admin_menu(), the specific code starts at line 741:
$index = 1; foreach ( $submenu_items as $item ) { add_submenu_page( $this->_options_page_slug, $item['name'], $item['name'], 'manage_options', $this->_options_page_slug . $item['url'], array( $this, 'options_page' ) ); if ( ! empty( $_GET['tab'] ) && $_GET['tab'] === $item['id'] ) { $submenu[$this->_options_page_slug][$index][4] = 'current'; } $index++; }
This code creates the submenu pages for llar, and sets the CSS class to ‘current’ if needed. However, the code does not check if the current page is llar, so
$submenu[$this->_options_page_slug][$index][4] = 'current';
is executed if &tab matches no matter the page the user is on.The problem comes if the user is on a page like ?page=myplugin&tab=settings. That causes the error above if the user does not have the capability to show llar, and also if the user does have the capability then the item will have the ‘current’ class added even though it isn’t the current page.
The following is a tested fix, though I imagine there are other ways to do it:
global $plugin_page; $is_llar_page = $plugin_page === $this->_options_page_slug; $index = 1; foreach ( $submenu_items as $item ) { add_submenu_page( $this->_options_page_slug, $item['name'], $item['name'], 'manage_options', $this->_options_page_slug . $item['url'], array( $this, 'options_page' ) ); if ( $is_llar_page && ! empty( $_GET['tab'] ) && $_GET['tab'] === $item['id'] ) { $submenu[$this->_options_page_slug][$index][4] = 'current'; } $index++; }
- You must be logged in to reply to this topic.