PluginProbe
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot / 4.9.2
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot v4.9.2
4.9.2 4.9.1 4.9.0 4.8.2 4.8.1 4.8.0 4.7.0 4.6.2 4.6.1 4.6.0 4.5.6 4.5.5 4.5.4 4.5.3 4.5.2 4.5.1 4.5.0 4.4.1 4.4.0 3.3.4 3.4.0 3.4.1 3.4.2 3.5.0 3.5.1 All 200 releases
← All changes | includes/Admin/CSVExporter.php +19 -2 4.6.14.9.2 View file →
@@ -652,11 +652,14 @@
652 652 ob_start();
653 653
654 654 $output = fopen( 'php://output', 'w' );
655 655
656 - // Add CSV rows
656 + // Add CSV rows. Neutralize spreadsheet formula injection: a cell that a
657 + // lower-privileged author controls (e.g. a doc/FAQ title or term name) could
658 + // start with =, +, -, @, or a tab/CR and execute when the admin opens the
659 + // export in Excel/LibreOffice. Prefix such cells with a single quote.
657 660 foreach ( $data as $row ) {
658 - fputcsv( $output, $row );
661 + fputcsv( $output, array_map( [ $this, 'neutralize_csv_cell' ], (array) $row ) );
659 662 }
660 663
661 664 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose -- closing php://output stream; WP_Filesystem does not apply.
662 665 fclose( $output );
@@ -661,6 +664,20 @@
661 664 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose -- closing php://output stream; WP_Filesystem does not apply.
662 665 fclose( $output );
663 666
664 667 return ob_get_clean();
668 + }
669 +
670 + /**
671 + * Prefix a leading formula trigger (= + - @ tab CR) with a single quote so
672 + * spreadsheet apps treat the cell as text instead of executing it.
673 + */
674 + private function neutralize_csv_cell( $cell ) {
675 + $cell = (string) $cell;
676 +
677 + if ( $cell !== '' && preg_match( '/^[=+\-@\t\r]/', $cell ) ) {
678 + return "'" . $cell;
679 + }
680 +
681 + return $cell;
665 682 }
666 683 }