Bug 37727: Prevent CSV Formula injection via DataTables

This change prevents CSV Formula injection on DataTables exports
by escaping formula with a single quote prefix as per OWASP recommendations.

Test plan:
0. Apply patch
1. Go to http://localhost:8081/cgi-bin/koha/members/memberentry.pl
?op=edit_form&destination=circ&borrowernumber=51
2. Add the following in a "Circulation note"
=SUM(1+1)
3. Go to http://localhost:8081/cgi-bin/koha/members/member.pl
?quicksearch=1&circsearch=1&searchmember=koha
4. Click "Export" and choose "Excel" and "CSV"
5. Open those downloaded files in Excel
6. Note that the =SUM(1+1) function is prefixed with a single quote,
and is not automatically executed

Signed-off-by: Magnus Enger <magnus@libriotech.no>
Works as advertised. The problematic "cell" is exported as "'=SUM(1+1)".
Signed-off-by: Chris Cormack <chris@bigballofwax.co.nz>
Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de>
Signed-off-by: wainuiwitikapark <wainuiwitikapark@catalyst.net.nz>
This commit is contained in:
David Cook 2024-10-17 05:35:56 +00:00 committed by wainuiwitikapark
parent 2896429708
commit dcb5cc1051
2 changed files with 38 additions and 4 deletions

View File

@ -35,6 +35,23 @@ function KohaTable(id_selector, dt_parameters, table_settings, add_filters) {
exportColumns = dt_parameters["exportColumns"];
}
const export_format_spreadsheet = {
body: function ( data, row, column, node ) {
var newnode = $(node);
if ( newnode.find(".noExport").length > 0 ) {
newnode = newnode.clone();
newnode.find(".noExport").remove();
}
let trimmed_str = newnode.text().replace( /\n/g, ' ' ).trim();
const unsafeCharacters = /^[=+\-@\t\r]/;
if ( unsafeCharacters.test(trimmed_str) ){
trimmed_str = "'" + trimmed_str;
}
return trimmed_str;
}
}
var export_format = {
body: function ( data, row, column, node ) {
var newnode = $(node);
@ -78,7 +95,7 @@ function KohaTable(id_selector, dt_parameters, table_settings, add_filters) {
exportOptions: {
columns: exportColumns,
rows: exportRows,
format: export_format
format: export_format_spreadsheet
},
},
{
@ -100,7 +117,7 @@ function KohaTable(id_selector, dt_parameters, table_settings, add_filters) {
exportOptions: {
columns: exportColumns,
rows: exportRows,
format: export_format
format: export_format_spreadsheet
},
}
);

View File

@ -672,6 +672,23 @@ function _dt_buttons(params){
exportColumns = settings["exportColumns"];
}
const export_format_spreadsheet = {
body: function ( data, row, column, node ) {
var newnode = $(node);
if ( newnode.find(".noExport").length > 0 ) {
newnode = newnode.clone();
newnode.find(".noExport").remove();
}
let trimmed_str = newnode.text().replace( /\n/g, ' ' ).trim();
const unsafeCharacters = /^[=+\-@\t\r]/;
if ( unsafeCharacters.test(trimmed_str) ){
trimmed_str = "'" + trimmed_str;
}
return trimmed_str;
}
}
var export_format = {
body: function ( data, row, column, node ) {
var newnode = $(node);
@ -691,7 +708,7 @@ function _dt_buttons(params){
text: __("Excel"),
exportOptions: {
columns: exportColumns,
format: export_format
format: export_format_spreadsheet
},
},
{
@ -699,7 +716,7 @@ function _dt_buttons(params){
text: __("CSV"),
exportOptions: {
columns: exportColumns,
format: export_format
format: export_format_spreadsheet
},
},
{