HEX
Server: Apache
System: Linux vps-3158868-x.dattaweb.com 3.10.0-1160.119.1.el7.x86_64 #1 SMP Tue Jun 4 14:43:51 UTC 2024 x86_64
User: emerlux (1185)
PHP: 8.3.1
Disabled: system, shell, exec, system_exec, shell_exec, mysql_pconnect, passthru, popen, proc_open, proc_close, proc_nice, proc_terminate, proc_get_status, escapeshellarg, escapeshellcmd, eval
Upload Files
File: /home/emerlux/public_html/wp-content/plugins/wpvulnerability/wpvulnerability-run.php
<?php
/**
 * Running functions
 *
 * @package WPVulnerability
 *
 * @version 2.0.0
 */

defined( 'ABSPATH' ) || die( 'No script kiddies please!' );

/**
 * Adds a settings link to the plugin row in the plugins list.
 *
 * This function conditionally adds either a network admin settings link for multisite
 * or a standard settings link for single site installations.
 *
 * @since 3.5.0
 *
 * @param array $links The links that appear in the plugin row.
 *
 * @return array The modified array of links.
 */
function wpvulnerability_add_settings_link( $links ) {
	// Check if the user has the required capabilities to view the settings link.
	if ( wpvulnerability_capabilities() ) {
		// Determine the correct settings link based on the environment.
		if ( is_multisite() && is_network_admin() ) {
			// Network admin settings link for multisite.
			$links[] = '<a href="' . network_admin_url( 'settings.php?page=wpvulnerability-options' ) . '">' . __( 'Network Settings', 'wpvulnerability' ) . '</a>';
		} elseif ( ! is_multisite() && is_admin() ) {
			// Standard settings link for single site.
			$links[] = '<a href="' . get_admin_url( null, 'options-general.php?page=wpvulnerability-options' ) . '">' . __( 'Settings', 'wpvulnerability' ) . '</a>';
		}
	}
	return $links;
}

// Hook the function to the appropriate filters.
if ( is_multisite() ) {
	add_filter( 'network_admin_plugin_action_links_' . WPVULNERABILITY_PLUGIN_BASE, 'wpvulnerability_add_settings_link' );
} else {
	add_filter( 'plugin_action_links_' . WPVULNERABILITY_PLUGIN_BASE, 'wpvulnerability_add_settings_link' );
}

/**
 * Updates the plugin's vulnerability data.
 *
 * This function updates the vulnerability data for WordPress core, plugins, themes, PHP, Apache, nginx, MariaDB, and MySQL.
 * It ensures that the required functions are available by including the necessary files.
 * After updating the vulnerabilities, it flushes the WordPress cache.
 *
 * @since 2.0.0
 *
 * @return void
 */
function wpvulnerability_update_database_data() {

	// Ensure necessary files are included for core, plugins, and themes.
	require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-core.php';
	require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-plugins.php';
	require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-themes.php';
	require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-software.php';

	wpvulnerability_delete_transients();

	// Update core, plugins, and themes vulnerabilities.
	wpvulnerability_core_get_vulnerabilities_clean();
	wpvulnerability_plugin_get_vulnerabilities_clean();
	wpvulnerability_theme_get_vulnerabilities_clean();

	// Array of software types to update.
	$software_types = array( 'php', 'apache', 'nginx', 'mariadb', 'mysql', 'imagemagick', 'curl', 'memcached', 'redis', 'sqlite' );

	// Update vulnerabilities for each software type.
	foreach ( $software_types as $software ) {
		wpvulnerability_get_vulnerabilities_clean( $software );
	}

	wpvulnerability_statistics_get();

	// Clean the WordPress cache.
	wp_cache_flush();
}

/**
 * Updates the plugin's vulnerability data if the cache has expired.
 *
 * This function checks if the cached vulnerability data for various components (core, plugins, themes, PHP, Apache, nginx, MariaDB, MySQL) has expired and updates it accordingly.
 * It ensures that the required functions are available by including the necessary files.
 * The function handles both multisite and single site installations.
 *
 * @since 3.0.0
 *
 * @return void
 */
function wpvulnerability_expired_database_data() {

	// Ensure necessary files are included for core, plugins, and themes.
	require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-core.php';
	require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-plugins.php';
	require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-themes.php';
	require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-software.php';

	// Current time for cache expiration comparison.
	$cache_time = time();

	// Check and update core, plugins, and themes vulnerabilities if cache has expired.
	$components = array(
		'core'   => 'wpvulnerability-core-cache',
		'plugin' => 'wpvulnerability-plugins-cache',
		'theme'  => 'wpvulnerability-themes-cache',
	);

	foreach ( $components as $component => $cache_key ) {
		$cache_value = is_multisite() ? get_site_option( $cache_key ) : get_option( $cache_key );

		if ( json_decode( $cache_value ) < $cache_time ) {
			call_user_func( "wpvulnerability_{$component}_get_vulnerabilities_clean" );
		}
	}

	// Array of software types to update.
	$software_types = array( 'php', 'apache', 'nginx', 'mariadb', 'mysql', 'imagemagick', 'curl', 'memcached', 'redis', 'sqlite' );

	// Ensure necessary files are included and update vulnerabilities for each software type.
	foreach ( $software_types as $software ) {
		if ( is_multisite() ) {
			if ( json_decode( get_site_option( 'wpvulnerability-' . $software . '-cache' ) ) < $cache_time ) {
				wpvulnerability_get_vulnerabilities_clean( $software );
			}
		} elseif ( json_decode( get_option( 'wpvulnerability-' . $software . '-cache' ) ) < $cache_time ) {
				wpvulnerability_get_vulnerabilities_clean( $software );
		}
	}

	wpvulnerability_statistics_get();

	unset( $cache_time );
}

/**
 * Callback function for when the plugin is activated.
 * Adds plugin data options if they are not already created.
 *
 * @since 2.0.0
 *
 * @return void
 */
function wpvulnerability_activation() {
	$is_multisite  = is_multisite();
	$config_key    = $is_multisite ? 'get_site_option' : 'get_option';
	$add_option    = $is_multisite ? 'add_site_option' : 'add_option';
	$update_option = $is_multisite ? 'update_site_option' : 'update_option';

	wpvulnerability_delete_transients();

	// Add wpvulnerability-config option if it does not exist.
	if ( ! $config_key( 'wpvulnerability-config' ) ) {
																$default_config = array(
																	'emails'        => get_bloginfo( 'admin_email' ),
																	'period'        => 'weekly',
																	'day'           => 'monday',
																	'hour'          => 0,
																	'minute'        => 0,
																	'cache'         => 12,
																	'notify'        => array(
																		'email' => 'y',
																		'slack' => 'n',
																		'teams' => 'n',
																	),
																	'slack_webhook' => '',
																	'teams_webhook' => '',
																);
																$add_option( 'wpvulnerability-config', $default_config );
	}

	// Add other options if they do not exist.
	$options = array(
		'wpvulnerability-plugins'                => '',
		'wpvulnerability-plugins-cache'          => 0,
		'wpvulnerability-plugins-vulnerable'     => 0,
		'wpvulnerability-plugins-data'           => '',
		'wpvulnerability-plugins-data-cache'     => 0,
		'wpvulnerability-themes'                 => '',
		'wpvulnerability-themes-cache'           => 0,
		'wpvulnerability-themes-vulnerable'      => 0,
		'wpvulnerability-core'                   => '',
		'wpvulnerability-core-cache'             => 0,
		'wpvulnerability-core-vulnerable'        => 0,
		'wpvulnerability-php'                    => '',
		'wpvulnerability-php-cache'              => 0,
		'wpvulnerability-php-vulnerable'         => 0,
		'wpvulnerability-apache'                 => '',
		'wpvulnerability-apache-cache'           => 0,
		'wpvulnerability-apache-vulnerable'      => 0,
		'wpvulnerability-nginx'                  => '',
		'wpvulnerability-nginx-cache'            => 0,
		'wpvulnerability-nginx-vulnerable'       => 0,
		'wpvulnerability-mariadb'                => '',
		'wpvulnerability-mariadb-cache'          => 0,
		'wpvulnerability-mariadb-vulnerable'     => 0,
		'wpvulnerability-mysql'                  => '',
		'wpvulnerability-mysql-cache'            => 0,
		'wpvulnerability-mysql-vulnerable'       => 0,
		'wpvulnerability-imagemagick'            => '',
		'wpvulnerability-imagemagick-cache'      => 0,
		'wpvulnerability-imagemagick-vulnerable' => 0,
		'wpvulnerability-curl'                   => '',
		'wpvulnerability-curl-cache'             => 0,
		'wpvulnerability-curl-vulnerable'        => 0,
		'wpvulnerability-memcached'              => '',
		'wpvulnerability-memcached-cache'        => 0,
		'wpvulnerability-memcached-vulnerable'   => 0,
		'wpvulnerability-redis'                  => '',
		'wpvulnerability-redis-cache'            => 0,
		'wpvulnerability-redis-vulnerable'       => 0,
		'wpvulnerability-sqlite'                 => '',
		'wpvulnerability-sqlite-cache'           => 0,
		'wpvulnerability-sqlite-vulnerable'      => 0,
		'wpvulnerability-statistics'             => '',
		'wpvulnerability-statistics-cache'       => 0,
	);

	foreach ( $options as $key => $value ) {
		if ( ! $config_key( $key ) ) {
			$add_option( $key, $value );
		}
	}

	// Add wpvulnerability-analyze option if it does not exist.
	if ( ! $config_key( 'wpvulnerability-analyze' ) ) {
		$default_analyze = array(
			'core'        => 0,
			'plugins'     => 0,
			'themes'      => 0,
			'php'         => 0,
			'apache'      => 0,
			'nginx'       => 0,
			'mariadb'     => 0,
			'mysql'       => 0,
			'imagemagick' => 0,
			'curl'        => 0,
			'memcached'   => 0,
			'redis'       => 0,
			'sqlite'      => 0,
		);

		foreach ( array_keys( $default_analyze ) as $component ) {
			$constant = 'WPVULNERABILITY_HIDE_' . strtoupper( $component );
			if ( defined( $constant ) && constant( $constant ) ) {
				$default_analyze[ $component ] = 1;
			}
		}
		$current_option = $config_key( 'wpvulnerability-analyze' );

		if ( false === $current_option ) {
			$add_option( 'wpvulnerability-analyze', $default_analyze );
		} else {
			$updated_option = array_merge( $default_analyze, $current_option );
			if ( $updated_option !== $current_option ) {
				$update_option( 'wpvulnerability-analyze', $updated_option );
			}
		}
	}
}

/**
 * Callback function to run when the plugin is deactivated.
 * Deletes options and removes scheduled wp-cron jobs.
 *
 * @since 2.0.0
 *
 * @return void
 */
function wpvulnerability_deactivation() {
	$options = array(
		'wpvulnerability_settings',
		'wpvulnerability-data',
		'wpvulnerability-analyze',
		'wpvulnerability-themes',
		'wpvulnerability-themes-cache',
		'wpvulnerability-themes-vulnerable',
		'wpvulnerability-plugins',
		'wpvulnerability-plugins-cache',
		'wpvulnerability-plugins-vulnerable',
		'wpvulnerability-core',
		'wpvulnerability-core-cache',
		'wpvulnerability-core-vulnerable',
		'wpvulnerability-php',
		'wpvulnerability-php-cache',
		'wpvulnerability-php-vulnerable',
		'wpvulnerability-apache',
		'wpvulnerability-apache-cache',
		'wpvulnerability-apache-vulnerable',
		'wpvulnerability-nginx',
		'wpvulnerability-nginx-cache',
		'wpvulnerability-nginx-vulnerable',
		'wpvulnerability-mariadb',
		'wpvulnerability-mariadb-cache',
		'wpvulnerability-mariadb-vulnerable',
		'wpvulnerability-mysql',
		'wpvulnerability-mysql-cache',
		'wpvulnerability-mysql-vulnerable',
		'wpvulnerability-imagemagick',
		'wpvulnerability-imagemagick-cache',
		'wpvulnerability-imagemagick-vulnerable',
		'wpvulnerability-curl',
		'wpvulnerability-curl-cache',
		'wpvulnerability-curl-vulnerable',
		'wpvulnerability-memcached',
		'wpvulnerability-memcached-cache',
		'wpvulnerability-memcached-vulnerable',
		'wpvulnerability-redis',
		'wpvulnerability-redis-cache',
		'wpvulnerability-redis-vulnerable',
		'wpvulnerability-sqlite',
		'wpvulnerability-sqlite-cache',
		'wpvulnerability-sqlite-vulnerable',
		'wpvulnerability-statistics',
		'wpvulnerability-statistics-cache',
	);

	// Delete options based on the installation type.
	$delete_option_func = is_multisite() ? 'delete_site_option' : 'delete_option';
	foreach ( $options as $option ) {
		$delete_option_func( $option );
	}

	wpvulnerability_delete_transients();

	// Unschedule and remove scheduled wp-cron jobs.
	$cron_jobs = array(
		'wpvulnerability_notification',
		'wpvulnerability_update_database',
		'wpvulnerability_pull_db_data_event',
	);
	foreach ( $cron_jobs as $job ) {
		wp_unschedule_event( wp_next_scheduled( $job ), $job );
		wp_clear_scheduled_hook( $job );
	}
}

/**
 * Deletes all transients that start with 'wpvulnerability_'.
 *
 * @since 3.5.0
 *
 * @return void
 */
function wpvulnerability_delete_transients() {
	global $wpdb;

	// Determine if the site is multisite.
	$is_multisite = is_multisite();

	// Define the prefix according to whether it is multisite or not.
	$transient_prefix = $is_multisite ? '_site_transient_wpvulnerability_' : '_transient_wpvulnerability_';

	// Prepare the LIKE pattern securely.
	$like_pattern = $wpdb->esc_like( $transient_prefix ) . '%';

	// Try to get transients from cache first.
	$cache_key  = 'wpvulnerability_transients_list';
	$transients = wp_cache_get( $cache_key );

	if ( false === $transients ) {
		// If cache is empty, query the database for matching transients.
		$transients = $wpdb->get_col( // phpcs:ignore
			$wpdb->prepare(
				"SELECT option_name FROM {$wpdb->options} WHERE option_name LIKE %s",
				$like_pattern
			)
		); // phpcs:ignore

		// Store the result in cache for future use.
		wp_cache_set( $cache_key, $transients, '', HOUR_IN_SECONDS );
	}

	// If no transients are found, exit early.
	if ( empty( $transients ) ) {
		return;
	}

	foreach ( $transients as $transient ) {
		if ( $is_multisite ) {
			// For multisite, delete using delete_site_transient.
			$transient_name = str_replace( '_site_transient_', '', $transient );
			delete_site_transient( $transient_name );
		} else {
			// For single sites, delete using delete_transient.
			$transient_name = str_replace( '_transient_', '', $transient );
			delete_transient( $transient_name );
		}
	}

	// Optionally clear the cache after deletion.
	wp_cache_delete( $cache_key );
}

/**
 * Callback function to run when the plugin is uninstalled.
 * Deletes options and removes scheduled wp-cron jobs.
 *
 * @since 3.0.0
 *
 * @return void
 */
function wpvulnerability_uninstall() {
	// Delete deprecated options.
	delete_option( 'wpvulnerability_settings' );
	delete_option( 'wpvulnerability-data' );

	// Options to delete for both single site and multisite.
	$options = array(
		'wpvulnerability-themes',
		'wpvulnerability-themes-cache',
		'wpvulnerability-themes-vulnerable',
		'wpvulnerability-plugins',
		'wpvulnerability-plugins-cache',
		'wpvulnerability-plugins-vulnerable',
		'wpvulnerability-core',
		'wpvulnerability-core-cache',
		'wpvulnerability-core-vulnerable',
		'wpvulnerability-php',
		'wpvulnerability-php-cache',
		'wpvulnerability-php-vulnerable',
		'wpvulnerability-apache',
		'wpvulnerability-apache-cache',
		'wpvulnerability-apache-vulnerable',
		'wpvulnerability-nginx',
		'wpvulnerability-nginx-cache',
		'wpvulnerability-nginx-vulnerable',
		'wpvulnerability-mariadb',
		'wpvulnerability-mariadb-cache',
		'wpvulnerability-mariadb-vulnerable',
		'wpvulnerability-mysql',
		'wpvulnerability-mysql-cache',
		'wpvulnerability-mysql-vulnerable',
		'wpvulnerability-imagemagick',
		'wpvulnerability-imagemagick-cache',
		'wpvulnerability-imagemagick-vulnerable',
		'wpvulnerability-curl',
		'wpvulnerability-curl-cache',
		'wpvulnerability-curl-vulnerable',
		'wpvulnerability-memcached',
		'wpvulnerability-memcached-cache',
		'wpvulnerability-memcached-vulnerable',
		'wpvulnerability-redis',
		'wpvulnerability-redis-cache',
		'wpvulnerability-redis-vulnerable',
		'wpvulnerability-sqlite',
		'wpvulnerability-sqlite-cache',
		'wpvulnerability-sqlite-vulnerable',
		'wpvulnerability-statistics',
		'wpvulnerability-statistics-cache',
		'wpvulnerability-analyze',
	);

	// Delete options based on the installation type.
	$delete_option_func = is_multisite() ? 'delete_site_option' : 'delete_option';
	foreach ( $options as $option ) {
		$delete_option_func( $option );
	}

	// Delete config data.
	$delete_option_func( 'wpvulnerability-config' );

	wpvulnerability_delete_transients();

	// Unschedule and remove scheduled wp-cron jobs.
	$cron_jobs = array(
		'wpvulnerability_notification',
		'wpvulnerability_update_database',
	);
	foreach ( $cron_jobs as $job ) {
		wp_unschedule_event( wp_next_scheduled( $job ), $job );
		wp_clear_scheduled_hook( $job );
	}
}

/**
 * Filters and returns the WPVulnerability analysis setting for a given type.
 *
 * This function retrieves the WPVulnerability analysis settings, either from
 * the single site or the multisite network, depending on the WordPress setup.
 * It returns false if the specified type ('core', 'plugins', 'themes',
 * 'php', 'apache', 'nginx', 'mariadb', 'mysql') is set. If the type is not set or is invalid, it returns true.
 *
 * @since 3.3.0
 *
 * @param string $type The type of analysis setting to retrieve ('core', 'plugins', 'themes', 'php', 'apache', 'nginx', 'mariadb', 'mysql').
 *
 * @return bool False if the specified type is set, true if not set or invalid.
 */
function wpvulnerability_analyze_filter( $type ) {
	// Retrieve the analysis settings based on the WordPress setup.
	$wpvulnerability_analyze = is_multisite() ? get_site_option( 'wpvulnerability-analyze', array() ) : get_option( 'wpvulnerability-analyze', array() );

	// Define the valid types for analysis.
	$valid_types = array( 'core', 'plugins', 'themes', 'php', 'apache', 'nginx', 'mariadb', 'mysql', 'imagemagick', 'curl', 'memcached', 'redis', 'sqlite' );

	if ( in_array( $type, $valid_types, true ) ) {
		$constant = 'WPVULNERABILITY_HIDE_' . strtoupper( $type );
		if ( defined( $constant ) && constant( $constant ) ) {
			return false;
		}

		return ! ( isset( $wpvulnerability_analyze[ $type ] ) && (int) $wpvulnerability_analyze[ $type ] );
	}

	return true; // Return true for invalid types.
}

/**
 * Clean the cache after an update.
 *
 * This function is triggered after a plugin or theme update to clean the cache
 * and refresh the vulnerability data.
 *
 * @since 2.0.0
 *
 * @return void
 */
add_action( 'upgrader_process_complete', 'wpvulnerability_update_database_data', 10, 2 );

/**
 * Adds a notification count to the Plugins menu item in the WordPress admin if there are vulnerable plugins.
 *
 * This function retrieves the number of vulnerable plugins from the cache, either from a single site
 * or a multisite setup, and displays the count in the WordPress admin menu next to the Plugins menu item.
 * The count is shown with a gold background (#FFD700) and black text.
 *
 * @since 3.3.5
 *
 * @return void
 */
function wpvulnerability_counter_plugins() {

	if ( ! wpvulnerability_analyze_filter( 'plugins' ) ) {
		return; // Skip if plugin analysis is disabled.
	}

	// Retrieve the number of vulnerable plugins from cache.
	$wpvulnerability_plugins_count = is_multisite() && is_network_admin()
		? get_site_option( 'wpvulnerability-plugins-vulnerable' )
		: get_option( 'wpvulnerability-plugins-vulnerable' );

	// Decode the count from JSON, default to 0 if not set.
	$wpvulnerability_plugins_total = $wpvulnerability_plugins_count ? json_decode( $wpvulnerability_plugins_count ) : 0;

	if ( $wpvulnerability_plugins_total > 0 ) {
		global $menu;
		foreach ( $menu as $key => $value ) {
			if ( 'plugins.php' === $menu[ $key ][2] ) {
				$menu[ $key ][0] .= ' <span class="update-plugins" style="background-color: #FFD700; color: #000000;"><span class="update-count" title="' . __( 'Vulnerabilities', 'wpvulnerability' ) . '">' . esc_html( $wpvulnerability_plugins_total ) . '</span></span>'; // phpcs:ignore
				break;
			}
		}
	}
}

// Hook into the appropriate admin menu action based on the site type.
if ( is_multisite() && is_network_admin() ) {
	add_action( 'network_admin_menu', 'wpvulnerability_counter_plugins' );
} elseif ( ! is_multisite() ) {
	add_action( 'admin_menu', 'wpvulnerability_counter_plugins' );
}

/**
 * Adds a notification count to the Themes menu item in the WordPress admin if there are vulnerable themes.
 *
 * This function retrieves the number of vulnerable themes from the cache, either from a single site
 * or a multisite setup, and displays the count in the WordPress admin menu next to the Themes menu item.
 * The count is displayed with a gold background (#FFD700) and black text.
 *
 * @since 3.3.5
 *
 * @return void
 */
function wpvulnerability_counter_themes() {

	if ( ! wpvulnerability_analyze_filter( 'themes' ) ) {
		return; // Skip if theme analysis is disabled.
	}

	// Retrieve the number of theme vulnerabilities from cache.
	$wpvulnerability_themes_count = ( is_multisite() && is_network_admin() )
		? get_site_option( 'wpvulnerability-themes-vulnerable' )
		: get_option( 'wpvulnerability-themes-vulnerable' );

	// Decode the count from JSON, default to 0 if not set.
	$wpvulnerability_themes_total = $wpvulnerability_themes_count ? json_decode( $wpvulnerability_themes_count ) : 0;

	if ( $wpvulnerability_themes_total > 0 ) {

		// Check if we are in a multisite setup or not.
		if ( ! is_multisite() ) {
			global $submenu;

			// Check if the submenu for themes exists.
			if ( isset( $submenu['themes.php'] ) ) {
				foreach ( $submenu['themes.php'] as $key => $value ) {
					if ( 'themes.php' === $submenu['themes.php'][ $key ][2] ) {
						$submenu['themes.php'][ $key ][0] .= ' <span class="update-plugins" style="background-color: #FFD700; color: #000000;"><span class="update-count" title="' . esc_html__( 'Vulnerabilities', 'wpvulnerability' ) . '">' . esc_html( $wpvulnerability_themes_total ) . '</span></span>'; // phpcs:ignore
						break;
					}
				}
			}
		} elseif ( is_network_admin() ) {
			global $menu;

			foreach ( $menu as $key => $value ) {
				if ( 'themes.php' === $menu[ $key ][2] ) {
					$menu[ $key ][0] .= ' <span class="update-plugins" style="background-color: #FFD700; color: #000000;"><span class="update-count" title="' . esc_html__( 'Vulnerabilities', 'wpvulnerability' ) . '">' . esc_html( $wpvulnerability_themes_total ) . '</span></span>'; // phpcs:ignore
					break;
				}
			}
		}
	}
}

// Hook into the appropriate admin menu action based on the site type.
if ( is_multisite() && is_network_admin() ) {
	add_action( 'network_admin_menu', 'wpvulnerability_counter_themes' );
} elseif ( ! is_multisite() ) {
	add_action( 'admin_menu', 'wpvulnerability_counter_themes' );
}

/**
 * Adds a notification count to the Updates submenu item under Dashboard in the WordPress admin if there are core updates.
 *
 * This function checks for core updates and then displays the count in the WordPress admin submenu
 * next to the Updates menu item with a gold background (#FFD700) and black text.
 *
 * @since 3.3.5
 *
 * @return void
 */
function wpvulnerability_counter_core() {

	if ( ! wpvulnerability_analyze_filter( 'core' ) ) {
		return; // Skip if core analysis is disabled.
	}

	// Retrieve the number of core vulnerabilities from cache.
	$wpvulnerability_core_count = is_multisite() && is_network_admin()
		? get_site_option( 'wpvulnerability-core-vulnerable' )
		: get_option( 'wpvulnerability-core-vulnerable' );

	// Decode the count from JSON, default to 0 if not set.
	$wpvulnerability_core_total = $wpvulnerability_core_count ? json_decode( $wpvulnerability_core_count ) : 0;

	if ( $wpvulnerability_core_total > 0 ) {
		global $submenu;
		if ( isset( $submenu['index.php'] ) ) {
			foreach ( $submenu['index.php'] as $key => $value ) {
				if ( 'update-core.php' === $submenu['index.php'][ $key ][2] ) {
					$submenu['index.php'][ $key ][0] .= ' <span class="update-plugins" style="background-color: #FFD700; color: #000000;"><span class="update-count" title="' . __( 'Vulnerabilities', 'wpvulnerability' ) . '">' . esc_html( $wpvulnerability_core_total ) . '</span></span>'; // phpcs:ignore
					break;
				}
			}
		}
	}
}

// Hook into the appropriate admin menu action based on the site type.
if ( is_multisite() && is_network_admin() ) {
	add_action( 'network_admin_menu', 'wpvulnerability_counter_core' );
} elseif ( ! is_multisite() ) {
	add_action( 'admin_menu', 'wpvulnerability_counter_core' );
}