CVE-2023-4006 (published 2023-07-31T01:15Z)

Improper Neutralization of Formula Elements in a CSV File in GitHub repository thorsten/phpmyfaq prior to 3.1.16.

CVSS v3 base score: 9.8, CRITICAL (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)

Weakness information:
cwe_id: CWE-1236
cwe_name: Improper Neutralization of Formula Elements in a CSV File
description: The product saves user-provided information into a Comma-Separated Value (CSV) file, but it does not neutralize or incorrectly neutralizes special elements that could be interpreted as a command when the file is opened by a spreadsheet product.
extended_description: User-provided data is often saved to traditional databases.  This data can be exported to a CSV file, which allows users to read the data using spreadsheet software such as Excel, Numbers, or Calc.  This software interprets entries beginning with '=' as formulas, which are then executed by the spreadsheet software.  The software's formula language often allows methods to access hyperlinks or the local command line, and frequently allows enough characters to invoke an entire script. Attackers can populate data fields which, when saved to a CSV file, may attempt information exfiltration or other malicious activity when automatically executed by the spreadsheet software.
			

Fix information:
repo_url: https://github.com/thorsten/phpmyfaq
commit_details: repo_url: https://github.com/thorsten/phpmyfaq
author: Thorsten Rinne
author_date: 2023-07-01 10:10:47+02:00
msg: fix: added sanitizer for CSV
repository: repo_url: https://github.com/thorsten/phpmyfaq
repo_name: thorsten/phpMyFAQ
description: phpMyFAQ - Open Source FAQ web application for PHP 8.1+ and MySQL, PostgreSQL and other databases
repo_language: PHP
owner: thorsten
file_changes: filename: report.export.php
change_type: ModificationType.MODIFY
diff: @@ -116,7 +116,8 @@ if ($user->perm->hasPermission($user->getUserId(), 'reports')) {
 
     $content = '';
     foreach ($text as $row) {
-        $content .= implode(';', $row);
+        $csvRow = array_map(['phpMyFAQ\Report', 'sanitize'], $row);
+        $content .= implode(';', $csvRow);
         $content .= "\r\n";
     }
 

programming_language: PHP
filename: Report.php
change_type: ModificationType.MODIFY
diff: @@ -28,7 +28,7 @@ class Report
     /**
      * @var Configuration
      */
-    private $config;
+    private Configuration $config;
 
     /**
      * Constructor.
@@ -147,4 +147,18 @@ class Report
         $toBeRemoved = ['=', '+', '-', 'HYPERLINK'];
         return str_replace($toBeRemoved, '', $outputString);
     }
+
+    /**
+     * Sanitizes input to avoid CSV injection.
+     * @param string|int $value
+     * @return string
+     */
+    public static function sanitize($value): string
+    {
+        if (preg_match('/[=\+\-\@\|]/', $value)) {
+            $value = '"' . str_replace('"', '""', $value) . '"';
+        }
+
+        return $value;
+    }
 }

programming_language: PHP
filename: ReportTest.php
change_type: ModificationType.ADD
diff: @@ -0,0 +1,31 @@
+<?php
+
+namespace phpMyFAQ;
+
+use PHPUnit\Framework\TestCase;
+
+class ReportTest extends TestCase
+{
+
+    public function testSanitize(): void
+    {
+        $data = [
+            ['John Doe', 'john.doe@example.com', '12345'],
+            ['Jane Smith', 'jane.smith@example.com', '=SUM(A1:A10)'],
+        ];
+
+        $actual = [];
+
+        $expected = [
+            'John Doe,"john.doe@example.com",12345',
+            'Jane Smith,"jane.smith@example.com","=SUM(A1:A10)"'
+        ];
+
+        foreach ($data as $row) {
+            $csvRow = array_map(['phpMyFAQ\Report', 'sanitize'], $row);
+            $actual[] = implode(',', $csvRow);
+        }
+
+        $this->assertEquals($expected, $actual);
+    }
+}

programming_language: PHP