CVE-2020-5299: Improper Neutralization of Special Elements used in a Command ('Command Injection') (CWE-77)
value: In OctoberCMS (october/october composer package) versions from 1.0.319 and before 1.0.466, any users with the ability to modify any data that could eventually be exported as a CSV file from the `ImportExportController` could potentially introduce a CSV injection into the data to cause the generated CSV export file to be malicious. This requires attackers to achieve the following before a successful attack can be completed: 1. Have found a vulnerability in the victims spreadsheet software of choice. 2. Control data that would potentially be exported through the `ImportExportController` by a theoretical victim. 3. Convince the victim to export above data as a CSV and run it in vulnerable spreadsheet software while also bypassing any sanity checks by said software. Issue has been patched in Build 466 (v1.0.466).
CWE description: The product constructs all or part of a command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended command when it is sent to a downstream component.
CVSS v3 base score: 5.1
Published: 2020-06-03T22:15Z
Repository: https://github.com/octobercms/october
Language: PHP
Files changed: modules/backend/behaviors/ImportExportController.php, modules/backend/models/ExportModel.php
Commit date: 2020-03-31 09:53:35 -0600
Commit message: Temporary workaround until the L6 upgrade can be merged in to use league/csv >= 9.1

Diff: diff --git a/modules/backend/behaviors/ImportExportController.php b/modules/backend/behaviors/ImportExportController.php
index 950234362d..c146050b64 100644
--- a/modules/backend/behaviors/ImportExportController.php
+++ b/modules/backend/behaviors/ImportExportController.php
@@ -9,10 +9,11 @@ use BackendAuth;
 use Backend\Classes\ControllerBehavior;
 use Backend\Behaviors\ImportExportController\TranscodeFilter;
 use Illuminate\Database\Eloquent\MassAssignmentException;
 use League\Csv\Reader as CsvReader;
 use League\Csv\Writer as CsvWriter;
+use October\Rain\Parse\League\EscapeFormula as CsvEscapeFormula;
 use ApplicationException;
 use SplTempFileObject;
 use Exception;
 
 /**
@@ -622,10 +623,13 @@ class ImportExportController extends ControllerBehavior
         $csv->setOutputBOM(CsvWriter::BOM_UTF8);
         $csv->setDelimiter($options['delimiter']);
         $csv->setEnclosure($options['enclosure']);
         $csv->setEscape($options['escape']);
 
+        // Temporary until upgrading to league/csv >= 9.1.0 (will be $csv->addFormatter($formatter))
+        $formatter = new CsvEscapeFormula();
+
         /*
          * Add headers
          */
         $headers = [];
         $columns = $widget->getVisibleColumns();
@@ -655,10 +659,14 @@ class ImportExportController extends ControllerBehavior
                 if (is_array($value)) {
                     $value = implode('|', $value);
                 }
                 $record[] = $value;
             }
+
+            // Temporary until upgrading to league/csv >= 9.1.0
+            $record = $formatter($record);
+
             $csv->insertOne($record);
         }
 
         /*
          * Response
diff --git a/modules/backend/models/ExportModel.php b/modules/backend/models/ExportModel.php
index e0ec00e3c4..1a03a813b7 100644
--- a/modules/backend/models/ExportModel.php
+++ b/modules/backend/models/ExportModel.php
@@ -3,10 +3,11 @@
 use File;
 use Lang;
 use Model;
 use Response;
 use League\Csv\Writer as CsvWriter;
+use October\Rain\Parse\League\EscapeFormula as CsvEscapeFormula;
 use ApplicationException;
 use SplTempFileObject;
 
 /**
  * Model used for exporting data
@@ -109,10 +110,13 @@ abstract class ExportModel extends Model
 
         if ($options['escape'] !== null) {
             $csv->setEscape($options['escape']);
         }
 
+        // Temporary until upgrading to league/csv >= 9.1.0 (will be $csv->addFormatter($formatter))
+        $formatter = new CsvEscapeFormula();
+
         /*
          * Add headers
          */
         if ($options['firstRowTitles']) {
             $headers = $this->getColumnHeaders($columns);
@@ -122,10 +126,14 @@ abstract class ExportModel extends Model
         /*
          * Add records
          */
         foreach ($results as $result) {
             $data = $this->matchDataToColumns($result, $columns);
+
+            // Temporary until upgrading to league/csv >= 9.1.0
+            $data = $formatter($data);
+
             $csv->insertOne($data);
         }
 
         /*
          * Output

Fixed code: use October\Rain\Parse\League\EscapeFormula as CsvEscapeFormula;
        // Temporary until upgrading to league/csv >= 9.1.0 (will be $csv->addFormatter($formatter))
        $formatter = new CsvEscapeFormula();


            // Temporary until upgrading to league/csv >= 9.1.0
            $record = $formatter($record);

use October\Rain\Parse\League\EscapeFormula as CsvEscapeFormula;
        // Temporary until upgrading to league/csv >= 9.1.0 (will be $csv->addFormatter($formatter))
        $formatter = new CsvEscapeFormula();


            // Temporary until upgrading to league/csv >= 9.1.0
            $data = $formatter($data);