CVE-2023-48709: Insufficient Information (NVD-CWE-noinfo)
value: iTop is an IT service management platform.  When exporting data from backoffice or portal in CSV or Excel files, users' inputs may include malicious formulas that may be imported into Excel. As Excel 2016 does **not** prevent Remote Code Execution by default, uninformed users may become victims. This vulnerability is fixed in 2.7.9, 3.0.4, 3.1.1, and 3.2.0.
CWE description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
Published: 2024-04-15T18:15Z
Repository: https://github.com/Combodo/iTop
Language: PHP
Files changed: core/csvbulkexport.class.inc.php, core/excelbulkexport.class.inc.php, datamodels/2.x/itop-portal-base/portal/src/Controller/ManageBrickController.php, datamodels/2.x/itop-portal-base/portal/templates/bricks/manage/popup-export-excel.html.twig, dictionaries/cs.dictionary.itop.core.php, dictionaries/da.dictionary.itop.core.php, dictionaries/de.dictionary.itop.core.php, dictionaries/en.dictionary.itop.core.php, dictionaries/es_cr.dictionary.itop.core.php, dictionaries/fr.dictionary.itop.core.php, dictionaries/hu.dictionary.itop.core.php, dictionaries/it.dictionary.itop.core.php, dictionaries/ja.dictionary.itop.core.php, dictionaries/nl.dictionary.itop.core.php, dictionaries/pt_br.dictionary.itop.core.php, dictionaries/ru.dictionary.itop.core.php, dictionaries/sk.dictionary.itop.core.php, dictionaries/tr.dictionary.itop.core.php, dictionaries/zh_cn.dictionary.itop.core.php, lib/autoload.php, lib/composer/ClassLoader.php, lib/composer/autoload_classmap.php, lib/composer/autoload_files.php, lib/composer/autoload_namespaces.php, lib/composer/autoload_psr4.php, lib/composer/autoload_real.php, lib/composer/autoload_static.php, lib/composer/include_paths.php, sources/application/Helper/ExportHelper.php
Commit date: 2023-11-21 09:42:11 +0100
Commit message: N°6951 - Security hardening

Diff: diff --git a/core/csvbulkexport.class.inc.php b/core/csvbulkexport.class.inc.php
index bfb22cfcfa4..09e39067aa9 100644
--- a/core/csvbulkexport.class.inc.php
+++ b/core/csvbulkexport.class.inc.php
@@ -13,10 +13,11 @@
 //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 //   GNU Affero General Public License for more details.
 //
 //   You should have received a copy of the GNU Affero General Public License
 //   along with iTop. If not, see <http://www.gnu.org/licenses/>
+use Combodo\iTop\Application\Helper\ExportHelper;
 
 /**
  * Bulk export: CSV export
  *
  * @copyright   Copyright (C) 2015-2016 Combodo SARL
@@ -111,10 +112,11 @@ class CSVBulkExport extends TabularBulkExport
 				$this->GetInteractiveFieldsWidget($oP, 'interactive_fields_csv');
 				break;
 
 			case 'csv_options':
 				$oP->add('<fieldset><legend>'.Dict::S('Core:BulkExport:CSVOptions').'</legend>');
+                $oP->add(ExportHelper::GetAlertForExcelMaliciousInjection());
 				$oP->add('<table class="export_parameters"><tr><td style="vertical-align:top">');
 				$oP->add('<h3>'.Dict::S('UI:CSVImport:SeparatorCharacter').'</h3>');
 				$sRawSeparator = utils::ReadParam('separator', ',', true, 'raw_data');
 				$sCustomDateTimeFormat = utils::ReadParam('', ',', true, 'raw_data');
 				$aSep = array(
diff --git a/core/excelbulkexport.class.inc.php b/core/excelbulkexport.class.inc.php
index 1d456939731..ae307917130 100644
--- a/core/excelbulkexport.class.inc.php
+++ b/core/excelbulkexport.class.inc.php
@@ -21,10 +21,12 @@
  *
  * @copyright   Copyright (C) 2015-2016 Combodo SARL
  * @license     http://opensource.org/licenses/AGPL-3.0
  */
 
+use Combodo\iTop\Application\Helper\ExportHelper;
+
 require_once(APPROOT.'application/xlsxwriter.class.php');
 
 class ExcelBulkExport extends TabularBulkExport
 {
 	protected $sData;
@@ -87,10 +89,11 @@ class ExcelBulkExport extends TabularBulkExport
 				$this->GetInteractiveFieldsWidget($oP, 'interactive_fields_xlsx');
 				break;
 					
 			case 'xlsx_options':
 				$oP->add('<fieldset><legend>'.Dict::S('Core:BulkExport:XLSXOptions').'</legend>');
+                $oP->add(ExportHelper::GetAlertForExcelMaliciousInjection());
 				$oP->add('<table class="export_parameters"><tr><td style="vertical-align:top">');
 				
 				$sChecked = (utils::ReadParam('formatted_text', 0) == 1) ? ' checked ' : '';
 				$oP->add('<h3>'.Dict::S('Core:BulkExport:TextFormat').'</h3>');
 				$oP->add('<input type="checkbox" id="xlsx_formatted_text" name="formatted_text" value="1"'.$sChecked.'><label for="xlsx_formatted_text"> '.Dict::S('Core:BulkExport:OptionFormattedText').'</label>');
diff --git a/datamodels/2.x/itop-portal-base/portal/src/Controller/ManageBrickController.php b/datamodels/2.x/itop-portal-base/portal/src/Controller/ManageBrickController.php
index c1933372c41..c4408c170ae 100644
--- a/datamodels/2.x/itop-portal-base/portal/src/Controller/ManageBrickController.php
+++ b/datamodels/2.x/itop-portal-base/portal/src/Controller/ManageBrickController.php
@@ -47,10 +47,11 @@ use LogChannels;
 use MetaModel;
 use Symfony\Component\HttpFoundation\JsonResponse;
 use Symfony\Component\HttpFoundation\Request;
 use UnaryExpression;
 use URLButtonItem;
+use utils;
 
 /**
  * Class ManageBrickController
  *
  * @package Combodo\iTop\Portal\Controller
@@ -257,10 +258,11 @@ class ManageBrickController extends BrickController
 
 		$aData = array(
 			'oBrick' => $oBrick,
 			'sBrickId' => $sBrickId,
 			'sToken' => $oExporter->SaveState(),
+            'sWikiUrl' => 'https://www.itophub.io/wiki/page?id='.utils::GetItopVersionWikiSyntax().'%3Auser%3Alists#excel_export',
 		);
 
 		return $this->render(static::EXCEL_EXPORT_TEMPLATE_PATH, $aData);
 	}
 
diff --git a/datamodels/2.x/itop-portal-base/portal/templates/bricks/manage/popup-export-excel.html.twig b/datamodels/2.x/itop-portal-base/portal/templates/bricks/manage/popup-export-excel.html.twig
index 32417e3913b..c7a528f086f 100644
--- a/datamodels/2.x/itop-portal-base/portal/templates/bricks/manage/popup-export-excel.html.twig
+++ b/datamodels/2.x/itop-portal-base/portal/templates/bricks/manage/popup-export-excel.html.twig
@@ -9,10 +9,11 @@
         <p>{{ 'Core:BulkExport:ExportResult'|dict_s }}</p>
         <p id="export-error" class="alert alert-danger" role="alert"></p>
     </div>
 
     <div id="export-feedback">
+        <p id="export-excel-warning" class="alert alert-warning" role="alert">{{ 'UI:Bulk:Export:MaliciousInjection:Alert:Message'|dict_format(sWikiUrl)|raw }}</p>
         <p class="export-message" style="text-align:center;">{{ 'ExcelExport:PreparingExport'|dict_s }}</p>
         <div class="progress">
             <div class="progress-bar" role="progressbar" style="width: 0%"
                  aria-valuenow="0" aria-valuemin="0" aria-valuemax="100">
                 <span class="progress-message">0%</span>
diff --git a/dictionaries/cs.dictionary.itop.core.php b/dictionaries/cs.dictionary.itop.core.php
index c5a03926248..d64141a58ce 100755
--- a/dictionaries/cs.dictionary.itop.core.php
+++ b/dictionaries/cs.dictionary.itop.core.php
@@ -932,10 +932,11 @@ Dict::Add('CS CZ', 'Czech', 'Čeština', array(
 	'Core:BulkExport:TextFormat' => 'Textová pole obsahující HTML kód',
 	'Core:BulkExport:DateTimeFormat' => 'Date and Time format~~',
 	'Core:BulkExport:DateTimeFormatDefault_Example' => 'Default format (%1$s), e.g. %2$s~~',
 	'Core:BulkExport:DateTimeFormatCustom_Format' => 'Custom format: %1$s~~',
 	'Core:BulkExport:PDF:PageNumber' => 'Page %1$s~~',
+    'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s">Learn more in our documentation.</a>~~',
 	'Core:DateTime:Placeholder_d' => 'DD~~', // Day of the month: 2 digits (with leading zero)
 	'Core:DateTime:Placeholder_j' => 'D~~', // Day of the month: 1 or 2 digits (without leading zero)
 	'Core:DateTime:Placeholder_m' => 'MM~~', // Month on 2 digits i.e. 01-12
 	'Core:DateTime:Placeholder_n' => 'M~~', // Month on 1 or 2 digits 1-12
 	'Core:DateTime:Placeholder_Y' => 'YYYY~~', // Year on 4 digits
diff --git a/dictionaries/da.dictionary.itop.core.php b/dictionaries/da.dictionary.itop.core.php
index 99a95dc4a52..dc757bbf603 100644
--- a/dictionaries/da.dictionary.itop.core.php
+++ b/dictionaries/da.dictionary.itop.core.php
@@ -930,11 +930,12 @@ Dict::Add('DA DA', 'Danish', 'Dansk', array(
 	'Core:BulkExport:TextFormat' => 'Text fields containing some HTML markup~~',
 	'Core:BulkExport:DateTimeFormat' => 'Date and Time format~~',
 	'Core:BulkExport:DateTimeFormatDefault_Example' => 'Default format (%1$s), e.g. %2$s~~',
 	'Core:BulkExport:DateTimeFormatCustom_Format' => 'Custom format: %1$s~~',
 	'Core:BulkExport:PDF:PageNumber' => 'Page %1$s~~',
-	'Core:DateTime:Placeholder_d' => 'DD~~', // Day of the month: 2 digits (with leading zero)
+    'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s">Learn more in our documentation.</a>~~', 
+    'Core:DateTime:Placeholder_d' => 'DD~~', // Day of the month: 2 digits (with leading zero)
 	'Core:DateTime:Placeholder_j' => 'D~~', // Day of the month: 1 or 2 digits (without leading zero)
 	'Core:DateTime:Placeholder_m' => 'MM~~', // Month on 2 digits i.e. 01-12
 	'Core:DateTime:Placeholder_n' => 'M~~', // Month on 1 or 2 digits 1-12
 	'Core:DateTime:Placeholder_Y' => 'YYYY~~', // Year on 4 digits
 	'Core:DateTime:Placeholder_y' => 'YY~~', // Year on 2 digits
diff --git a/dictionaries/de.dictionary.itop.core.php b/dictionaries/de.dictionary.itop.core.php
index cd30938632c..b2d1d4c6ae5 100644
--- a/dictionaries/de.dictionary.itop.core.php
+++ b/dictionaries/de.dictionary.itop.core.php
@@ -929,11 +929,12 @@ Dict::Add('DE DE', 'German', 'Deutsch', array(
 	'Core:BulkExport:TextFormat' => 'Textfelder enthalten HTML-Markup',
 	'Core:BulkExport:DateTimeFormat' => 'Datum- und Zeitformat',
 	'Core:BulkExport:DateTimeFormatDefault_Example' => 'Standardformat (%1$s), z.B. %2$s',
 	'Core:BulkExport:DateTimeFormatCustom_Format' => 'Angepasstes format: %1$s',
 	'Core:BulkExport:PDF:PageNumber' => 'Seite %1$s',
-	'Core:DateTime:Placeholder_d' => 'TT', // Day of the month: 2 digits (with leading zero)
+    'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s">Learn more in our documentation.</a>~~', 
+    'Core:DateTime:Placeholder_d' => 'TT', // Day of the month: 2 digits (with leading zero)
 	'Core:DateTime:Placeholder_j' => 'T', // Day of the month: 1 or 2 digits (without leading zero)
 	'Core:DateTime:Placeholder_m' => 'MM', // Month on 2 digits i.e. 01-12
 	'Core:DateTime:Placeholder_n' => 'M', // Month on 1 or 2 digits 1-12
 	'Core:DateTime:Placeholder_Y' => 'JJJJ', // Year on 4 digits
 	'Core:DateTime:Placeholder_y' => 'JJ', // Year on 2 digits
diff --git a/dictionaries/en.dictionary.itop.core.php b/dictionaries/en.dictionary.itop.core.php
index bbbf41b2a04..bfbd6a949a5 100644
--- a/dictionaries/en.dictionary.itop.core.php
+++ b/dictionaries/en.dictionary.itop.core.php
@@ -930,10 +930,11 @@ Dict::Add('EN US', 'English', 'English', array(
 	'Core:BulkExport:TextFormat' => 'Text fields containing some HTML markup',
 	'Core:BulkExport:DateTimeFormat' => 'Date and Time format',
 	'Core:BulkExport:DateTimeFormatDefault_Example' => 'Default format (%1$s), e.g. %2$s',
 	'Core:BulkExport:DateTimeFormatCustom_Format' => 'Custom format: %1$s',
 	'Core:BulkExport:PDF:PageNumber' => 'Page %1$s',
+    'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s">Learn more in our documentation.</a>', 
 	'Core:DateTime:Placeholder_d' => 'DD', // Day of the month: 2 digits (with leading zero)
 	'Core:DateTime:Placeholder_j' => 'D', // Day of the month: 1 or 2 digits (without leading zero)
 	'Core:DateTime:Placeholder_m' => 'MM', // Month on 2 digits i.e. 01-12
 	'Core:DateTime:Placeholder_n' => 'M', // Month on 1 or 2 digits 1-12
 	'Core:DateTime:Placeholder_Y' => 'YYYY', // Year on 4 digits
diff --git a/dictionaries/es_cr.dictionary.itop.core.php b/dictionaries/es_cr.dictionary.itop.core.php
index 615184f6288..e5de92d84f2 100644
--- a/dictionaries/es_cr.dictionary.itop.core.php
+++ b/dictionaries/es_cr.dictionary.itop.core.php
@@ -931,11 +931,12 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellaño', array(
 	'Core:BulkExport:TextFormat' => 'Compos texto conteniendo algunas marcas HTML',
 	'Core:BulkExport:DateTimeFormat' => 'Formato de fecha y hora',
 	'Core:BulkExport:DateTimeFormatDefault_Example' => 'Formato por omisión (%1$s), ej. %2$s',
 	'Core:BulkExport:DateTimeFormatCustom_Format' => 'Formato personalizado: %1$s',
 	'Core:BulkExport:PDF:PageNumber' => 'Página %1$s',
-	'Core:DateTime:Placeholder_d' => 'DD', // Day of the month: 2 digits (with leading zero)
+    'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s">Learn more in our documentation.</a>~~',
+    'Core:DateTime:Placeholder_d' => 'DD', // Day of the month: 2 digits (with leading zero)
 	'Core:DateTime:Placeholder_j' => 'D', // Day of the month: 1 or 2 digits (without leading zero)
 	'Core:DateTime:Placeholder_m' => 'MM', // Month on 2 digits i.e. 01-12
 	'Core:DateTime:Placeholder_n' => 'M', // Month on 1 or 2 digits 1-12
 	'Core:DateTime:Placeholder_Y' => 'AAAA', // Year on 4 digits
 	'Core:DateTime:Placeholder_y' => 'AA', // Year on 2 digits
diff --git a/dictionaries/fr.dictionary.itop.core.php b/dictionaries/fr.dictionary.itop.core.php
index 2a9f66b3ae9..c27139f1646 100644
--- a/dictionaries/fr.dictionary.itop.core.php
+++ b/dictionaries/fr.dictionary.itop.core.php
@@ -928,11 +928,12 @@ Dict::Add('FR FR', 'French', 'Français', array(
 	'Core:BulkExport:TextFormat' => 'Champs texte contenant des balises HTML',
 	'Core:BulkExport:DateTimeFormat' => 'Format de date et heure',
 	'Core:BulkExport:DateTimeFormatDefault_Example' => 'Format par défaut (%1$s), ex. %2$s',
 	'Core:BulkExport:DateTimeFormatCustom_Format' => 'Format spécial: %1$s',
 	'Core:BulkExport:PDF:PageNumber' => 'Page %1$s',
-	'Core:DateTime:Placeholder_d' => 'JJ', // Day of the month: 2 digits (with leading zero)
+    'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'L\'ouverture d\'un fichier contenant des données non fiables dans Microsoft Excel peut entraîner l\'injection de formules. Assurez-vous que vos paramètres Excel sont configurés pour traiter les fichiers en toute sécurité. <a href="%1$s">Pour en savoir plus, consultez notre documentation.</a>',
+    'Core:DateTime:Placeholder_d' => 'JJ', // Day of the month: 2 digits (with leading zero)
 	'Core:DateTime:Placeholder_j' => 'J', // Day of the month: 1 or 2 digits (without leading zero)
 	'Core:DateTime:Placeholder_m' => 'MM', // Month on 2 digits i.e. 01-12
 	'Core:DateTime:Placeholder_n' => 'M', // Month on 1 or 2 digits 1-12
 	'Core:DateTime:Placeholder_Y' => 'AAAA', // Year on 4 digits
 	'Core:DateTime:Placeholder_y' => 'AA', // Year on 2 digits
diff --git a/dictionaries/hu.dictionary.itop.core.php b/dictionaries/hu.dictionary.itop.core.php
index 502680cf4e5..8b2f94700a2 100755
--- a/dictionaries/hu.dictionary.itop.core.php
+++ b/dictionaries/hu.dictionary.itop.core.php
@@ -928,11 +928,12 @@ Dict::Add('HU HU', 'Hungarian', 'Magyar', array(
 	'Core:BulkExport:TextFormat' => 'Text fields containing some HTML markup~~',
 	'Core:BulkExport:DateTimeFormat' => 'Date and Time format~~',
 	'Core:BulkExport:DateTimeFormatDefault_Example' => 'Default format (%1$s), e.g. %2$s~~',
 	'Core:BulkExport:DateTimeFormatCustom_Format' => 'Custom format: %1$s~~',
 	'Core:BulkExport:PDF:PageNumber' => 'Page %1$s~~',
-	'Core:DateTime:Placeholder_d' => 'DD~~', // Day of the month: 2 digits (with leading zero)
+    'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s">Learn more in our documentation.</a>~~',
+    'Core:DateTime:Placeholder_d' => 'DD~~', // Day of the month: 2 digits (with leading zero)
 	'Core:DateTime:Placeholder_j' => 'D~~', // Day of the month: 1 or 2 digits (without leading zero)
 	'Core:DateTime:Placeholder_m' => 'MM~~', // Month on 2 digits i.e. 01-12
 	'Core:DateTime:Placeholder_n' => 'M~~', // Month on 1 or 2 digits 1-12
 	'Core:DateTime:Placeholder_Y' => 'YYYY~~', // Year on 4 digits
 	'Core:DateTime:Placeholder_y' => 'YY~~', // Year on 2 digits
diff --git a/dictionaries/it.dictionary.itop.core.php b/dictionaries/it.dictionary.itop.core.php
index b0e3721ad57..621fc14c1e7 100644
--- a/dictionaries/it.dictionary.itop.core.php
+++ b/dictionaries/it.dictionary.itop.core.php
@@ -930,11 +930,12 @@ Dict::Add('IT IT', 'Italian', 'Italiano', array(
 	'Core:BulkExport:TextFormat' => 'Text fields containing some HTML markup~~',
 	'Core:BulkExport:DateTimeFormat' => 'Date and Time format~~',
 	'Core:BulkExport:DateTimeFormatDefault_Example' => 'Default format (%1$s), e.g. %2$s~~',
 	'Core:BulkExport:DateTimeFormatCustom_Format' => 'Custom format: %1$s~~',
 	'Core:BulkExport:PDF:PageNumber' => 'Page %1$s~~',
-	'Core:DateTime:Placeholder_d' => 'GG', // Day of the month: 2 digits (with leading zero)
+    'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s">Learn more in our documentation.</a>~~',
+    'Core:DateTime:Placeholder_d' => 'GG', // Day of the month: 2 digits (with leading zero)
 	'Core:DateTime:Placeholder_j' => 'G', // Day of the month: 1 or 2 digits (without leading zero)
 	'Core:DateTime:Placeholder_m' => 'MM', // Month on 2 digits i.e. 01-12
 	'Core:DateTime:Placeholder_n' => 'M', // Month on 1 or 2 digits 1-12
 	'Core:DateTime:Placeholder_Y' => 'AAAA', // Year on 4 digits
 	'Core:DateTime:Placeholder_y' => 'AA', // Year on 2 digits
diff --git a/dictionaries/ja.dictionary.itop.core.php b/dictionaries/ja.dictionary.itop.core.php
index 651a6c2dd4f..2866a1d0b11 100644
--- a/dictionaries/ja.dictionary.itop.core.php
+++ b/dictionaries/ja.dictionary.itop.core.php
@@ -928,11 +928,12 @@ Dict::Add('JA JP', 'Japanese', '日本語', array(
 	'Core:BulkExport:TextFormat' => 'Text fields containing some HTML markup~~',
 	'Core:BulkExport:DateTimeFormat' => 'Date and Time format~~',
 	'Core:BulkExport:DateTimeFormatDefault_Example' => 'Default format (%1$s), e.g. %2$s~~',
 	'Core:BulkExport:DateTimeFormatCustom_Format' => 'Custom format: %1$s~~',
 	'Core:BulkExport:PDF:PageNumber' => 'Page %1$s~~',
-	'Core:DateTime:Placeholder_d' => 'DD~~', // Day of the month: 2 digits (with leading zero)
+    'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s">Learn more in our documentation.</a>~~',
+    'Core:DateTime:Placeholder_d' => 'DD~~', // Day of the month: 2 digits (with leading zero)
 	'Core:DateTime:Placeholder_j' => 'D~~', // Day of the month: 1 or 2 digits (without leading zero)
 	'Core:DateTime:Placeholder_m' => 'MM~~', // Month on 2 digits i.e. 01-12
 	'Core:DateTime:Placeholder_n' => 'M~~', // Month on 1 or 2 digits 1-12
 	'Core:DateTime:Placeholder_Y' => 'YYYY~~', // Year on 4 digits
 	'Core:DateTime:Placeholder_y' => 'YY~~', // Year on 2 digits
diff --git a/dictionaries/nl.dictionary.itop.core.php b/dictionaries/nl.dictionary.itop.core.php
index eb0252ac838..6e7396741d4 100644
--- a/dictionaries/nl.dictionary.itop.core.php
+++ b/dictionaries/nl.dictionary.itop.core.php
@@ -936,11 +936,12 @@ Dict::Add('NL NL', 'Dutch', 'Nederlands', array(
 	'Core:BulkExport:TextFormat' => 'Tekstvelden die HTML-opmaak bevatten',
 	'Core:BulkExport:DateTimeFormat' => 'Datum- en tijdformaat',
 	'Core:BulkExport:DateTimeFormatDefault_Example' => 'Standaardformaat (%1$s), bv. %2$s',
 	'Core:BulkExport:DateTimeFormatCustom_Format' => 'Aangepast formaat: %1$s',
 	'Core:BulkExport:PDF:PageNumber' => 'Pagina %1$s',
-	'Core:DateTime:Placeholder_d' => 'DD', // Day of the month: 2 digits (with leading zero)
+    'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s">Learn more in our documentation.</a>~~',
+    'Core:DateTime:Placeholder_d' => 'DD', // Day of the month: 2 digits (with leading zero)
 	'Core:DateTime:Placeholder_j' => 'D', // Day of the month: 1 or 2 digits (without leading zero)
 	'Core:DateTime:Placeholder_m' => 'MM', // Month on 2 digits i.e. 01-12
 	'Core:DateTime:Placeholder_n' => 'M', // Month on 1 or 2 digits 1-12
 	'Core:DateTime:Placeholder_Y' => 'YYYY', // Year on 4 digits
 	'Core:DateTime:Placeholder_y' => 'YY', // Year on 2 digits
diff --git a/dictionaries/pt_br.dictionary.itop.core.php b/dictionaries/pt_br.dictionary.itop.core.php
index dc5fc782cce..bc0500321e5 100644
--- a/dictionaries/pt_br.dictionary.itop.core.php
+++ b/dictionaries/pt_br.dictionary.itop.core.php
@@ -930,11 +930,12 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
 	'Core:BulkExport:TextFormat' => 'Campos de texto contendo alguma marcação HTML',
 	'Core:BulkExport:DateTimeFormat' => 'Formato de data e hora',
 	'Core:BulkExport:DateTimeFormatDefault_Example' => 'Formato padrão (%1$s), por ex. %2$s',
 	'Core:BulkExport:DateTimeFormatCustom_Format' => 'Formato personalizado: %1$s',
 	'Core:BulkExport:PDF:PageNumber' => 'Página %1$s',
-	'Core:DateTime:Placeholder_d' => 'DD', // Day of the month: 2 digits (with leading zero)
+    'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s">Learn more in our documentation.</a>~~',
+    'Core:DateTime:Placeholder_d' => 'DD', // Day of the month: 2 digits (with leading zero)
 	'Core:DateTime:Placeholder_j' => 'D', // Day of the month: 1 or 2 digits (without leading zero)
 	'Core:DateTime:Placeholder_m' => 'MM', // Month on 2 digits i.e. 01-12
 	'Core:DateTime:Placeholder_n' => 'M', // Month on 1 or 2 digits 1-12
 	'Core:DateTime:Placeholder_Y' => 'YYYY', // Year on 4 digits
 	'Core:DateTime:Placeholder_y' => 'YY', // Year on 2 digits
diff --git a/dictionaries/ru.dictionary.itop.core.php b/dictionaries/ru.dictionary.itop.core.php
index a1a26429a39..1c1c48f6b34 100644
--- a/dictionaries/ru.dictionary.itop.core.php
+++ b/dictionaries/ru.dictionary.itop.core.php
@@ -917,11 +917,12 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
 	'Core:BulkExport:TextFormat' => 'Текстовые поля с HTML-разметкой',
 	'Core:BulkExport:DateTimeFormat' => 'Формат даты и времени',
 	'Core:BulkExport:DateTimeFormatDefault_Example' => 'Формат по умолчанию (%1$s), например %2$s',
 	'Core:BulkExport:DateTimeFormatCustom_Format' => 'Пользовательский формат: %1$s',
 	'Core:BulkExport:PDF:PageNumber' => 'Страница %1$s',
-	'Core:DateTime:Placeholder_d' => 'DD', // Day of the month: 2 digits (with leading zero)
+    'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s">Learn more in our documentation.</a>~~',
+    'Core:DateTime:Placeholder_d' => 'DD', // Day of the month: 2 digits (with leading zero)
 	'Core:DateTime:Placeholder_j' => 'D', // Day of the month: 1 or 2 digits (without leading zero)
 	'Core:DateTime:Placeholder_m' => 'MM', // Month on 2 digits i.e. 01-12
 	'Core:DateTime:Placeholder_n' => 'M', // Month on 1 or 2 digits 1-12
 	'Core:DateTime:Placeholder_Y' => 'YYYY', // Year on 4 digits
 	'Core:DateTime:Placeholder_y' => 'YY', // Year on 2 digits
diff --git a/dictionaries/sk.dictionary.itop.core.php b/dictionaries/sk.dictionary.itop.core.php
index 11458e6f3a8..d22cbac5b43 100644
--- a/dictionaries/sk.dictionary.itop.core.php
+++ b/dictionaries/sk.dictionary.itop.core.php
@@ -927,11 +927,12 @@ Dict::Add('SK SK', 'Slovak', 'Slovenčina', array(
 	'Core:BulkExport:TextFormat' => 'Text fields containing some HTML markup~~',
 	'Core:BulkExport:DateTimeFormat' => 'Date and Time format~~',
 	'Core:BulkExport:DateTimeFormatDefault_Example' => 'Default format (%1$s), e.g. %2$s~~',
 	'Core:BulkExport:DateTimeFormatCustom_Format' => 'Custom format: %1$s~~',
 	'Core:BulkExport:PDF:PageNumber' => 'Page %1$s~~',
-	'Core:DateTime:Placeholder_d' => 'DD~~', // Day of the month: 2 digits (with leading zero)
+    'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s">Learn more in our documentation.</a>~~',
+    'Core:DateTime:Placeholder_d' => 'DD~~', // Day of the month: 2 digits (with leading zero)
 	'Core:DateTime:Placeholder_j' => 'D~~', // Day of the month: 1 or 2 digits (without leading zero)
 	'Core:DateTime:Placeholder_m' => 'MM~~', // Month on 2 digits i.e. 01-12
 	'Core:DateTime:Placeholder_n' => 'M~~', // Month on 1 or 2 digits 1-12
 	'Core:DateTime:Placeholder_Y' => 'YYYY~~', // Year on 4 digits
 	'Core:DateTime:Placeholder_y' => 'YY~~', // Year on 2 digits
diff --git a/dictionaries/tr.dictionary.itop.core.php b/dictionaries/tr.dictionary.itop.core.php
index 82f36b56a46..f4b844a9238 100644
--- a/dictionaries/tr.dictionary.itop.core.php
+++ b/dictionaries/tr.dictionary.itop.core.php
@@ -938,11 +938,12 @@ Dict::Add('TR TR', 'Turkish', 'Türkçe', array(
 	'Core:BulkExport:TextFormat' => 'Bazı HTML işaretlemesi içeren metin alanları',
 	'Core:BulkExport:DateTimeFormat' => 'Date and Time format~~',
 	'Core:BulkExport:DateTimeFormatDefault_Example' => 'Default format (%1$s), e.g. %2$s~~',
 	'Core:BulkExport:DateTimeFormatCustom_Format' => 'Custom format: %1$s~~',
 	'Core:BulkExport:PDF:PageNumber' => 'Page %1$s~~',
-	'Core:DateTime:Placeholder_d' => 'DD~~', // Day of the month: 2 digits (with leading zero)
+    'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s">Learn more in our documentation.</a>~~',
+    'Core:DateTime:Placeholder_d' => 'DD~~', // Day of the month: 2 digits (with leading zero)
 	'Core:DateTime:Placeholder_j' => 'D~~', // Day of the month: 1 or 2 digits (without leading zero)
 	'Core:DateTime:Placeholder_m' => 'MM~~', // Month on 2 digits i.e. 01-12
 	'Core:DateTime:Placeholder_n' => 'M~~', // Month on 1 or 2 digits 1-12
 	'Core:DateTime:Placeholder_Y' => 'YYYY~~', // Year on 4 digits
 	'Core:DateTime:Placeholder_y' => 'YY~~', // Year on 2 digits
diff --git a/dictionaries/zh_cn.dictionary.itop.core.php b/dictionaries/zh_cn.dictionary.itop.core.php
index 5e0f585418d..870d6a3bbc1 100644
--- a/dictionaries/zh_cn.dictionary.itop.core.php
+++ b/dictionaries/zh_cn.dictionary.itop.core.php
@@ -929,11 +929,12 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
 	'Core:BulkExport:TextFormat' => '文本中包含一些HTML 标记',
 	'Core:BulkExport:DateTimeFormat' => '日期和时间格式',
 	'Core:BulkExport:DateTimeFormatDefault_Example' => '默认格式 (%1$s), e.g. %2$s',
 	'Core:BulkExport:DateTimeFormatCustom_Format' => '自定义格式: %1$s',
 	'Core:BulkExport:PDF:PageNumber' => '第 %1$s 页',
-	'Core:DateTime:Placeholder_d' => 'DD', // Day of the month: 2 digits (with leading zero)
+    'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s">Learn more in our documentation.</a>~~',
+    'Core:DateTime:Placeholder_d' => 'DD', // Day of the month: 2 digits (with leading zero)
 	'Core:DateTime:Placeholder_j' => 'D', // Day of the month: 1 or 2 digits (without leading zero)
 	'Core:DateTime:Placeholder_m' => 'MM', // Month on 2 digits i.e. 01-12
 	'Core:DateTime:Placeholder_n' => 'M', // Month on 1 or 2 digits 1-12
 	'Core:DateTime:Placeholder_Y' => 'YYYY', // Year on 4 digits
 	'Core:DateTime:Placeholder_y' => 'YY', // Year on 2 digits
diff --git a/lib/autoload.php b/lib/autoload.php
index 79c1600b5cb..d85126e453e 100644
--- a/lib/autoload.php
+++ b/lib/autoload.php
@@ -1,7 +1,25 @@
 <?php
 
 // 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 ComposerAutoloaderInit0018331147de7601e7552f7da8e3bb8b::getLoader();
diff --git a/lib/composer/ClassLoader.php b/lib/composer/ClassLoader.php
index 0cd6055d1b7..7824d8f7eaf 100644
--- a/lib/composer/ClassLoader.php
+++ b/lib/composer/ClassLoader.php
@@ -40,78 +40,79 @@ namespace Composer\Autoload;
  * @see    https://www.php-fig.org/psr/psr-0/
  * @see    https://www.php-fig.org/psr/psr-4/
  */
 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('Foo\Bar (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();
 
     /** @var bool */
     private $useIncludePath = false;
 
     /**
-     * @var string[]
-     * @psalm-var array<string, string>
+     * @var array<string, string>
      */
     private $classMap = array();
 
     /** @var bool */
     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()
     {
         if (!empty($this->prefixesPsr0)) {
             return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
@@ -119,48 +120,43 @@ class ClassLoader
 
         return array();
     }
 
     /**
-     * @return array[]
-     * @psalm-return array<string, array<int, string>>
+     * @return array<string, list<string>>
      */
     public function getPrefixesPsr4()
     {
         return $this->prefixDirsPsr4;
     }
 
     /**
-     * @return array[]
-     * @psalm-return array<string, string>
+     * @return list<string>
      */
     public function getFallbackDirs()
     {
         return $this->fallbackDirsPsr0;
     }
 
     /**
-     * @return array[]
-     * @psalm-return array<string, string>
+     * @return list<string>
      */
     public function getFallbackDirsPsr4()
     {
         return $this->fallbackDirsPsr4;
     }
 
     /**
-     * @return string[] Array of classname => path
-     * @psalm-var array<string, string>
+     * @return array<string, string> Array of classname => path
      */
     public function getClassMap()
     {
         return $this->classMap;
     }
 
     /**
-     * @param string[] $classMap Class to filename map
-     * @psalm-param array<string, string> $classMap
+     * @param array<string, string> $classMap Class to filename map
      *
      * @return void
      */
     public function addClassMap(array $classMap)
     {
@@ -173,109 +169,111 @@ class ClassLoader
 
     /**
      * 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
                 );
             }
 
             return;
         }
 
         $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
             );
         }
     }
 
     /**
      * 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
      *
      * @return void
      */
     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])) {
             // Register directories for a new namespace.
             $length = strlen($prefix);
             if ('\\' !== $prefix[$length - 1]) {
                 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
             );
         }
     }
 
     /**
      * 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
      */
     public function set($prefix, $paths)
     {
@@ -288,12 +286,12 @@ class ClassLoader
 
     /**
      * 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
      *
      * @return void
      */
@@ -423,11 +421,12 @@ class ClassLoader
      * @return true|null True if loaded, null otherwise
      */
     public function loadClass($class)
     {
         if ($file = $this->findFile($class)) {
-            includeFile($file);
+            $includeFile = self::$includeFile;
+            $includeFile($file);
 
             return true;
         }
 
         return null;
@@ -474,13 +473,13 @@ class ClassLoader
 
         return $file;
     }
 
     /**
-     * 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()
     {
         return self::$registeredLoaders;
     }
@@ -553,20 +552,28 @@ class ClassLoader
             return $file;
         }
 
         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);
+    }
 }
diff --git a/lib/composer/autoload_classmap.php b/lib/composer/autoload_classmap.php
index f080a002f7b..1481c8767d2 100644
--- a/lib/composer/autoload_classmap.php
+++ b/lib/composer/autoload_classmap.php
@@ -1,10 +1,10 @@
 <?php
 
 // autoload_classmap.php @generated by Composer
 
-$vendorDir = dirname(dirname(__FILE__));
+$vendorDir = dirname(__DIR__);
 $baseDir = dirname($vendorDir);
 
 return array(
     'AbstractApplicationObjectExtension' => $baseDir . '/application/applicationextension.inc.php',
     'AbstractApplicationUIExtension' => $baseDir . '/application/applicationextension.inc.php',
@@ -136,10 +136,11 @@ return array(
     'CellStatus_Void' => $baseDir . '/core/bulkchange.class.inc.php',
     'CharConcatExpression' => $baseDir . '/core/oql/expression.class.inc.php',
     'CharConcatWSExpression' => $baseDir . '/core/oql/expression.class.inc.php',
     'CheckStopWatchThresholds' => $baseDir . '/core/ormstopwatch.class.inc.php',
     'CheckableExpression' => $baseDir . '/core/oql/oqlquery.class.inc.php',
+    'Combodo\\iTop\\Application\\Helper\\ExportHelper' => $baseDir . '/sources/application/Helper/ExportHelper.php',
     'Combodo\\iTop\\Application\\Search\\AjaxSearchException' => $baseDir . '/sources/application/search/ajaxsearchexception.class.inc.php',
     'Combodo\\iTop\\Application\\Search\\CriterionConversionAbstract' => $baseDir . '/sources/application/search/criterionconversionabstract.class.inc.php',
     'Combodo\\iTop\\Application\\Search\\CriterionConversion\\CriterionToOQL' => $baseDir . '/sources/application/search/criterionconversion/criteriontooql.class.inc.php',
     'Combodo\\iTop\\Application\\Search\\CriterionConversion\\CriterionToSearchForm' => $baseDir . '/sources/application/search/criterionconversion/criteriontosearchform.class.inc.php',
     'Combodo\\iTop\\Application\\Search\\CriterionParser' => $baseDir . '/sources/application/search/criterionparser.class.inc.php',
@@ -448,10 +449,11 @@ return array(
     'Interop\\Container\\Exception\\NotFoundException' => $vendorDir . '/container-interop/container-interop/src/Interop/Container/Exception/NotFoundException.php',
     'IntervalExpression' => $baseDir . '/core/oql/expression.class.inc.php',
     'IntervalOqlExpression' => $baseDir . '/core/oql/oqlquery.class.inc.php',
     'Introspection' => $baseDir . '/core/introspection.class.inc.php',
     'InvalidConfigParamException' => $baseDir . '/core/coreexception.class.inc.php',
+    'InvalidExternalKeyValueException' => $baseDir . '/core/coreexception.class.inc.php',
     'InvalidPasswordAttributeOneWayPassword' => $baseDir . '/core/coreexception.class.inc.php',
     'IssueLog' => $baseDir . '/core/log.class.inc.php',
     'ItopCounter' => $baseDir . '/core/counter.class.inc.php',
     'JSButtonItem' => $baseDir . '/application/applicationextension.inc.php',
     'JSPopupMenuItem' => $baseDir . '/application/applicationextension.inc.php',
diff --git a/lib/composer/autoload_files.php b/lib/composer/autoload_files.php
index 7be757bea3e..ae02e5199e3 100644
--- a/lib/composer/autoload_files.php
+++ b/lib/composer/autoload_files.php
@@ -1,26 +1,26 @@
 <?php
 
 // autoload_files.php @generated by Composer
 
-$vendorDir = dirname(dirname(__FILE__));
+$vendorDir = dirname(__DIR__);
 $baseDir = dirname($vendorDir);
 
 return array(
     '320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php',
-    '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
     '5255c38a0faeba867671b61dfda6d864' => $vendorDir . '/paragonie/random_compat/lib/random.php',
     '023d27dca8066ef29e6739335ea73bad' => $vendorDir . '/symfony/polyfill-php70/bootstrap.php',
-    '32dcc8afd4335739640db7d200c1971d' => $vendorDir . '/symfony/polyfill-apcu/bootstrap.php',
-    '667aeda72477189d0494fecd327c3641' => $vendorDir . '/symfony/var-dumper/Resources/functions/dump.php',
-    'bd9634f2d41831496de0d3dfe4c94881' => $vendorDir . '/symfony/polyfill-php56/bootstrap.php',
+    '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
     '7e9bd612cc444b3eed788ebbe46263a0' => $vendorDir . '/laminas/laminas-zendframework-bridge/src/autoload.php',
     'e69f7f6ee287b969198c3c9d6777bd38' => $vendorDir . '/symfony/polyfill-intl-normalizer/bootstrap.php',
     '25072dd6e2470089de65ae7bf11d3109' => $vendorDir . '/symfony/polyfill-php72/bootstrap.php',
     'f598d06aa772fa33d905e87be6398fb1' => $vendorDir . '/symfony/polyfill-intl-idn/bootstrap.php',
     '7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php',
+    'bd9634f2d41831496de0d3dfe4c94881' => $vendorDir . '/symfony/polyfill-php56/bootstrap.php',
     'c964ee0ededf28c96ebd9db5099ef910' => $vendorDir . '/guzzlehttp/promises/src/functions_include.php',
     'a0edc8309cc5e1d60e3047b5df6b7052' => $vendorDir . '/guzzlehttp/psr7/src/functions_include.php',
     '37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php',
+    '32dcc8afd4335739640db7d200c1971d' => $vendorDir . '/symfony/polyfill-apcu/bootstrap.php',
     'def43f6c87e4f8dfd0c9e1b1bab14fe8' => $vendorDir . '/symfony/polyfill-iconv/bootstrap.php',
+    '667aeda72477189d0494fecd327c3641' => $vendorDir . '/symfony/var-dumper/Resources/functions/dump.php',
     '2c102faa651ef8ea5874edb585946bce' => $vendorDir . '/swiftmailer/swiftmailer/lib/swift_required.php',
 );
diff --git a/lib/composer/autoload_namespaces.php b/lib/composer/autoload_namespaces.php
index d12922d087a..e6117c7501b 100644
--- a/lib/composer/autoload_namespaces.php
+++ b/lib/composer/autoload_namespaces.php
@@ -1,10 +1,10 @@
 <?php
 
 // autoload_namespaces.php @generated by Composer
 
-$vendorDir = dirname(dirname(__FILE__));
+$vendorDir = dirname(__DIR__);
 $baseDir = dirname($vendorDir);
 
 return array(
     'Twig_' => array($vendorDir . '/twig/twig/lib'),
     'Console' => array($vendorDir . '/pear/console_getopt'),
diff --git a/lib/composer/autoload_psr4.php b/lib/composer/autoload_psr4.php
index ca8b4b9f6b7..651c9f0c103 100644
--- a/lib/composer/autoload_psr4.php
+++ b/lib/composer/autoload_psr4.php
@@ -1,10 +1,10 @@
 <?php
 
 // autoload_psr4.php @generated by Composer
 
-$vendorDir = dirname(dirname(__FILE__));
+$vendorDir = dirname(__DIR__);
 $baseDir = dirname($vendorDir);
 
 return array(
     'Twig\\' => array($vendorDir . '/twig/twig/src'),
     'TrueBV\\' => array($vendorDir . '/true/punycode/src'),
diff --git a/lib/composer/autoload_real.php b/lib/composer/autoload_real.php
index 661cd25436d..6c0e1e666a6 100644
--- a/lib/composer/autoload_real.php
+++ b/lib/composer/autoload_real.php
@@ -23,48 +23,33 @@ class ComposerAutoloaderInit0018331147de7601e7552f7da8e3bb8b
         }
 
         require __DIR__ . '/platform_check.php';
 
         spl_autoload_register(array('ComposerAutoloaderInit0018331147de7601e7552f7da8e3bb8b', 'loadClassLoader'), true, true);
-        self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__)));
+        self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
         spl_autoload_unregister(array('ComposerAutoloaderInit0018331147de7601e7552f7da8e3bb8b', 'loadClassLoader'));
 
         $includePaths = require __DIR__ . '/include_paths.php';
         $includePaths[] = get_include_path();
         set_include_path(implode(PATH_SEPARATOR, $includePaths));
 
-        $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(\Composer\Autoload\ComposerStaticInit0018331147de7601e7552f7da8e3bb8b::getInitializer($loader));
-        } else {
-            $classMap = require __DIR__ . '/autoload_classmap.php';
-            if ($classMap) {
-                $loader->addClassMap($classMap);
-            }
-        }
+        require __DIR__ . '/autoload_static.php';
+        call_user_func(\Composer\Autoload\ComposerStaticInit0018331147de7601e7552f7da8e3bb8b::getInitializer($loader));
 
         $loader->setClassMapAuthoritative(true);
         $loader->register(true);
 
-        if ($useStaticLoader) {
-            $includeFiles = Composer\Autoload\ComposerStaticInit0018331147de7601e7552f7da8e3bb8b::$files;
-        } else {
-            $includeFiles = require __DIR__ . '/autoload_files.php';
-        }
-        foreach ($includeFiles as $fileIdentifier => $file) {
-            composerRequire0018331147de7601e7552f7da8e3bb8b($fileIdentifier, $file);
+        $filesToLoad = \Composer\Autoload\ComposerStaticInit0018331147de7601e7552f7da8e3bb8b::$files;
+        $requireFile = \Closure::bind(static function ($fileIdentifier, $file) {
+            if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
+                $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
+
+                require $file;
+            }
+        }, null, null);
+        foreach ($filesToLoad as $fileIdentifier => $file) {
+            $requireFile($fileIdentifier, $file);
         }
 
         return $loader;
     }
 }
-
-function composerRequire0018331147de7601e7552f7da8e3bb8b($fileIdentifier, $file)
-{
-    if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
-        require $file;
-
-        $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
-    }
-}
diff --git a/lib/composer/autoload_static.php b/lib/composer/autoload_static.php
index 4a74a9cc435..48b0f9c5e74 100644
--- a/lib/composer/autoload_static.php
+++ b/lib/composer/autoload_static.php
@@ -6,25 +6,25 @@ namespace Composer\Autoload;
 
 class ComposerStaticInit0018331147de7601e7552f7da8e3bb8b
 {
     public static $files = array (
         '320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php',
-        '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
         '5255c38a0faeba867671b61dfda6d864' => __DIR__ . '/..' . '/paragonie/random_compat/lib/random.php',
         '023d27dca8066ef29e6739335ea73bad' => __DIR__ . '/..' . '/symfony/polyfill-php70/bootstrap.php',
-        '32dcc8afd4335739640db7d200c1971d' => __DIR__ . '/..' . '/symfony/polyfill-apcu/bootstrap.php',
-        '667aeda72477189d0494fecd327c3641' => __DIR__ . '/..' . '/symfony/var-dumper/Resources/functions/dump.php',
-        'bd9634f2d41831496de0d3dfe4c94881' => __DIR__ . '/..' . '/symfony/polyfill-php56/bootstrap.php',
+        '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
         '7e9bd612cc444b3eed788ebbe46263a0' => __DIR__ . '/..' . '/laminas/laminas-zendframework-bridge/src/autoload.php',
         'e69f7f6ee287b969198c3c9d6777bd38' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/bootstrap.php',
         '25072dd6e2470089de65ae7bf11d3109' => __DIR__ . '/..' . '/symfony/polyfill-php72/bootstrap.php',
         'f598d06aa772fa33d905e87be6398fb1' => __DIR__ . '/..' . '/symfony/polyfill-intl-idn/bootstrap.php',
         '7b11c4dc42b3b3023073cb14e519683c' => __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php',
+        'bd9634f2d41831496de0d3dfe4c94881' => __DIR__ . '/..' . '/symfony/polyfill-php56/bootstrap.php',
         'c964ee0ededf28c96ebd9db5099ef910' => __DIR__ . '/..' . '/guzzlehttp/promises/src/functions_include.php',
         'a0edc8309cc5e1d60e3047b5df6b7052' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/functions_include.php',
         '37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php',
+        '32dcc8afd4335739640db7d200c1971d' => __DIR__ . '/..' . '/symfony/polyfill-apcu/bootstrap.php',
         'def43f6c87e4f8dfd0c9e1b1bab14fe8' => __DIR__ . '/..' . '/symfony/polyfill-iconv/bootstrap.php',
+        '667aeda72477189d0494fecd327c3641' => __DIR__ . '/..' . '/symfony/var-dumper/Resources/functions/dump.php',
         '2c102faa651ef8ea5874edb585946bce' => __DIR__ . '/..' . '/swiftmailer/swiftmailer/lib/swift_required.php',
     );
 
     public static $prefixLengthsPsr4 = array (
         'T' => 
@@ -504,10 +504,11 @@ class ComposerStaticInit0018331147de7601e7552f7da8e3bb8b
         'CellStatus_Void' => __DIR__ . '/../..' . '/core/bulkchange.class.inc.php',
         'CharConcatExpression' => __DIR__ . '/../..' . '/core/oql/expression.class.inc.php',
         'CharConcatWSExpression' => __DIR__ . '/../..' . '/core/oql/expression.class.inc.php',
         'CheckStopWatchThresholds' => __DIR__ . '/../..' . '/core/ormstopwatch.class.inc.php',
         'CheckableExpression' => __DIR__ . '/../..' . '/core/oql/oqlquery.class.inc.php',
+        'Combodo\\iTop\\Application\\Helper\\ExportHelper' => __DIR__ . '/../..' . '/sources/application/Helper/ExportHelper.php',
         'Combodo\\iTop\\Application\\Search\\AjaxSearchException' => __DIR__ . '/../..' . '/sources/application/search/ajaxsearchexception.class.inc.php',
         'Combodo\\iTop\\Application\\Search\\CriterionConversionAbstract' => __DIR__ . '/../..' . '/sources/application/search/criterionconversionabstract.class.inc.php',
         'Combodo\\iTop\\Application\\Search\\CriterionConversion\\CriterionToOQL' => __DIR__ . '/../..' . '/sources/application/search/criterionconversion/criteriontooql.class.inc.php',
         'Combodo\\iTop\\Application\\Search\\CriterionConversion\\CriterionToSearchForm' => __DIR__ . '/../..' . '/sources/application/search/criterionconversion/criteriontosearchform.class.inc.php',
         'Combodo\\iTop\\Application\\Search\\CriterionParser' => __DIR__ . '/../..' . '/sources/application/search/criterionparser.class.inc.php',
@@ -816,10 +817,11 @@ class ComposerStaticInit0018331147de7601e7552f7da8e3bb8b
         'Interop\\Container\\Exception\\NotFoundException' => __DIR__ . '/..' . '/container-interop/container-interop/src/Interop/Container/Exception/NotFoundException.php',
         'IntervalExpression' => __DIR__ . '/../..' . '/core/oql/expression.class.inc.php',
         'IntervalOqlExpression' => __DIR__ . '/../..' . '/core/oql/oqlquery.class.inc.php',
         'Introspection' => __DIR__ . '/../..' . '/core/introspection.class.inc.php',
         'InvalidConfigParamException' => __DIR__ . '/../..' . '/core/coreexception.class.inc.php',
+        'InvalidExternalKeyValueException' => __DIR__ . '/../..' . '/core/coreexception.class.inc.php',
         'InvalidPasswordAttributeOneWayPassword' => __DIR__ . '/../..' . '/core/coreexception.class.inc.php',
         'IssueLog' => __DIR__ . '/../..' . '/core/log.class.inc.php',
         'ItopCounter' => __DIR__ . '/../..' . '/core/counter.class.inc.php',
         'JSButtonItem' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
         'JSPopupMenuItem' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
diff --git a/lib/composer/include_paths.php b/lib/composer/include_paths.php
index d4fb967181c..af33c14914c 100644
--- a/lib/composer/include_paths.php
+++ b/lib/composer/include_paths.php
@@ -1,10 +1,10 @@
 <?php
 
 // include_paths.php @generated by Composer
 
-$vendorDir = dirname(dirname(__FILE__));
+$vendorDir = dirname(__DIR__);
 $baseDir = dirname($vendorDir);
 
 return array(
     $vendorDir . '/pear/archive_tar',
     $vendorDir . '/pear/console_getopt',
diff --git a/sources/application/Helper/ExportHelper.php b/sources/application/Helper/ExportHelper.php
new file mode 100644
index 00000000000..79fdcd48ad9
--- /dev/null
+++ b/sources/application/Helper/ExportHelper.php
@@ -0,0 +1,23 @@
+<?php
+
+namespace Combodo\iTop\Application\Helper;
+use Dict;
+use utils;
+
+/**
+ * Class
+ * ExportHelper
+ *
+ * @internal
+ * @author Stephen Abello <stephen.abello@combodo.com>
+ * @since 2.7.9 3.0.4 3.1.1 3.2.0
+ * @package Combodo\iTop\Application\Helper
+ */
+class ExportHelper
+{
+	public static function GetAlertForExcelMaliciousInjection()
+	{
+        $sWikiUrl =  'https://www.itophub.io/wiki/page?id='.utils::GetItopVersionWikiSyntax().'%3Auser%3Alists#excel_export';
+		return '<div class="message_warning">' . Dict::Format('UI:Bulk:Export:MaliciousInjection:Alert:Message', $sWikiUrl) . '</div>';
+	}
+}
\ No newline at end of file

Vulnerable code: 	'Core:DateTime:Placeholder_d' => 'DD~~', // Day of the month: 2 digits (with leading zero)
	'Core:DateTime:Placeholder_d' => 'TT', // Day of the month: 2 digits (with leading zero)
	'Core:DateTime:Placeholder_d' => 'DD', // Day of the month: 2 digits (with leading zero)
	'Core:DateTime:Placeholder_d' => 'JJ', // Day of the month: 2 digits (with leading zero)
	'Core:DateTime:Placeholder_d' => 'DD~~', // Day of the month: 2 digits (with leading zero)
	'Core:DateTime:Placeholder_d' => 'GG', // Day of the month: 2 digits (with leading zero)
	'Core:DateTime:Placeholder_d' => 'DD~~', // Day of the month: 2 digits (with leading zero)
	'Core:DateTime:Placeholder_d' => 'DD', // Day of the month: 2 digits (with leading zero)
	'Core:DateTime:Placeholder_d' => 'DD', // Day of the month: 2 digits (with leading zero)
	'Core:DateTime:Placeholder_d' => 'DD', // Day of the month: 2 digits (with leading zero)
	'Core:DateTime:Placeholder_d' => 'DD~~', // Day of the month: 2 digits (with leading zero)
	'Core:DateTime:Placeholder_d' => 'DD~~', // Day of the month: 2 digits (with leading zero)
	'Core:DateTime:Placeholder_d' => 'DD', // Day of the month: 2 digits (with leading zero)
    /** @var ?string */
     * @var array[]
     * @psalm-var array<string, array<string, int>>
     * @var array[]
     * @psalm-var array<string, array<int, string>>
     * @var array[]
     * @psalm-var array<string, string>
     * @var array[]
     * @psalm-var array<string, array<string, string[]>>
     * @var array[]
     * @psalm-var array<string, string>
     * @var string[]
     * @psalm-var array<string, string>
     * @var bool[]
     * @psalm-var array<string, bool>
    /** @var ?string */
     * @var self[]
     * @param ?string $vendorDir
     * @return string[]
     * @return array[]
     * @psalm-return array<string, array<int, string>>
     * @return array[]
     * @psalm-return array<string, string>
     * @return array[]
     * @psalm-return array<string, string>
     * @return string[] Array of classname => path
     * @psalm-var array<string, string>
     * @param string[] $classMap Class to filename map
     * @psalm-param array<string, string> $classMap
     * @param string          $prefix  The prefix
     * @param string[]|string $paths   The PSR-0 root directories
     * @param bool            $prepend Whether to prepend the directories
                    (array) $paths,
                    (array) $paths
            $this->prefixesPsr0[$first][$prefix] = (array) $paths;
                (array) $paths,
                (array) $paths
     * @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
                    (array) $paths,
                    (array) $paths
            $this->prefixDirsPsr4[$prefix] = (array) $paths;
                (array) $paths,
                (array) $paths
     * @param string          $prefix The prefix
     * @param string[]|string $paths  The PSR-0 base directories
     * @param string          $prefix The prefix/namespace, with trailing '\\'
     * @param string[]|string $paths  The PSR-4 base directories
            includeFile($file);
     * Returns the currently registered loaders indexed by their corresponding vendor directories.
     * @return self[]
}
/**
 * Scope isolated include.
 *
 * Prevents access to $this/self from included files.
 *
 * @param  string $file
 * @return void
 * @private
 */
function includeFile($file)
{
    include $file;
$vendorDir = dirname(dirname(__FILE__));
$vendorDir = dirname(dirname(__FILE__));
    '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
    '32dcc8afd4335739640db7d200c1971d' => $vendorDir . '/symfony/polyfill-apcu/bootstrap.php',
    '667aeda72477189d0494fecd327c3641' => $vendorDir . '/symfony/var-dumper/Resources/functions/dump.php',
    'bd9634f2d41831496de0d3dfe4c94881' => $vendorDir . '/symfony/polyfill-php56/bootstrap.php',
$vendorDir = dirname(dirname(__FILE__));
$vendorDir = dirname(dirname(__FILE__));
        self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__)));
        $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(\Composer\Autoload\ComposerStaticInit0018331147de7601e7552f7da8e3bb8b::getInitializer($loader));
        } else {
            $classMap = require __DIR__ . '/autoload_classmap.php';
            if ($classMap) {
                $loader->addClassMap($classMap);
            }
        }
        if ($useStaticLoader) {
            $includeFiles = Composer\Autoload\ComposerStaticInit0018331147de7601e7552f7da8e3bb8b::$files;
        } else {
            $includeFiles = require __DIR__ . '/autoload_files.php';
        }
        foreach ($includeFiles as $fileIdentifier => $file) {
            composerRequire0018331147de7601e7552f7da8e3bb8b($fileIdentifier, $file);

function composerRequire0018331147de7601e7552f7da8e3bb8b($fileIdentifier, $file)
{
    if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
        require $file;

        $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
    }
}
        '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
        '32dcc8afd4335739640db7d200c1971d' => __DIR__ . '/..' . '/symfony/polyfill-apcu/bootstrap.php',
        '667aeda72477189d0494fecd327c3641' => __DIR__ . '/..' . '/symfony/var-dumper/Resources/functions/dump.php',
        'bd9634f2d41831496de0d3dfe4c94881' => __DIR__ . '/..' . '/symfony/polyfill-php56/bootstrap.php',
$vendorDir = dirname(dirname(__FILE__));
Fixed code: use Combodo\iTop\Application\Helper\ExportHelper;
                $oP->add(ExportHelper::GetAlertForExcelMaliciousInjection());
use Combodo\iTop\Application\Helper\ExportHelper;

                $oP->add(ExportHelper::GetAlertForExcelMaliciousInjection());
use utils;
            'sWikiUrl' => 'https://www.itophub.io/wiki/page?id='.utils::GetItopVersionWikiSyntax().'%3Auser%3Alists#excel_export',
        <p id="export-excel-warning" class="alert alert-warning" role="alert">{{ 'UI:Bulk:Export:MaliciousInjection:Alert:Message'|dict_format(sWikiUrl)|raw }}</p>
    'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s">Learn more in our documentation.</a>~~',
    'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s">Learn more in our documentation.</a>~~', 
    'Core:DateTime:Placeholder_d' => 'DD~~', // Day of the month: 2 digits (with leading zero)
    'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s">Learn more in our documentation.</a>~~', 
    'Core:DateTime:Placeholder_d' => 'TT', // Day of the month: 2 digits (with leading zero)
    'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s">Learn more in our documentation.</a>', 
    'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s">Learn more in our documentation.</a>~~',
    'Core:DateTime:Placeholder_d' => 'DD', // Day of the month: 2 digits (with leading zero)
    'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'L\'ouverture d\'un fichier contenant des données non fiables dans Microsoft Excel peut entraîner l\'injection de formules. Assurez-vous que vos paramètres Excel sont configurés pour traiter les fichiers en toute sécurité. <a href="%1$s">Pour en savoir plus, consultez notre documentation.</a>',
    'Core:DateTime:Placeholder_d' => 'JJ', // Day of the month: 2 digits (with leading zero)
    'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s">Learn more in our documentation.</a>~~',
    'Core:DateTime:Placeholder_d' => 'DD~~', // Day of the month: 2 digits (with leading zero)
    'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s">Learn more in our documentation.</a>~~',
    'Core:DateTime:Placeholder_d' => 'GG', // Day of the month: 2 digits (with leading zero)
    'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s">Learn more in our documentation.</a>~~',
    'Core:DateTime:Placeholder_d' => 'DD~~', // Day of the month: 2 digits (with leading zero)
    'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s">Learn more in our documentation.</a>~~',
    'Core:DateTime:Placeholder_d' => 'DD', // Day of the month: 2 digits (with leading zero)
    'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s">Learn more in our documentation.</a>~~',
    'Core:DateTime:Placeholder_d' => 'DD', // Day of the month: 2 digits (with leading zero)
    'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s">Learn more in our documentation.</a>~~',
    'Core:DateTime:Placeholder_d' => 'DD', // Day of the month: 2 digits (with leading zero)
    'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s">Learn more in our documentation.</a>~~',
    'Core:DateTime:Placeholder_d' => 'DD~~', // Day of the month: 2 digits (with leading zero)
    'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s">Learn more in our documentation.</a>~~',
    'Core:DateTime:Placeholder_d' => 'DD~~', // Day of the month: 2 digits (with leading zero)
    'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s">Learn more in our documentation.</a>~~',
    'Core:DateTime:Placeholder_d' => 'DD', // Day of the month: 2 digits (with leading zero)
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
    );
}

    /** @var \Closure(string):void */
    private static $includeFile;

    /** @var string|null */
     * @var array<string, array<string, int>>
     * @var array<string, list<string>>
     * @var list<string>
     * List of PSR-0 prefixes
     *
     * Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2')))
     *
     * @var array<string, array<string, list<string>>>
     * @var list<string>
     * @var array<string, string>
     * @var array<string, bool>
    /** @var string|null */
     * @var array<string, self>
     * @param string|null $vendorDir
        self::initializeIncludeClosure();
     * @return array<string, list<string>>
     * @return array<string, list<string>>
     * @return list<string>
     * @return list<string>
     * @return array<string, string> Array of classname => path
     * @param array<string, string> $classMap Class to filename map
     * @param string              $prefix  The prefix
     * @param list<string>|string $paths   The PSR-0 root directories
     * @param bool                $prepend Whether to prepend the directories
        $paths = (array) $paths;
                    $paths,
                    $paths
            $this->prefixesPsr0[$first][$prefix] = $paths;
                $paths,
                $paths
     * @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
        $paths = (array) $paths;
                    $paths,
                    $paths
            $this->prefixDirsPsr4[$prefix] = $paths;
                $paths,
                $paths
     * @param string              $prefix The prefix
     * @param list<string>|string $paths  The PSR-0 base directories
     * @param string              $prefix The prefix/namespace, with trailing '\\'
     * @param list<string>|string $paths  The PSR-4 base directories
            $includeFile = self::$includeFile;
            $includeFile($file);
     * Returns the currently registered loaders keyed by their corresponding vendor directories.
     * @return array<string, self>
    /**
     * @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);
    }
$vendorDir = dirname(__DIR__);
    'Combodo\\iTop\\Application\\Helper\\ExportHelper' => $baseDir . '/sources/application/Helper/ExportHelper.php',
    'InvalidExternalKeyValueException' => $baseDir . '/core/coreexception.class.inc.php',
$vendorDir = dirname(__DIR__);
    '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
    'bd9634f2d41831496de0d3dfe4c94881' => $vendorDir . '/symfony/polyfill-php56/bootstrap.php',
    '32dcc8afd4335739640db7d200c1971d' => $vendorDir . '/symfony/polyfill-apcu/bootstrap.php',
    '667aeda72477189d0494fecd327c3641' => $vendorDir . '/symfony/var-dumper/Resources/functions/dump.php',
$vendorDir = dirname(__DIR__);
$vendorDir = dirname(__DIR__);
        self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
        require __DIR__ . '/autoload_static.php';
        call_user_func(\Composer\Autoload\ComposerStaticInit0018331147de7601e7552f7da8e3bb8b::getInitializer($loader));
        $filesToLoad = \Composer\Autoload\ComposerStaticInit0018331147de7601e7552f7da8e3bb8b::$files;
        $requireFile = \Closure::bind(static function ($fileIdentifier, $file) {
            if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
                $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;

                require $file;
            }
        }, null, null);
        foreach ($filesToLoad as $fileIdentifier => $file) {
            $requireFile($fileIdentifier, $file);
        '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
        'bd9634f2d41831496de0d3dfe4c94881' => __DIR__ . '/..' . '/symfony/polyfill-php56/bootstrap.php',
        '32dcc8afd4335739640db7d200c1971d' => __DIR__ . '/..' . '/symfony/polyfill-apcu/bootstrap.php',
        '667aeda72477189d0494fecd327c3641' => __DIR__ . '/..' . '/symfony/var-dumper/Resources/functions/dump.php',
        'Combodo\\iTop\\Application\\Helper\\ExportHelper' => __DIR__ . '/../..' . '/sources/application/Helper/ExportHelper.php',
        'InvalidExternalKeyValueException' => __DIR__ . '/../..' . '/core/coreexception.class.inc.php',
$vendorDir = dirname(__DIR__);
<?php

namespace Combodo\iTop\Application\Helper;
use Dict;
use utils;

/**
 * Class
 * ExportHelper
 *
 * @internal
 * @author Stephen Abello <stephen.abello@combodo.com>
 * @since 2.7.9 3.0.4 3.1.1 3.2.0
 * @package Combodo\iTop\Application\Helper
 */
class ExportHelper
{
	public static function GetAlertForExcelMaliciousInjection()
	{
        $sWikiUrl =  'https://www.itophub.io/wiki/page?id='.utils::GetItopVersionWikiSyntax().'%3Auser%3Alists#excel_export';
		return '<div class="message_warning">' . Dict::Format('UI:Bulk:Export:MaliciousInjection:Alert:Message', $sWikiUrl) . '</div>';
	}
}